diff --git a/firmware/ice40-riscv/icE1usb/Makefile b/firmware/ice40-riscv/icE1usb/Makefile index f385408..513329c 100644 --- a/firmware/ice40-riscv/icE1usb/Makefile +++ b/firmware/ice40-riscv/icE1usb/Makefile @@ -57,6 +57,7 @@ HEADERS_app=\ ice1usb_proto.h \ i2c.h \ misc.h \ + rs422.h \ usb_desc_ids.h \ usb_dev.h \ usb_e1.h \ @@ -72,6 +73,7 @@ SOURCES_app=\ gpsdo.c \ i2c.c \ misc.c \ + rs422.c \ usb_desc_app.c \ usb_dev.c \ usb_e1.c \ diff --git a/firmware/ice40-riscv/icE1usb/config.h b/firmware/ice40-riscv/icE1usb/config.h index a27a53c..99ebfb1 100644 --- a/firmware/ice40-riscv/icE1usb/config.h +++ b/firmware/ice40-riscv/icE1usb/config.h @@ -18,6 +18,7 @@ #define MISC_BASE 0x88000000 #define GPS_UART_BASE 0x89000000 #define I2C_BASE 0x8a000000 +#define AUX_UART_BASE 0x8b000000 /* Alias for common code */ #define UART_BASE DBG_UART_BASE diff --git a/firmware/ice40-riscv/icE1usb/gps.c b/firmware/ice40-riscv/icE1usb/gps.c index c1ad3a8..6f8480f 100644 --- a/firmware/ice40-riscv/icE1usb/gps.c +++ b/firmware/ice40-riscv/icE1usb/gps.c @@ -13,6 +13,7 @@ #include "console.h" #include "gps.h" #include "misc.h" +#include "rs422.h" #include "usb_gps.h" #include "utils.h" @@ -28,7 +29,7 @@ struct gps_uart { #define GPS_UART_CSR_TX_EMPTY (1 << 29) #define GPS_UART_DATA_EMPTY (1 << 31) -static volatile struct gps_uart * const gps_uart_regs = (void*)(GPS_UART_BASE); +static volatile struct gps_uart * const gps_uart_regs = (void*)(AUX_UART_BASE); static struct { @@ -159,37 +160,11 @@ _gps_query(void) void _gps_parse_nmea(const char *nmea) { - /* Very basic parsing, we just look at GSA messages and consider - * that if we have a 3D fix with PDOP < 5, the timing data should - * be usable - */ - if (!strncmp(nmea, "$GPGSA", 6)) + /* Very basic parsing, we just look at $PERC,GPsts message for + * state 1 (survey mode) and 2 (position-hold) */ + if (!strncmp(nmea, "$PERC,GPsts,", 12)) { - /* Check for Autonomous 3D fix (fixed field positions) */ - if ((nmea[7] != 'A') || (nmea[9] != '3')) { - g_gps.fix.valid = false; - return; - } - - /* Find PDOP */ - const char *p = nmea; - for (int i=0; (i < 15) && (*p != '*'); i += (*(p++)==',') ); - - /* Is it low enough ? */ - g_gps.fix.valid = (p[1] < '5'); - } - - /* Parse TXT ANTENNA Status */ - if (!strncmp(nmea, "$GPTXT", 6) && nmea[13] == '0' && nmea[14] == '1') - { - if (!strncmp(&nmea[16], "ANTENNA OK", 10)) - g_gps.antenna = ANT_OK; - else if (!strncmp(&nmea[16], "ANTENNA OPEN", 12)) - g_gps.antenna = ANT_OPEN; - else if (!strncmp(&nmea[16], "ANTENNA SHORT", 13)) - g_gps.antenna = ANT_SHORT; - else - g_gps.antenna = ANT_UNKNOWN; + g_gps.fix.valid = (nmea[12] == '1') || (nmea[12] == '2'); } } @@ -226,65 +201,31 @@ gps_poll(void) void gps_init(void) { - int i; + uint32_t start_time = time_now_read(); + bool init_ok; /* State init */ memset(&g_gps, 0x00, sizeof(g_gps)); - /* Configure reset gpio */ + /* Hold onboard GPS in reset */ gpio_out(3, false); gpio_dir(3, true); - /* Attempt reset sequence at 9600 baud and then 115200 baud */ - for (i=0; i<2; i++) - { - uint32_t start_time = time_now_read(); - bool init_ok; + /* Init RS422 board */ + rs422_init(); - /* Assert reset */ - gpio_out(3, false); + /* Configure uart and empty buffer */ + gps_uart_regs->csr = GPS_UART_CSR_DIV(9600); + _gps_empty(false); - /* Configure uart and empty buffer */ - gps_uart_regs->csr = i ? GPS_UART_CSR_DIV(115200) : GPS_UART_CSR_DIV(9600); - _gps_empty(false); - - /* Wait 100 ms */ - delay(100); - - /* Release reset line */ - gpio_out(3, true); - - /* Wait for first line of output as sign it's ready, timeout after 1s */ - while (!time_elapsed(start_time, SYS_CLK_FREQ)) - if ((init_ok = (_gps_query() != NULL))) - break; - - if (init_ok) { - printf("[+] GPS ok at %d baud\n", i ? 115200 : 9600); + /* Wait for first line of output as sign it's ready, timeout after 10 s */ + while (!time_elapsed(start_time, 10 * SYS_CLK_FREQ)) + if ((init_ok = (_gps_query() != NULL))) break; - } - } - /* Failed ? */ - if (i == 2) { + if (init_ok) { + printf("[+] GPS ok\n"); + } else { printf("[!] GPS init failed\n"); - return; } - - /* If success was at 9600 baud, need to speed up */ - if (i == 0) { - /* Configure GPS to use serial at 115200 baud */ - _gps_send("PCAS01,5"); - - /* Add dummy byte which will be mangled during baudrate switch ... */ - gps_uart_regs->data = 0x00; - while (!(gps_uart_regs->csr & GPS_UART_CSR_TX_EMPTY)); - - /* Set uart to 115200 and empty uart buffer, line aligned */ - gps_uart_regs->csr = GPS_UART_CSR_DIV(115200) ; - _gps_empty(true); - } - - /* Configure GPS to be GPS-only (no GLONASS/BEIDOU) */ - _gps_send("PCAS04,1"); } diff --git a/firmware/ice40-riscv/icE1usb/rs422.c b/firmware/ice40-riscv/icE1usb/rs422.c new file mode 100644 index 0000000..4bdcb6c --- /dev/null +++ b/firmware/ice40-riscv/icE1usb/rs422.c @@ -0,0 +1,96 @@ +/* + * rs422.c + * + * Copyright (C) 2022 Sylvain Munaut + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include + +#include "console.h" +#include "i2c.h" +#include "misc.h" + +#include "config.h" + + +/* Local side buffer control */ +#define BUF_TCA9534_ADDR 0x42 +#define BUF_TXD_RXEN_n (1 << 0) +#define BUF_TXD_TXEN_n (1 << 1) +#define BUF_PPS_RXEN_n (1 << 4) +#define BUF_PPS_TXEN_n (1 << 5) +#define BUF_RXD_RXEN_n (1 << 6) +#define BUF_RXD_TXEN_n (1 << 7) + +/* Isolated side line driver control */ +#define LDRV_TCA9534_ADDR 0x40 +#define LDRV_TXD_RE_n (1 << 0) +#define LDRV_TXD_DE (1 << 1) +#define LDRV_RXD_RE_n (1 << 2) +#define LDRV_RXD_DE (1 << 3) +#define LDRV_PPS_DE (1 << 4) +#define LDRV_PPS_RE_n (1 << 5) + + +static void +tca9534_set_out(uint8_t dev, uint8_t data) +{ + /* Check device */ + if (!i2c_probe(dev)) { + printf("[1] Unable to configure TCA9534 at address %02x\n", dev); + return; + } + + /* Output values */ + i2c_write_reg(dev, 1, data); + + /* No inversion */ + i2c_write_reg(dev, 2, 0x00); + + /* All pins as output to avoid floating pins */ + i2c_write_reg(dev, 3, 0x00); +} + + +void +rs422_init(void) +{ + /* Reset GPS receiver to free I2C bus */ + gpio_out(3, false); + gpio_dir(3, true); + + /* Configure: + * - TXD pair: Receive + * - RXD pair: Transmit + * - PPS pair: Receive + */ + tca9534_set_out(BUF_TCA9534_ADDR, + BUF_TXD_TXEN_n | + BUF_RXD_RXEN_n | + BUF_PPS_TXEN_n | + 0 + ); + + tca9534_set_out(LDRV_TCA9534_ADDR, + LDRV_RXD_RE_n | +#if 0 + /* We don't actually TX anything to the module and + * this burns power ... */ + LDRV_RXD_DE | +#endif + 0 + ); + + /* Configure GPIO alt functions */ + /* Aux UART RX */ + gpio_sfn(0, true); + + /* Aux UART TX */ + gpio_sfn(1, true); + + /* PPS input */ + gpio_dir(2, false); + gpio_sfn(2, true); +} diff --git a/firmware/ice40-riscv/icE1usb/rs422.h b/firmware/ice40-riscv/icE1usb/rs422.h new file mode 100644 index 0000000..333f2e1 --- /dev/null +++ b/firmware/ice40-riscv/icE1usb/rs422.h @@ -0,0 +1,13 @@ +/* + * rs422.h + * + * Copyright (C) 2022 Sylvain Munaut + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include + +void rs422_init(void);