From dbab746e3c887fd0ec41af9a089053a85fcc2431 Mon Sep 17 00:00:00 2001 From: Alastair D'Silva Date: Mon, 11 Apr 2016 20:46:38 +1000 Subject: [PATCH] Add support for the TX_ENABLE signal for RS-485 trancievers --- esp-link/cgipins.c | 16 ++++++--- esp-link/config.h | 1 + esp-link/main.c | 5 ++- html/home.html | 5 +++ html/ui.js | 16 +++++---- serial/serbridge.c | 15 ++++++-- serial/uart.c | 89 ++++++++++++++++++++++++++++++++++++++++++++-- serial/uart.h | 4 ++- 8 files changed, 131 insertions(+), 20 deletions(-) diff --git a/esp-link/cgipins.c b/esp-link/cgipins.c index b763d12..7880195 100644 --- a/esp-link/cgipins.c +++ b/esp-link/cgipins.c @@ -32,9 +32,10 @@ int ICACHE_FLASH_ATTR cgiPinsGet(HttpdConnData *connData) { int len; len = os_sprintf(buff, - "{ \"reset\":%d, \"isp\":%d, \"conn\":%d, \"ser\":%d, \"swap\":%d, \"rxpup\":%d }", + "{ \"reset\":%d, \"isp\":%d, \"conn\":%d, \"ser\":%d, \"swap\":%d, \"rxpup\":%d, \"uart0_tx_enable\":%d }", flashConfig.reset_pin, flashConfig.isp_pin, flashConfig.conn_led_pin, - flashConfig.ser_led_pin, !!flashConfig.swap_uart, !!flashConfig.rx_pullup); + flashConfig.ser_led_pin, !!flashConfig.swap_uart, !!flashConfig.rx_pullup, + flashConfig.uart0_tx_enable_pin); jsonHeader(connData, 200); httpdSend(connData, buff, len); @@ -48,7 +49,7 @@ int ICACHE_FLASH_ATTR cgiPinsSet(HttpdConnData *connData) { } int8_t ok = 0; - int8_t reset, isp, conn, ser; + int8_t reset, isp, conn, ser, uart0_tx_enable; uint8_t swap, rxpup; ok |= getInt8Arg(connData, "reset", &reset); ok |= getInt8Arg(connData, "isp", &isp); @@ -56,6 +57,7 @@ int ICACHE_FLASH_ATTR cgiPinsSet(HttpdConnData *connData) { ok |= getInt8Arg(connData, "ser", &ser); ok |= getBoolArg(connData, "swap", &swap); ok |= getBoolArg(connData, "rxpup", &rxpup); + ok |= getInt8Arg(connData, "uart0_tx_enable", &uart0_tx_enable); if (ok < 0) return HTTPD_CGI_DONE; char *coll; @@ -75,6 +77,10 @@ int ICACHE_FLASH_ATTR cgiPinsSet(HttpdConnData *connData) { if (pins & (1<= 0) { + if (pins & (1< #include "httpd.h" #include "httpdespfs.h" @@ -110,6 +112,7 @@ void user_rf_pre_init(void) { // Main routine to initialize esp-link. void user_init(void) { + system_timer_reinit(); // get the flash config so we know how to init things //configWipe(); // uncomment to reset the config for testing purposes bool restoreOk = configRestore(); @@ -117,7 +120,7 @@ void user_init(void) { gpio_init(); gpio_output_set(0, 0, 0, (1<<15)); // some people tie it to GND, gotta ensure it's disabled // init UART - uart_init(flashConfig.baud_rate, 115200); + uart_init(flashConfig.baud_rate, flashConfig.uart0_tx_enable_pin, 115200); logInit(); // must come after init of uart // Say hello (leave some time to cause break in TX after boot loader's msg os_delay_us(10000L); diff --git a/html/home.html b/html/home.html index c977c74..bf8392d 100644 --- a/html/home.html +++ b/html/home.html @@ -76,6 +76,11 @@ +
+ + + +
diff --git a/html/ui.js b/html/ui.js index aa66f69..9b8637c 100644 --- a/html/ui.js +++ b/html/ui.js @@ -393,12 +393,12 @@ function showNotification(text) { //===== GPIO Pin mux card var pinPresets = { - // array: reset, isp, conn, ser, swap, rxpup - "esp-01": [ 0, -1, 2, -1, 0, 1 ], - "esp-12": [ 12, 14, 0, 2, 0, 1 ], - "esp-12 swap": [ 1, 3, 0, 2, 1, 1 ], - "esp-bridge": [ 12, 13, 0, 14, 0, 0 ], - "wifi-link-12": [ 1, 3, 0, 2, 1, 0 ], + // array: reset, isp, conn, ser, swap, rxpup, uart0_tx_enable + "esp-01": [ 0, -1, 2, -1, 0, 1, -1 ], + "esp-12": [ 12, 14, 0, 2, 0, 1, -1 ], + "esp-12 swap": [ 1, 3, 0, 2, 1, 1, -1 ], + "esp-bridge": [ 12, 13, 0, 14, 0, 0, -1 ], + "wifi-link-12": [ 1, 3, 0, 2, 1, 0, -1 ], }; function createPresets(sel) { @@ -418,6 +418,7 @@ function createPresets(sel) { setPP("ser", pp[3]); setPP("swap", pp[4]); $("#pin-rxpup").checked = !!pp[5]; + setPP("uart0-tx-enable", pp[6]); sel.value = 0; }; @@ -453,6 +454,7 @@ function displayPins(resp) { createSelectForPin("ser", resp["ser"]); $("#pin-swap").value = resp["swap"]; $("#pin-rxpup").checked = !!resp["rxpup"]; + createSelectForPin("uart0_tx_enable", resp["uart0_tx_enable"]); createPresets($("#pin-preset")); $("#pin-spinner").setAttribute("hidden", ""); @@ -469,7 +471,7 @@ function setPins(ev) { ev.preventDefault(); var url = "/pins"; var sep = "?"; - ["reset", "isp", "conn", "ser", "swap"].forEach(function(p) { + ["reset", "isp", "conn", "ser", "swap", "uart0_tx_enable"].forEach(function(p) { url += sep + p + "=" + $("#pin-"+p).value; sep = "&"; }); diff --git a/serial/serbridge.c b/serial/serbridge.c index 1e82e3d..5b8b53b 100644 --- a/serial/serbridge.c +++ b/serial/serbridge.c @@ -17,7 +17,7 @@ static struct espconn serbridgeConn1; // plain bridging port static struct espconn serbridgeConn2; // programming port static esp_tcp serbridgeTcp1, serbridgeTcp2; -static int8_t mcu_reset_pin, mcu_isp_pin; +static int8_t mcu_reset_pin, mcu_isp_pin, uart0_tx_enable_pin; extern uint8_t slip_disabled; // disable slip to allow flashing of attached MCU @@ -439,9 +439,10 @@ serbridgeInitPins() { mcu_reset_pin = flashConfig.reset_pin; mcu_isp_pin = flashConfig.isp_pin; + uart0_tx_enable_pin = flashConfig.uart0_tx_enable_pin; #ifdef SERBR_DBG - os_printf("Serbridge pins: reset=%d isp=%d swap=%d\n", - mcu_reset_pin, mcu_isp_pin, flashConfig.swap_uart); + os_printf("Serbridge pins: reset=%d isp=%d tx_enable=%d swap=%d\n", + mcu_reset_pin, mcu_isp_pin, uart0_tx_enable_pin, flashConfig.swap_uart); #endif if (flashConfig.swap_uart) { @@ -463,9 +464,17 @@ serbridgeInitPins() // set both pins to 1 before turning them on so we don't cause a reset if (mcu_isp_pin >= 0) GPIO_OUTPUT_SET(mcu_isp_pin, 1); if (mcu_reset_pin >= 0) GPIO_OUTPUT_SET(mcu_reset_pin, 1); + // set TX_ENABLE to 0 so we start up listening + if (mcu_reset_pin >= 0) GPIO_OUTPUT_SET(uart0_tx_enable_pin, 0); // switch pin mux to make these pins GPIO pins if (mcu_reset_pin >= 0) makeGpio(mcu_reset_pin); if (mcu_isp_pin >= 0) makeGpio(mcu_isp_pin); + if (uart0_tx_enable_pin >= 0) { + makeGpio(uart0_tx_enable_pin); + uart0_set_tx_enable_pin(uart0_tx_enable_pin); + } + + } // Start transparent serial bridge TCP server on specified port (typ. 23) diff --git a/serial/uart.c b/serial/uart.c index f7f07fa..206006c 100644 --- a/serial/uart.c +++ b/serial/uart.c @@ -17,9 +17,11 @@ * ---------------------------------------------------------------------------- * Heavily modified and enhanced by Thorsten von Eicken in 2015 */ +#define USE_US_TIMER #include "esp8266.h" #include "task.h" #include "uart.h" +#include #ifdef UART_DBG #define DBG_UART(format, ...) os_printf(format, ## __VA_ARGS__) @@ -28,6 +30,7 @@ #endif LOCAL uint8_t uart_recvTaskNum; +LOCAL int8_t uart0_tx_enable_pin; // UartDev is defined and initialized in rom code. extern UartDevice UartDev; @@ -36,6 +39,52 @@ static UartRecv_cb uart_recv_cb[4]; static void uart0_rx_intr_handler(void *para); +/****************************************************************************** + * FunctionName : set_tx_enable_pin + * Description : Set which pin to use for RS-485 TX_ENABLE + * Parameters : pin, the pin to use + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR +uart0_set_tx_enable_pin(int8_t pin) { + uart0_tx_enable_pin = pin; +} + +/****************************************************************************** + * FunctionName : tx_enable + * Description : Internal used function + * Set the TX_ENABLE line for RS-485 communications + * Parameters : state, true if the TX_ENABLE line should be asserted high + * Returns : NONE +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +tx_enable(bool state) +{ + if (uart0_tx_enable_pin >= 0) { +#ifdef SERBR_DBG + os_printf("TX_ENABLE gpio%d state=%d\n", uart0_tx_enable_pin, (int)state); +#endif + GPIO_OUTPUT_SET(uart0_tx_enable_pin, (state) ? 1 : 0); + } +#ifdef SERBR_DBG + else { os_printf("TX Enable: no pin\n"); } +#endif +} + +/****************************************************************************** + * FunctionName : tx_completed_interrupt + * Description : Internal used function + * Set the TX enable line low, after the UART has completed tranmission + * Parameters : unused unused + * Returns : NONE +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +tx_completed_interrupt(void *arg) +{ + tx_enable(false); +} + + /****************************************************************************** * FunctionName : uart_config * Description : Internal used function @@ -81,12 +130,19 @@ uart_config(uint8 uart_no) // to set the threshold here... // We do not enable framing error interrupts 'cause they tend to cause an interrupt avalanche // and instead just poll for them when we get a std RX interrupt. + + uint32_t tx_empty_bits = 0; + if (uart0_tx_enable_pin >= 0) { + tx_empty_bits = (0 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S | UART_TXFIFO_EMPTY_INT_ENA; + } WRITE_PERI_REG(UART_CONF1(uart_no), ((80 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | ((100 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) | UART_RX_FLOW_EN | (4 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S | - UART_RX_TOUT_EN); + UART_RX_TOUT_EN) | + tx_empty_bits + ; SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA); } else { WRITE_PERI_REG(UART_CONF1(uart_no), @@ -97,6 +153,9 @@ uart_config(uint8 uart_no) WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff); } +os_timer_t uart_tx_enable_timer; +bool uart_tx_enable_timer_inited = false; + /****************************************************************************** * FunctionName : uart1_tx_one_char * Description : Internal used function @@ -110,6 +169,16 @@ uart_tx_one_char(uint8 uart, uint8 c) //Wait until there is room in the FIFO while (((READ_PERI_REG(UART_STATUS(uart))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=100) ; //Send the character + if (UART0 == uart) { + if (uart_tx_enable_timer_inited) { + // If a tx_completed_interrupt has already been scheduled, cancel it before it fires during our transmission + os_timer_disarm(&uart_tx_enable_timer); + } else { + os_timer_setfn(&uart_tx_enable_timer, tx_completed_interrupt, NULL); + } + + tx_enable(true); + } WRITE_PERI_REG(UART_FIFO(uart), c); return OK; } @@ -168,6 +237,7 @@ uart0_sendStr(const char *str) } static uint32 last_frm_err; // time in us when last framing error message was printed +static int uart0_baud_rate = 0; // The baud rate for uart0 /****************************************************************************** * FunctionName : uart0_rx_intr_handler @@ -206,6 +276,12 @@ uart0_rx_intr_handler(void *para) //DBG_UART("stat:%02X",*(uint8 *)UART_INT_ENA(uart_no)); ETS_UART_INTR_DISABLE(); post_usr_task(uart_recvTaskNum, 0); + } else if (UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST)) { + // TX Queue is empty, disable the TX_ENABLE line once the transmission is complete + if (0 != uart0_baud_rate) { + int tx_char_time = 8 * 1000000 / uart0_baud_rate; // assumes 8 bits per character + os_timer_arm_us(&uart_tx_enable_timer, tx_char_time, false); + } } } @@ -255,6 +331,7 @@ done: void ICACHE_FLASH_ATTR uart0_baud(int rate) { + uart0_baud_rate = rate; os_printf("UART %d baud\n", rate); uart_div_modify(UART0, UART_CLK_FREQ / rate); } @@ -263,13 +340,19 @@ uart0_baud(int rate) { * FunctionName : uart_init * Description : user interface for init uart * Parameters : UartBautRate uart0_br - uart0 bautrate + * uart0TxEnablePin * UartBautRate uart1_br - uart1 bautrate * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -uart_init(UartBautRate uart0_br, UartBautRate uart1_br) +uart_init(UartBautRate uart0_br, int8_t uart0TxEnablePin, UartBautRate uart1_br) { + if (uart0TxEnablePin >= 0) { + uart0_set_tx_enable_pin(uart0TxEnablePin); + } + // rom use 74880 baut_rate, here reinitialize + uart0_baud_rate = (int)uart0_br; UartDev.baut_rate = uart0_br; uart_config(UART0); UartDev.baut_rate = uart1_br; @@ -298,7 +381,7 @@ uart_add_recv_cb(UartRecv_cb cb) { void ICACHE_FLASH_ATTR uart_reattach() { - uart_init(BIT_RATE_74880, BIT_RATE_74880); + uart_init(BIT_RATE_74880, -1, BIT_RATE_74880); // ETS_UART_INTR_ATTACH(uart_rx_intr_handler_ssc, &(UartDev.rcv_buff)); // ETS_UART_INTR_ENABLE(); } diff --git a/serial/uart.h b/serial/uart.h index 24fb2df..82880ee 100644 --- a/serial/uart.h +++ b/serial/uart.h @@ -8,7 +8,7 @@ typedef void (*UartRecv_cb)(char *buf, short len); // Initialize UARTs to the provided baud rates (115200 recommended). This also makes the os_printf // calls use uart1 for output (for debugging purposes) -void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); +void uart_init(UartBautRate uart0_br, int8_t uart0TxEnablePin, UartBautRate uart1_br); // Transmit a buffer of characters on UART0 void uart0_tx_buffer(char *buf, uint16 len); @@ -28,4 +28,6 @@ uint16_t uart0_rx_poll(char *buff, uint16_t nchars, uint32_t timeout_us); void uart0_baud(int rate); +void uart0_set_tx_enable_pin(int8_t pin); + #endif /* __UART_H__ */