From e255f25cfd626cb902d8f55fbe006505435ccdad Mon Sep 17 00:00:00 2001 From: Me No Dev Date: Sat, 23 Jan 2016 13:02:01 +0200 Subject: [PATCH 1/5] Bufferless and Interruptless HardwareSerial Let's use the onboard buffers :) --- cores/esp8266/HardwareSerial.cpp | 839 ++++++++++--------------------- cores/esp8266/HardwareSerial.h | 8 +- 2 files changed, 277 insertions(+), 570 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index c1b81487b3..beb4a498be 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -82,683 +82,396 @@ static const int UART_NO = -1; HardwareSerial Serial(UART0); HardwareSerial Serial1(UART1); -// #################################################################################################### -// #################################################################################################### -// #################################################################################################### - -void uart_interrupt_handler(uart_t* uart); -void uart_wait_for_tx_fifo(uart_t* uart, size_t size_needed); - -size_t uart_get_tx_fifo_room(uart_t* uart); -void uart_wait_for_transmit(uart_t* uart); -void uart_transmit_char(uart_t* uart, char c); -void uart_transmit(uart_t* uart, const char* buf, size_t size); -void uart_flush(uart_t* uart); -void uart_interrupt_enable(uart_t* uart); -void uart_interrupt_disable(uart_t* uart); -void uart_arm_tx_interrupt(uart_t* uart); -void uart_disarm_tx_interrupt(uart_t* uart); -void uart_set_baudrate(uart_t* uart, int baud_rate); -int uart_get_baudrate(uart_t* uart); - -uart_t* uart_start_init(int uart_nr, int baudrate, byte config, uint8_t use_tx); -void uart_finish_init(uart_t* uart); -void uart_uninit(uart_t* uart); -void uart_swap(uart_t* uart, uint8_t use_tx); -void uart_set_tx(uart_t* uart, uint8_t use_tx); -void uart_set_pins(uart_t* uart, uint8_t tx, uint8_t rx); - -void uart_ignore_char(char c); -void uart0_write_char(char c); -void uart1_write_char(char c); - -void uart_set_debug(int uart_nr); -int uart_get_debug(); - -// #################################################################################################### -// #################################################################################################### -// #################################################################################################### - -// These function internals can be used from interrupt handlers to ensure they -// are in instruction RAM, or anywhere that the uart_nr has been validated. -#define UART_GET_TX_FIFO_ROOM(uart_nr) (UART_TX_FIFO_SIZE - ((USS(uart_nr) >> USTXC) & 0xff)) -#define UART_TRANSMIT_CHAR(uart_nr, c) do { USF(uart_nr) = (c); } while(0) -#define UART_ARM_TX_INTERRUPT(uart_nr) do { USIE(uart_nr) |= (1 << UIFE); } while(0) -#define UART_DISARM_TX_INTERRUPT(uart_nr) do { USIE(uart_nr) &= ~(1 << UIFE); } while(0) -void ICACHE_RAM_ATTR uart_interrupt_handler(uart_t* uart) { - - // -------------- UART 0 -------------- - if(Serial.isRxEnabled()) { - while(U0IS & (1 << UIFF)) { - Serial._rx_complete_irq((char) (U0F & 0xff)); - U0IC = (1 << UIFF); - } - } - if(Serial.isTxEnabled()) { - if(U0IS & (1 << UIFE)) { - U0IC = (1 << UIFE); - Serial._tx_empty_irq(); - } - } - - // -------------- UART 1 -------------- - // Note: only TX is supported on UART 1. - if(Serial1.isTxEnabled()) { - if(U1IS & (1 << UIFE)) { - U1IC = (1 << UIFE); - Serial1._tx_empty_irq(); - } - } +void uart_write_char(uart_t* uart, char c) { + if(uart == 0 || !uart->txEnabled) + return; + while((USS(uart->uart_nr) >> USTXC) >= 0x7f); + USF(uart->uart_nr) = c; } -// #################################################################################################### - -void uart_wait_for_tx_fifo(uart_t* uart, size_t size_needed) { - if(uart == 0) - return; - if(uart->txEnabled) { - while(true) { - size_t tx_count = (USS(uart->uart_nr) >> USTXC) & 0xff; - if(tx_count <= (UART_TX_FIFO_SIZE - size_needed)) - break; - } - } +void uart_write(uart_t* uart, const char* buf, size_t size) { + if(uart == 0 || !uart->txEnabled) + return; + while(size--) + uart_write_char(uart, *buf++); } -size_t uart_get_tx_fifo_room(uart_t* uart) { - if(uart == 0) - return 0; - if(uart->txEnabled) { - return UART_GET_TX_FIFO_ROOM(uart->uart_nr); - } +uint8_t uart_read_char(uart_t* uart){ + if(uart == 0 || !uart->rxEnabled) return 0; + return USF(uart->uart_nr) & 0xff; } -void uart_wait_for_transmit(uart_t* uart) { - if(uart == 0) - return; - if(uart->txEnabled) { - uart_wait_for_tx_fifo(uart, UART_TX_FIFO_SIZE); - } +uint8_t uart_rx_available(uart_t* uart){ + if(uart == 0 || !uart->rxEnabled) + return 0; + return (USS(uart->uart_nr) >> USRXC) & 0xff; } -void uart_transmit_char(uart_t* uart, char c) { - if(uart == 0) - return; - if(uart->txEnabled) { - UART_TRANSMIT_CHAR(uart->uart_nr, c); - } +uint8_t uart_tx_free(uart_t* uart){ + if(uart == 0 || !uart->txEnabled) + return 0; + return UART_TX_FIFO_SIZE - ((USS(uart->uart_nr) >> USTXC) & 0xff); } -void uart_transmit(uart_t* uart, const char* buf, size_t size) { - if(uart == 0) - return; - if(uart->txEnabled) { - while(size) { - size_t part_size = (size > UART_TX_FIFO_SIZE) ? UART_TX_FIFO_SIZE : size; - size -= part_size; - - uart_wait_for_tx_fifo(uart, part_size); - for(; part_size; --part_size, ++buf) - USF(uart->uart_nr) = *buf; - } - } +void uart_wait_tx_empty(uart_t* uart){ + if(uart == 0 || !uart->txEnabled) + return; + while(((USS(uart->uart_nr) >> USTXC) & 0xff) > 0) delay(0); } void uart_flush(uart_t* uart) { - uint32_t tmp = 0x00000000; - - if(uart == 0) - return; - - if(uart->rxEnabled) { - tmp |= (1 << UCRXRST); - } - - if(uart->txEnabled) { - tmp |= (1 << UCTXRST); - } - - USC0(uart->uart_nr) |= (tmp); - USC0(uart->uart_nr) &= ~(tmp); -} + if(uart == 0) + return; -void uart_interrupt_enable(uart_t* uart) { - if(uart == 0) - return; - USIC(uart->uart_nr) = 0x1ff; - ETS_UART_INTR_ATTACH(&uart_interrupt_handler, uart); // uart parameter is not osed in irq function! - if(uart->rxEnabled) { - USIE(uart->uart_nr) |= (1 << UIFF); - } - ETS_UART_INTR_ENABLE(); -} + uint32_t tmp = 0x00000000; + if(uart->rxEnabled) { + tmp |= (1 << UCRXRST); + } -void uart_interrupt_disable(uart_t* uart) { - if(uart == 0) - return; - if(uart->rxEnabled) { - USIE(uart->uart_nr) &= ~(1 << UIFF); - } - if(uart->txEnabled) { - USIE(uart->uart_nr) &= ~(1 << UIFE); - } - //ETS_UART_INTR_DISABLE(); // never disable irq complete may its needed by the other Serial Interface! -} - -void uart_arm_tx_interrupt(uart_t* uart) { - if(uart == 0) - return; - if(uart->txEnabled) { - UART_ARM_TX_INTERRUPT(uart->uart_nr); - } -} + if(uart->txEnabled) { + tmp |= (1 << UCTXRST); + } -void uart_disarm_tx_interrupt(uart_t* uart) { - if(uart == 0) - return; - if(uart->txEnabled) { - UART_DISARM_TX_INTERRUPT(uart->uart_nr); - } + USC0(uart->uart_nr) |= (tmp); + USC0(uart->uart_nr) &= ~(tmp); } void uart_set_baudrate(uart_t* uart, int baud_rate) { - if(uart == 0) - return; - uart->baud_rate = baud_rate; - USD(uart->uart_nr) = (ESP8266_CLOCK / uart->baud_rate); + if(uart == 0) + return; + uart->baud_rate = baud_rate; + USD(uart->uart_nr) = (ESP8266_CLOCK / uart->baud_rate); } int uart_get_baudrate(uart_t* uart) { - if(uart == 0) - return 0; - return uart->baud_rate; -} - -uart_t* uart_start_init(int uart_nr, int baudrate, byte config, byte mode, uint8_t use_tx) { - - uart_t* uart = (uart_t*) os_malloc(sizeof(uart_t)); - - if(uart == 0) { - return 0; - } - - uart->uart_nr = uart_nr; - - switch(uart->uart_nr) { - case UART0: - uart->rxEnabled = (mode != SERIAL_TX_ONLY); - uart->txEnabled = (mode != SERIAL_RX_ONLY); - uart->rxPin = (uart->rxEnabled)?3:255; - if(uart->rxEnabled) { - if (use_tx == 2) { - uart->txPin = 2; - pinMode(uart->rxPin, FUNCTION_4); - } else { - uart->txPin = 1; - pinMode(uart->rxPin, SPECIAL); - } - } else uart->txPin = 255; - if(uart->txEnabled) pinMode(uart->txPin, SPECIAL); - IOSWAP &= ~(1 << IOSWAPU0); - break; - case UART1: - // Note: uart_interrupt_handler does not support RX on UART 1. - uart->rxEnabled = false; - uart->txEnabled = (mode != SERIAL_RX_ONLY); - uart->rxPin = 255; - uart->txPin = (uart->txEnabled)?2:255; // GPIO7 as TX not possible! See GPIO pins used by UART - if(uart->txEnabled) pinMode(uart->txPin, SPECIAL); - break; - case UART_NO: - default: - // big fail! - os_free(uart); - return 0; - } - uart_set_baudrate(uart, baudrate); - USC0(uart->uart_nr) = config; - - return uart; + if(uart == 0) + return 0; + return uart->baud_rate; } -void uart_finish_init(uart_t* uart) { - uint32_t conf1 = 0x00000000; +// #################################################################################################### +// #################################################################################################### +// #################################################################################################### - uart_flush(uart); - uart_interrupt_enable(uart); +uart_t* uart_init(int uart_nr, int baudrate, byte config, byte mode, uint8_t use_tx) { - if(uart->rxEnabled) { - conf1 |= (0x01 << UCFFT); - } + uart_t* uart = (uart_t*) os_malloc(sizeof(uart_t)); - if(uart->txEnabled) { - conf1 |= (0x20 << UCFET); - } - - USC1(uart->uart_nr) = conf1; + if(uart == 0) { + return 0; + } + + uart->uart_nr = uart_nr; + + switch(uart->uart_nr) { + case UART0: + uart->rxEnabled = (mode != SERIAL_TX_ONLY); + uart->txEnabled = (mode != SERIAL_RX_ONLY); + uart->rxPin = (uart->rxEnabled)?3:255; + if(uart->rxEnabled) { + if (use_tx == 2) { + uart->txPin = 2; + pinMode(uart->rxPin, FUNCTION_4); + } else { + uart->txPin = 1; + pinMode(uart->rxPin, SPECIAL); + } + } else uart->txPin = 255; + if(uart->txEnabled) pinMode(uart->txPin, SPECIAL); + IOSWAP &= ~(1 << IOSWAPU0); + break; + case UART1: + // Note: uart_interrupt_handler does not support RX on UART 1. + uart->rxEnabled = false; + uart->txEnabled = (mode != SERIAL_RX_ONLY); + uart->rxPin = 255; + uart->txPin = (uart->txEnabled)?2:255; // GPIO7 as TX not possible! See GPIO pins used by UART + if(uart->txEnabled) pinMode(uart->txPin, SPECIAL); + break; + case UART_NO: + default: + // big fail! + os_free(uart); + return 0; + } + + uart_set_baudrate(uart, baudrate); + USC0(uart->uart_nr) = config; + uart_flush(uart); + USC1(uart->uart_nr) = 0; + + return uart; } void uart_uninit(uart_t* uart) { - if(uart == 0) - return; - uart_interrupt_disable(uart); - - switch(uart->rxPin) { - case 3: - pinMode(3, INPUT); - break; - case 13: - pinMode(13, INPUT); - break; - } - - switch(uart->txPin) { - case 1: - pinMode(1, INPUT); - break; - case 2: - pinMode(2, INPUT); - break; - case 15: - pinMode(15, INPUT); - break; - } - - os_free(uart); + if(uart == 0) + return; + + switch(uart->rxPin) { + case 3: + pinMode(3, INPUT); + break; + case 13: + pinMode(13, INPUT); + break; + } + + switch(uart->txPin) { + case 1: + pinMode(1, INPUT); + break; + case 2: + pinMode(2, INPUT); + break; + case 15: + pinMode(15, INPUT); + break; + } + + os_free(uart); } void uart_swap(uart_t* uart, uint8_t use_tx) { - if(uart == 0) - return; - switch(uart->uart_nr) { - case UART0: - if(((uart->txPin == 1 || uart->txPin == 2) && uart->txEnabled) || (uart->rxPin == 3 && uart->rxEnabled)) { - if(uart->txEnabled){ //TX - pinMode(uart->txPin, INPUT); - uart->txPin = 15; - } - if(uart->rxEnabled){ //RX - pinMode(uart->rxPin, INPUT); - uart->rxPin = 13; - } - if(uart->txEnabled) pinMode(uart->txPin, FUNCTION_4); //TX - if(uart->rxEnabled) pinMode(uart->rxPin, FUNCTION_4); //RX - IOSWAP |= (1 << IOSWAPU0); - } else { - if(uart->txEnabled){ //TX - pinMode(uart->txPin, INPUT); - uart->txPin = (use_tx == 2)?2:1; - } - if(uart->rxEnabled){ //RX - pinMode(uart->rxPin, INPUT); - uart->rxPin = 3; - } - if(uart->txEnabled) pinMode(uart->txPin, (use_tx == 2)?FUNCTION_4:SPECIAL); //TX - if(uart->rxEnabled) pinMode(3, SPECIAL); //RX - IOSWAP &= ~(1 << IOSWAPU0); - } - - break; - case UART1: - // Currently no swap possible! See GPIO pins used by UART - break; - default: - break; - } + if(uart == 0) + return; + switch(uart->uart_nr) { + case UART0: + if(((uart->txPin == 1 || uart->txPin == 2) && uart->txEnabled) || (uart->rxPin == 3 && uart->rxEnabled)) { + if(uart->txEnabled){ //TX + pinMode(uart->txPin, INPUT); + uart->txPin = 15; + } + if(uart->rxEnabled){ //RX + pinMode(uart->rxPin, INPUT); + uart->rxPin = 13; + } + if(uart->txEnabled) pinMode(uart->txPin, FUNCTION_4); //TX + if(uart->rxEnabled) pinMode(uart->rxPin, FUNCTION_4); //RX + IOSWAP |= (1 << IOSWAPU0); + } else { + if(uart->txEnabled){ //TX + pinMode(uart->txPin, INPUT); + uart->txPin = (use_tx == 2)?2:1; + } + if(uart->rxEnabled){ //RX + pinMode(uart->rxPin, INPUT); + uart->rxPin = 3; + } + if(uart->txEnabled) pinMode(uart->txPin, (use_tx == 2)?FUNCTION_4:SPECIAL); //TX + if(uart->rxEnabled) pinMode(3, SPECIAL); //RX + IOSWAP &= ~(1 << IOSWAPU0); + } + + break; + case UART1: + // Currently no swap possible! See GPIO pins used by UART + break; + default: + break; + } } void uart_set_tx(uart_t* uart, uint8_t use_tx) { - if(uart == 0) - return; - switch(uart->uart_nr) { - case UART0: - if(uart->txEnabled) { - if (uart->txPin == 1 && use_tx == 2) { - pinMode(uart->txPin, INPUT); - uart->txPin = 2; - pinMode(uart->txPin, FUNCTION_4); - } else if (uart->txPin == 2 && use_tx != 2) { - pinMode(uart->txPin, INPUT); - uart->txPin = 1; - pinMode(uart->txPin, SPECIAL); - } - } - - break; - case UART1: - // GPIO7 as TX not possible! See GPIO pins used by UART - break; - default: - break; - } + if(uart == 0) + return; + switch(uart->uart_nr) { + case UART0: + if(uart->txEnabled) { + if (uart->txPin == 1 && use_tx == 2) { + pinMode(uart->txPin, INPUT); + uart->txPin = 2; + pinMode(uart->txPin, FUNCTION_4); + } else if (uart->txPin == 2 && use_tx != 2) { + pinMode(uart->txPin, INPUT); + uart->txPin = 1; + pinMode(uart->txPin, SPECIAL); + } + } + + break; + case UART1: + // GPIO7 as TX not possible! See GPIO pins used by UART + break; + default: + break; + } } void uart_set_pins(uart_t* uart, uint8_t tx, uint8_t rx) { - if(uart == 0) - return; - - if(uart->uart_nr == UART0) { // Only UART0 allows pin changes - if(uart->txEnabled && uart->txPin != tx) { - if( rx == 13 && tx == 15) { - uart_swap(uart, 15); - } else if (rx == 3 && (tx == 1 || tx == 2)) { - if (uart->rxPin != rx) uart_swap(uart, tx); - else uart_set_tx(uart, tx); - } - } - if(uart->rxEnabled && uart->rxPin != rx && rx == 13 && tx == 15) { - uart_swap(uart, 15); - } + if(uart == 0) + return; + + if(uart->uart_nr == UART0) { // Only UART0 allows pin changes + if(uart->txEnabled && uart->txPin != tx) { + if( rx == 13 && tx == 15) { + uart_swap(uart, 15); + } else if (rx == 3 && (tx == 1 || tx == 2)) { + if (uart->rxPin != rx) uart_swap(uart, tx); + else uart_set_tx(uart, tx); + } + } + if(uart->rxEnabled && uart->rxPin != rx && rx == 13 && tx == 15) { + uart_swap(uart, 15); } + } } // #################################################################################################### // #################################################################################################### // #################################################################################################### -void uart_ignore_char(char c) { -} +void uart_ignore_char(char c) {} void uart0_write_char(char c) { - if(&Serial != NULL && Serial.isTxEnabled()) { - if(Serial.availableForWrite() > 0) { - if(c == '\n') { - Serial.write('\r'); - } - Serial.write(c); - return; - } - } - - // wait for the Hardware FIFO - while(true) { - if(((USS(0) >> USTXC) & 0xff) <= (UART_TX_FIFO_SIZE - 2)) { - break; - } - } - - if(c == '\n') { - USF(0) = '\r'; - } - USF(0) = c; + while(((USS(0) >> USTXC) & 0xff) >= 0x7F) delay(0); + USF(0) = c; } void uart1_write_char(char c) { - if(&Serial1 != NULL && Serial1.isTxEnabled()) { - if(Serial1.availableForWrite() > 0) { - if(c == '\n') { - Serial1.write('\r'); - } - Serial1.write(c); - return; - } - } - - // wait for the Hardware FIFO - while(true) { - if(((USS(1) >> USTXC) & 0xff) <= (UART_TX_FIFO_SIZE - 2)) { - break; - } - } - - if(c == '\n') { - USF(1) = '\r'; - } - USF(1) = c; + while(((USS(1) >> USTXC) & 0xff) >= 0x7F) delay(0); + USF(1) = c; } static int s_uart_debug_nr = UART0; void uart_set_debug(int uart_nr) { - s_uart_debug_nr = uart_nr; - switch(s_uart_debug_nr) { - case UART0: - system_set_os_print(1); - ets_install_putc1((void *) &uart0_write_char); - break; - case UART1: - system_set_os_print(1); - ets_install_putc1((void *) &uart1_write_char); - break; - case UART_NO: - default: - system_set_os_print(0); - ets_install_putc1((void *) &uart_ignore_char); - break; - } + s_uart_debug_nr = uart_nr; + switch(s_uart_debug_nr) { + case UART0: + system_set_os_print(1); + ets_install_putc1((void *) &uart0_write_char); + break; + case UART1: + system_set_os_print(1); + ets_install_putc1((void *) &uart1_write_char); + break; + case UART_NO: + default: + system_set_os_print(0); + ets_install_putc1((void *) &uart_ignore_char); + break; + } } int uart_get_debug() { - return s_uart_debug_nr; + return s_uart_debug_nr; } + // #################################################################################################### // #################################################################################################### // #################################################################################################### -HardwareSerial::HardwareSerial(int uart_nr) : - _uart_nr(uart_nr), _uart(0), _tx_buffer(0), _rx_buffer(0) { -} +HardwareSerial::HardwareSerial(int uart_nr) + : _uart_nr(uart_nr) + , _uart(0) +{} void HardwareSerial::begin(unsigned long baud, byte config, byte mode, uint8_t use_tx) { - InterruptLock il; + if(uart_get_debug() == _uart_nr) + uart_set_debug(UART_NO); - // disable debug for this interface - if(uart_get_debug() == _uart_nr) { - uart_set_debug(UART_NO); - } - - if (_uart) { - os_free(_uart); - } - _uart = uart_start_init(_uart_nr, baud, config, mode, use_tx); - - if(_uart == 0) { - return; - } + if (_uart) + os_free(_uart); - // Disable the RX and/or TX functions if we fail to allocate circular buffers. - // The user can confirm they are enabled with isRxEnabled() and isTxEnabled(). - if(_uart->rxEnabled && !_rx_buffer) { - _rx_buffer = new cbuf(SERIAL_RX_BUFFER_SIZE); - if(!_rx_buffer) { - _uart->rxEnabled = false; - } - } - if(_uart->txEnabled && !_tx_buffer) { - _tx_buffer = new cbuf(SERIAL_TX_BUFFER_SIZE); - if(!_tx_buffer) { - _uart->txEnabled = false; - } - } - delay(1); - - uart_finish_init(_uart); + _uart = uart_init(_uart_nr, baud, config, mode, use_tx); } void HardwareSerial::end() { - InterruptLock il; + if(uart_get_debug() == _uart_nr) + uart_set_debug(UART_NO); - if(uart_get_debug() == _uart_nr) { - uart_set_debug(UART_NO); - } - uart_uninit(_uart); - delete _rx_buffer; - delete _tx_buffer; - _uart = 0; - _rx_buffer = 0; - _tx_buffer = 0; + uart_uninit(_uart); } void HardwareSerial::swap(uint8_t use_tx) { - if(_uart == 0) - return; - uart_swap(_uart, use_tx); + if(_uart == 0) + return; + uart_swap(_uart, use_tx); } void HardwareSerial::set_tx(uint8_t use_tx) { - if(_uart == 0) - return; - uart_set_tx(_uart, use_tx); + if(_uart == 0) + return; + uart_set_tx(_uart, use_tx); } void HardwareSerial::pins(uint8_t tx, uint8_t rx) { - if(_uart == 0) - return; - uart_set_pins(_uart, tx, rx); + if(_uart == 0) + return; + uart_set_pins(_uart, tx, rx); } void HardwareSerial::setDebugOutput(bool en) { - if(_uart == 0) - return; - if(en) { - if(_uart->txEnabled) - uart_set_debug(_uart->uart_nr); - else - uart_set_debug(UART_NO); - } else { - // disable debug for this interface - if(uart_get_debug() == _uart_nr) { - uart_set_debug(UART_NO); - } + if(_uart == 0) + return; + if(en) { + if(_uart->txEnabled) + uart_set_debug(_uart->uart_nr); + else + uart_set_debug(UART_NO); + } else { + // disable debug for this interface + if(uart_get_debug() == _uart_nr) { + uart_set_debug(UART_NO); } + } } bool ICACHE_RAM_ATTR HardwareSerial::isTxEnabled(void) { - if(_uart == 0) - return false; - return _uart->txEnabled; + return _uart != 0 && _uart->txEnabled; } bool ICACHE_RAM_ATTR HardwareSerial::isRxEnabled(void) { - if(_uart == 0) - return false; - return _uart->rxEnabled; + return _uart != 0 && _uart->rxEnabled; } int HardwareSerial::available(void) { - int result = 0; + if(_uart == 0 || !_uart->rxEnabled) + return 0; - if (_uart != NULL && _uart->rxEnabled) { - InterruptLock il; - result = static_cast(_rx_buffer->available()); - } - - if (!result) { - optimistic_yield(USD(_uart->uart_nr) / 128); - } - - return result; + int result = static_cast(uart_rx_available(_uart)); + if (!result) { + optimistic_yield(USD(_uart->uart_nr) / 128); + } + return result; } int HardwareSerial::peek(void) { - if(_uart == 0) - return -1; - if(_uart->rxEnabled) { - InterruptLock il; - return _rx_buffer->peek(); - } else { - return -1; - } + return -1; } int HardwareSerial::read(void) { - if(_uart == 0) - return -1; - if(_uart->rxEnabled) { - InterruptLock il; - return _rx_buffer->read(); - } else { - return -1; - } + if(_uart == 0 || !_uart->rxEnabled) + return -1; + + return static_cast(uart_read_char(_uart)); } int HardwareSerial::availableForWrite(void) { - if(_uart == 0) - return 0; - if(_uart->txEnabled) { - InterruptLock il; - return static_cast(_tx_buffer->room()); - } else { - return 0; - } + if(_uart == 0 || !_uart->txEnabled) + return 0; + + return static_cast(uart_tx_free(_uart)); } void HardwareSerial::flush() { - if(_uart == 0) - return; - if(!_uart->txEnabled) - return; - - const int uart_nr = _uart->uart_nr; - while(true) { - { - InterruptLock il; - if(_tx_buffer->available() == 0 && - UART_GET_TX_FIFO_ROOM(uart_nr) >= UART_TX_FIFO_SIZE) { - break; - } else if(il.savedInterruptLevel() > 0) { - _tx_empty_irq(); - continue; - } - } - yield(); - } -} + if(_uart == 0 || !_uart->txEnabled) + return; -size_t HardwareSerial::write(uint8_t c) { - if(_uart == 0 || !_uart->txEnabled) - return 0; - - bool tx_now = false; - const int uart_nr = _uart->uart_nr; - while(true) { - { - InterruptLock il; - if(_tx_buffer->empty()) { - if(UART_GET_TX_FIFO_ROOM(uart_nr) > 0) { - tx_now = true; - } else { - _tx_buffer->write(c); - UART_ARM_TX_INTERRUPT(uart_nr); - } - break; - } else if(_tx_buffer->write(c)) { - break; - } else if(il.savedInterruptLevel() > 0) { - _tx_empty_irq(); - continue; - } - } - yield(); - } - if (tx_now) { - UART_TRANSMIT_CHAR(uart_nr, c); - } - return 1; + uart_wait_tx_empty(_uart); } -HardwareSerial::operator bool() const { - return _uart != 0; -} +size_t HardwareSerial::write(uint8_t c) { + if(_uart == 0 || !_uart->txEnabled) + return 0; -void ICACHE_RAM_ATTR HardwareSerial::_rx_complete_irq(char c) { - _rx_buffer->write(c); + uart_write_char(_uart, c); + return 1; } -void ICACHE_RAM_ATTR HardwareSerial::_tx_empty_irq(void) { - const int uart_nr = _uart->uart_nr; - size_t queued = _tx_buffer->available(); - if(!queued) { - UART_DISARM_TX_INTERRUPT(uart_nr); - return; - } - - size_t room = UART_GET_TX_FIFO_ROOM(uart_nr); - int n = static_cast((queued < room) ? queued : room); - while(n--) { - UART_TRANSMIT_CHAR(uart_nr, _tx_buffer->read()); - } +HardwareSerial::operator bool() const { + return _uart != 0; } diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h index ed96438467..44484aa180 100644 --- a/cores/esp8266/HardwareSerial.h +++ b/cores/esp8266/HardwareSerial.h @@ -64,14 +64,13 @@ #define SERIAL_RX_ONLY 1 #define SERIAL_TX_ONLY 2 -class cbuf; - struct uart_; typedef struct uart_ uart_t; class HardwareSerial: public Stream { public: HardwareSerial(int uart_nr); + virtual ~HardwareSerial(){} void begin(unsigned long baud) { begin(baud, SERIAL_8N1, SERIAL_FULL, 1); @@ -127,15 +126,10 @@ class HardwareSerial: public Stream { bool isRxEnabled(void); protected: - friend void uart_interrupt_handler(uart_t* uart); - void _rx_complete_irq(char c); - void _tx_empty_irq(void); protected: int _uart_nr; uart_t* _uart; - cbuf* _tx_buffer; - cbuf* _rx_buffer; }; extern HardwareSerial Serial; From 7960b633576fb5d64c1ff44324fd000af6b17020 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 25 Jan 2016 11:49:27 +0300 Subject: [PATCH 2/5] Move UART HAL into separate file, clean up code --- cores/esp8266/HardwareSerial.cpp | 497 ++++++------------------------- cores/esp8266/HardwareSerial.h | 207 ++++++------- cores/esp8266/uart.c | 396 ++++++++++++++++++++++++ cores/esp8266/uart.h | 100 +++++++ 4 files changed, 701 insertions(+), 499 deletions(-) create mode 100644 cores/esp8266/uart.c create mode 100644 cores/esp8266/uart.h diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index beb4a498be..3e9b8e5398 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -28,450 +28,149 @@ #include #include #include "Arduino.h" -#include "cbuf.h" -#include "interrupts.h" - -extern "C" { -#include "osapi.h" -#include "ets_sys.h" -#include "mem.h" -#include "user_interface.h" -} - #include "HardwareSerial.h" -#define UART_TX_FIFO_SIZE 0x80 - -struct uart_ { - int uart_nr; - int baud_rate; - bool rxEnabled; - bool txEnabled; - uint8_t rxPin; - uint8_t txPin; -}; - -static const int UART0 = 0; -static const int UART1 = 1; -static const int UART_NO = -1; - - -/** - * UART GPIOs - * - * UART0 TX: 1 or 2 - * UART0 RX: 3 - * - * UART0 SWAP TX: 15 - * UART0 SWAP RX: 13 - * - * - * UART1 TX: 7 (NC) or 2 - * UART1 RX: 8 (NC) - * - * UART1 SWAP TX: 11 (NC) - * UART1 SWAP RX: 6 (NC) - * - * NC = Not Connected to Module Pads --> No Access - * - */ - -// #################################################################################################### -// #################################################################################################### -// #################################################################################################### -HardwareSerial Serial(UART0); -HardwareSerial Serial1(UART1); +HardwareSerial::HardwareSerial(int uart_nr) + : _uart_nr(uart_nr) + , _uart(0) +{} -void uart_write_char(uart_t* uart, char c) { - if(uart == 0 || !uart->txEnabled) - return; - while((USS(uart->uart_nr) >> USTXC) >= 0x7f); - USF(uart->uart_nr) = c; -} - -void uart_write(uart_t* uart, const char* buf, size_t size) { - if(uart == 0 || !uart->txEnabled) - return; - while(size--) - uart_write_char(uart, *buf++); -} +void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin) +{ + if(uart_get_debug() == _uart_nr) { + uart_set_debug(UART_NO); + } -uint8_t uart_read_char(uart_t* uart){ - if(uart == 0 || !uart->rxEnabled) - return 0; - return USF(uart->uart_nr) & 0xff; -} + if (_uart) { + free(_uart); + } -uint8_t uart_rx_available(uart_t* uart){ - if(uart == 0 || !uart->rxEnabled) - return 0; - return (USS(uart->uart_nr) >> USRXC) & 0xff; + _uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin); } -uint8_t uart_tx_free(uart_t* uart){ - if(uart == 0 || !uart->txEnabled) - return 0; - return UART_TX_FIFO_SIZE - ((USS(uart->uart_nr) >> USTXC) & 0xff); -} +void HardwareSerial::end() +{ + if(uart_get_debug() == _uart_nr) { + uart_set_debug(UART_NO); + } -void uart_wait_tx_empty(uart_t* uart){ - if(uart == 0 || !uart->txEnabled) - return; - while(((USS(uart->uart_nr) >> USTXC) & 0xff) > 0) delay(0); + uart_uninit(_uart); } -void uart_flush(uart_t* uart) { - if(uart == 0) - return; - - uint32_t tmp = 0x00000000; - if(uart->rxEnabled) { - tmp |= (1 << UCRXRST); - } - - if(uart->txEnabled) { - tmp |= (1 << UCTXRST); - } - - USC0(uart->uart_nr) |= (tmp); - USC0(uart->uart_nr) &= ~(tmp); +void HardwareSerial::swap(uint8_t tx_pin) +{ + if(!_uart) { + return; + } + uart_swap(_uart, tx_pin); } -void uart_set_baudrate(uart_t* uart, int baud_rate) { - if(uart == 0) - return; - uart->baud_rate = baud_rate; - USD(uart->uart_nr) = (ESP8266_CLOCK / uart->baud_rate); +void HardwareSerial::set_tx(uint8_t tx_pin) +{ + if(!_uart) { + return; + } + uart_set_tx(_uart, tx_pin); } -int uart_get_baudrate(uart_t* uart) { - if(uart == 0) - return 0; - return uart->baud_rate; +void HardwareSerial::pins(uint8_t tx, uint8_t rx) +{ + if(!_uart) { + return; + } + uart_set_pins(_uart, tx, rx); } -// #################################################################################################### -// #################################################################################################### -// #################################################################################################### - -uart_t* uart_init(int uart_nr, int baudrate, byte config, byte mode, uint8_t use_tx) { - - uart_t* uart = (uart_t*) os_malloc(sizeof(uart_t)); - - if(uart == 0) { - return 0; - } - - uart->uart_nr = uart_nr; - - switch(uart->uart_nr) { - case UART0: - uart->rxEnabled = (mode != SERIAL_TX_ONLY); - uart->txEnabled = (mode != SERIAL_RX_ONLY); - uart->rxPin = (uart->rxEnabled)?3:255; - if(uart->rxEnabled) { - if (use_tx == 2) { - uart->txPin = 2; - pinMode(uart->rxPin, FUNCTION_4); +void HardwareSerial::setDebugOutput(bool en) +{ + if(!_uart) { + return; + } + if(en) { + if(uart_tx_enabled(_uart)) { + uart_set_debug(_uart_nr); } else { - uart->txPin = 1; - pinMode(uart->rxPin, SPECIAL); - } - } else uart->txPin = 255; - if(uart->txEnabled) pinMode(uart->txPin, SPECIAL); - IOSWAP &= ~(1 << IOSWAPU0); - break; - case UART1: - // Note: uart_interrupt_handler does not support RX on UART 1. - uart->rxEnabled = false; - uart->txEnabled = (mode != SERIAL_RX_ONLY); - uart->rxPin = 255; - uart->txPin = (uart->txEnabled)?2:255; // GPIO7 as TX not possible! See GPIO pins used by UART - if(uart->txEnabled) pinMode(uart->txPin, SPECIAL); - break; - case UART_NO: - default: - // big fail! - os_free(uart); - return 0; - } - - uart_set_baudrate(uart, baudrate); - USC0(uart->uart_nr) = config; - uart_flush(uart); - USC1(uart->uart_nr) = 0; - - return uart; -} - -void uart_uninit(uart_t* uart) { - if(uart == 0) - return; - - switch(uart->rxPin) { - case 3: - pinMode(3, INPUT); - break; - case 13: - pinMode(13, INPUT); - break; - } - - switch(uart->txPin) { - case 1: - pinMode(1, INPUT); - break; - case 2: - pinMode(2, INPUT); - break; - case 15: - pinMode(15, INPUT); - break; - } - - os_free(uart); -} - -void uart_swap(uart_t* uart, uint8_t use_tx) { - if(uart == 0) - return; - switch(uart->uart_nr) { - case UART0: - if(((uart->txPin == 1 || uart->txPin == 2) && uart->txEnabled) || (uart->rxPin == 3 && uart->rxEnabled)) { - if(uart->txEnabled){ //TX - pinMode(uart->txPin, INPUT); - uart->txPin = 15; - } - if(uart->rxEnabled){ //RX - pinMode(uart->rxPin, INPUT); - uart->rxPin = 13; + uart_set_debug(UART_NO); } - if(uart->txEnabled) pinMode(uart->txPin, FUNCTION_4); //TX - if(uart->rxEnabled) pinMode(uart->rxPin, FUNCTION_4); //RX - IOSWAP |= (1 << IOSWAPU0); - } else { - if(uart->txEnabled){ //TX - pinMode(uart->txPin, INPUT); - uart->txPin = (use_tx == 2)?2:1; + } else { + // disable debug for this interface + if(uart_get_debug() == _uart_nr) { + uart_set_debug(UART_NO); } - if(uart->rxEnabled){ //RX - pinMode(uart->rxPin, INPUT); - uart->rxPin = 3; - } - if(uart->txEnabled) pinMode(uart->txPin, (use_tx == 2)?FUNCTION_4:SPECIAL); //TX - if(uart->rxEnabled) pinMode(3, SPECIAL); //RX - IOSWAP &= ~(1 << IOSWAPU0); - } - - break; - case UART1: - // Currently no swap possible! See GPIO pins used by UART - break; - default: - break; - } -} - -void uart_set_tx(uart_t* uart, uint8_t use_tx) { - if(uart == 0) - return; - switch(uart->uart_nr) { - case UART0: - if(uart->txEnabled) { - if (uart->txPin == 1 && use_tx == 2) { - pinMode(uart->txPin, INPUT); - uart->txPin = 2; - pinMode(uart->txPin, FUNCTION_4); - } else if (uart->txPin == 2 && use_tx != 2) { - pinMode(uart->txPin, INPUT); - uart->txPin = 1; - pinMode(uart->txPin, SPECIAL); - } - } - - break; - case UART1: - // GPIO7 as TX not possible! See GPIO pins used by UART - break; - default: - break; - } -} - -void uart_set_pins(uart_t* uart, uint8_t tx, uint8_t rx) { - if(uart == 0) - return; - - if(uart->uart_nr == UART0) { // Only UART0 allows pin changes - if(uart->txEnabled && uart->txPin != tx) { - if( rx == 13 && tx == 15) { - uart_swap(uart, 15); - } else if (rx == 3 && (tx == 1 || tx == 2)) { - if (uart->rxPin != rx) uart_swap(uart, tx); - else uart_set_tx(uart, tx); - } - } - if(uart->rxEnabled && uart->rxPin != rx && rx == 13 && tx == 15) { - uart_swap(uart, 15); } - } -} - -// #################################################################################################### -// #################################################################################################### -// #################################################################################################### - -void uart_ignore_char(char c) {} - -void uart0_write_char(char c) { - while(((USS(0) >> USTXC) & 0xff) >= 0x7F) delay(0); - USF(0) = c; -} - -void uart1_write_char(char c) { - while(((USS(1) >> USTXC) & 0xff) >= 0x7F) delay(0); - USF(1) = c; -} - -static int s_uart_debug_nr = UART0; - -void uart_set_debug(int uart_nr) { - s_uart_debug_nr = uart_nr; - switch(s_uart_debug_nr) { - case UART0: - system_set_os_print(1); - ets_install_putc1((void *) &uart0_write_char); - break; - case UART1: - system_set_os_print(1); - ets_install_putc1((void *) &uart1_write_char); - break; - case UART_NO: - default: - system_set_os_print(0); - ets_install_putc1((void *) &uart_ignore_char); - break; - } } -int uart_get_debug() { - return s_uart_debug_nr; +bool HardwareSerial::isTxEnabled(void) +{ + return _uart && uart_tx_enabled(_uart); } - -// #################################################################################################### -// #################################################################################################### -// #################################################################################################### - -HardwareSerial::HardwareSerial(int uart_nr) - : _uart_nr(uart_nr) - , _uart(0) -{} - -void HardwareSerial::begin(unsigned long baud, byte config, byte mode, uint8_t use_tx) { - if(uart_get_debug() == _uart_nr) - uart_set_debug(UART_NO); - - if (_uart) - os_free(_uart); - - _uart = uart_init(_uart_nr, baud, config, mode, use_tx); -} - -void HardwareSerial::end() { - if(uart_get_debug() == _uart_nr) - uart_set_debug(UART_NO); - - uart_uninit(_uart); +bool HardwareSerial::isRxEnabled(void) +{ + return _uart && uart_rx_enabled(_uart); } -void HardwareSerial::swap(uint8_t use_tx) { - if(_uart == 0) - return; - uart_swap(_uart, use_tx); -} +int HardwareSerial::available(void) +{ + if(!_uart || !uart_rx_enabled(_uart)) { + return 0; + } -void HardwareSerial::set_tx(uint8_t use_tx) { - if(_uart == 0) - return; - uart_set_tx(_uart, use_tx); + int result = static_cast(uart_rx_available(_uart)); + if (!result) { + optimistic_yield(USD(_uart_nr) / 128); + } + return result; } -void HardwareSerial::pins(uint8_t tx, uint8_t rx) { - if(_uart == 0) - return; - uart_set_pins(_uart, tx, rx); +int HardwareSerial::peek(void) +{ + return -1; } -void HardwareSerial::setDebugOutput(bool en) { - if(_uart == 0) - return; - if(en) { - if(_uart->txEnabled) - uart_set_debug(_uart->uart_nr); - else - uart_set_debug(UART_NO); - } else { - // disable debug for this interface - if(uart_get_debug() == _uart_nr) { - uart_set_debug(UART_NO); +int HardwareSerial::read(void) +{ + if(!_uart || !uart_rx_enabled(_uart)) { + return -1; } - } -} - -bool ICACHE_RAM_ATTR HardwareSerial::isTxEnabled(void) { - return _uart != 0 && _uart->txEnabled; -} -bool ICACHE_RAM_ATTR HardwareSerial::isRxEnabled(void) { - return _uart != 0 && _uart->rxEnabled; + return uart_read_char(_uart); } -int HardwareSerial::available(void) { - if(_uart == 0 || !_uart->rxEnabled) - return 0; - - int result = static_cast(uart_rx_available(_uart)); - if (!result) { - optimistic_yield(USD(_uart->uart_nr) / 128); - } - return result; -} +int HardwareSerial::availableForWrite(void) +{ + if(!_uart || !uart_tx_enabled(_uart)) { + return 0; + } -int HardwareSerial::peek(void) { - return -1; + return static_cast(uart_tx_free(_uart)); } -int HardwareSerial::read(void) { - if(_uart == 0 || !_uart->rxEnabled) - return -1; +void HardwareSerial::flush() +{ + if(!_uart || !uart_tx_enabled(_uart)) { + return; + } - return static_cast(uart_read_char(_uart)); + uart_wait_tx_empty(_uart); } -int HardwareSerial::availableForWrite(void) { - if(_uart == 0 || !_uart->txEnabled) - return 0; +size_t HardwareSerial::write(uint8_t c) +{ + if(!_uart || !uart_tx_enabled(_uart)) { + return 0; + } - return static_cast(uart_tx_free(_uart)); + uart_write_char(_uart, c); + return 1; } -void HardwareSerial::flush() { - if(_uart == 0 || !_uart->txEnabled) - return; - - uart_wait_tx_empty(_uart); +HardwareSerial::operator bool() const +{ + return _uart != 0; } -size_t HardwareSerial::write(uint8_t c) { - if(_uart == 0 || !_uart->txEnabled) - return 0; - uart_write_char(_uart, c); - return 1; -} - -HardwareSerial::operator bool() const { - return _uart != 0; -} +HardwareSerial Serial(UART0); +HardwareSerial Serial1(UART1); diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h index 44484aa180..51ce09b2a0 100644 --- a/cores/esp8266/HardwareSerial.h +++ b/cores/esp8266/HardwareSerial.h @@ -28,108 +28,115 @@ #define HardwareSerial_h #include - #include "Stream.h" +#include "uart.h" + +enum SerialConfig { + SERIAL_5N1 = UART_5N1, + SERIAL_6N1 = UART_6N1, + SERIAL_7N1 = UART_7N1, + SERIAL_8N1 = UART_8N1, + SERIAL_5N2 = UART_5N2, + SERIAL_6N2 = UART_6N2, + SERIAL_7N2 = UART_7N2, + SERIAL_8N2 = UART_8N2, + SERIAL_5E1 = UART_5E1, + SERIAL_6E1 = UART_6E1, + SERIAL_7E1 = UART_7E1, + SERIAL_8E1 = UART_8E1, + SERIAL_5E2 = UART_5E2, + SERIAL_6E2 = UART_6E2, + SERIAL_7E2 = UART_7E2, + SERIAL_8E2 = UART_8E2, + SERIAL_5O1 = UART_5O1, + SERIAL_6O1 = UART_6O1, + SERIAL_7O1 = UART_7O1, + SERIAL_8O1 = UART_8O1, + SERIAL_5O2 = UART_5O2, + SERIAL_6O2 = UART_6O2, + SERIAL_7O2 = UART_7O2, + SERIAL_8O2 = UART_8O2, +}; + +enum SerialMode { + SERIAL_FULL = UART_FULL, + SERIAL_RX_ONLY = UART_RX_ONLY, + SERIAL_TX_ONLY = UART_TX_ONLY +}; -#define SERIAL_TX_BUFFER_SIZE 256 -#define SERIAL_RX_BUFFER_SIZE 256 - -// Define config for Serial.begin(baud, config); -#define SERIAL_5N1 0x10 -#define SERIAL_6N1 0x14 -#define SERIAL_7N1 0x18 -#define SERIAL_8N1 0x1c -#define SERIAL_5N2 0x30 -#define SERIAL_6N2 0x34 -#define SERIAL_7N2 0x38 -#define SERIAL_8N2 0x3c -#define SERIAL_5E1 0x12 -#define SERIAL_6E1 0x16 -#define SERIAL_7E1 0x1a -#define SERIAL_8E1 0x1e -#define SERIAL_5E2 0x32 -#define SERIAL_6E2 0x36 -#define SERIAL_7E2 0x3a -#define SERIAL_8E2 0x3e -#define SERIAL_5O1 0x13 -#define SERIAL_6O1 0x17 -#define SERIAL_7O1 0x1b -#define SERIAL_8O1 0x1f -#define SERIAL_5O2 0x33 -#define SERIAL_6O2 0x37 -#define SERIAL_7O2 0x3b -#define SERIAL_8O2 0x3f - -#define SERIAL_FULL 0 -#define SERIAL_RX_ONLY 1 -#define SERIAL_TX_ONLY 2 - -struct uart_; -typedef struct uart_ uart_t; - -class HardwareSerial: public Stream { - public: - HardwareSerial(int uart_nr); - virtual ~HardwareSerial(){} - - void begin(unsigned long baud) { - begin(baud, SERIAL_8N1, SERIAL_FULL, 1); - } - void begin(unsigned long baud, uint8_t config) { - begin(baud, config, SERIAL_FULL, 1); - } - void begin(unsigned long baud, uint8_t config, uint8_t mode) { - begin(baud, config, mode, 1); - } - void begin(unsigned long, uint8_t, uint8_t, uint8_t); - void end(); - void swap() { - swap(1); - } - void swap(uint8_t use_tx); //toggle between use of GPIO13/GPIO15 or GPIO3/GPIO(1/2) as RX and TX - - /* - * Toggle between use of GPIO1 and GPIO2 as TX on UART 0. - * Note: UART 1 can't be used if GPIO2 is used with UART 0! - */ - void set_tx(uint8_t use_tx); - - /* - * UART 0 possible options are (1, 3), (2, 3) or (15, 13) - * UART 1 allows only TX on 2 if UART 0 is not (2, 3) - */ - void pins(uint8_t tx, uint8_t rx); - - int available(void) override; - int peek(void) override; - int read(void) override; - int availableForWrite(void); - void flush(void) override; - size_t write(uint8_t) override; - inline size_t write(unsigned long n) { - return write((uint8_t) n); - } - inline size_t write(long n) { - return write((uint8_t) n); - } - inline size_t write(unsigned int n) { - return write((uint8_t) n); - } - inline size_t write(int n) { - return write((uint8_t) n); - } - using Print::write; // pull in write(str) and write(buf, size) from Print - operator bool() const; - - void setDebugOutput(bool); - bool isTxEnabled(void); - bool isRxEnabled(void); - - protected: - - protected: - int _uart_nr; - uart_t* _uart; +class HardwareSerial: public Stream +{ +public: + HardwareSerial(int uart_nr); + virtual ~HardwareSerial() {} + + void begin(unsigned long baud) + { + begin(baud, SERIAL_8N1, SERIAL_FULL, 1); + } + void begin(unsigned long baud, SerialConfig config) + { + begin(baud, config, SERIAL_FULL, 1); + } + void begin(unsigned long baud, SerialConfig config, SerialMode mode) + { + begin(baud, config, mode, 1); + } + + void begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin); + + void end(); + + void swap() + { + swap(1); + } + void swap(uint8_t tx_pin); //toggle between use of GPIO13/GPIO15 or GPIO3/GPIO(1/2) as RX and TX + + /* + * Toggle between use of GPIO1 and GPIO2 as TX on UART 0. + * Note: UART 1 can't be used if GPIO2 is used with UART 0! + */ + void set_tx(uint8_t tx_pin); + + /* + * UART 0 possible options are (1, 3), (2, 3) or (15, 13) + * UART 1 allows only TX on 2 if UART 0 is not (2, 3) + */ + void pins(uint8_t tx, uint8_t rx); + + int available(void) override; + int peek(void) override; + int read(void) override; + int availableForWrite(void); + void flush(void) override; + size_t write(uint8_t) override; + inline size_t write(unsigned long n) + { + return write((uint8_t) n); + } + inline size_t write(long n) + { + return write((uint8_t) n); + } + inline size_t write(unsigned int n) + { + return write((uint8_t) n); + } + inline size_t write(int n) + { + return write((uint8_t) n); + } + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool() const; + + void setDebugOutput(bool); + bool isTxEnabled(void); + bool isRxEnabled(void); + +protected: + int _uart_nr; + uart_t* _uart; }; extern HardwareSerial Serial; diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c new file mode 100644 index 0000000000..d7a3640082 --- /dev/null +++ b/cores/esp8266/uart.c @@ -0,0 +1,396 @@ +/* + uart.cpp - esp8266 UART HAL + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + */ + + +/** + * UART GPIOs + * + * UART0 TX: 1 or 2 + * UART0 RX: 3 + * + * UART0 SWAP TX: 15 + * UART0 SWAP RX: 13 + * + * + * UART1 TX: 7 (NC) or 2 + * UART1 RX: 8 (NC) + * + * UART1 SWAP TX: 11 (NC) + * UART1 SWAP RX: 6 (NC) + * + * NC = Not Connected to Module Pads --> No Access + * + */ +#include "Arduino.h" +#include "uart.h" +#include "esp8266_peri.h" +#include "user_interface.h" + +static int s_uart_debug_nr = UART0; + +struct uart_ { + int uart_nr; + int baud_rate; + bool rx_enabled; + bool tx_enabled; + uint8_t rx_pin; + uint8_t tx_pin; +}; + +void uart_write_char(uart_t* uart, char c) +{ + if(uart == NULL || !uart->tx_enabled) { + return; + } + while((USS(uart->uart_nr) >> USTXC) >= 0x7f); + USF(uart->uart_nr) = c; +} + +void uart_write(uart_t* uart, const char* buf, size_t size) +{ + if(uart == NULL || !uart->tx_enabled) { + return; + } + while(size--) { + uart_write_char(uart, *buf++); + } +} + +int uart_read_char(uart_t* uart) +{ + if(uart == NULL || !uart->rx_enabled) { + return -1; + } + return USF(uart->uart_nr) & 0xff; +} + +size_t uart_rx_available(uart_t* uart) +{ + if(uart == NULL || !uart->rx_enabled) { + return -1; + } + return (USS(uart->uart_nr) >> USRXC) & 0xff; +} + +size_t uart_tx_free(uart_t* uart) +{ + if(uart == NULL || !uart->tx_enabled) { + return 0; + } + return UART_TX_FIFO_SIZE - ((USS(uart->uart_nr) >> USTXC) & 0xff); +} + +void uart_wait_tx_empty(uart_t* uart) +{ + if(uart == NULL || !uart->tx_enabled) { + return; + } + while(((USS(uart->uart_nr) >> USTXC) & 0xff) > 0) { + delay(0); + } +} + +void uart_flush(uart_t* uart) +{ + if(uart == NULL) { + return; + } + + uint32_t tmp = 0x00000000; + if(uart->rx_enabled) { + tmp |= (1 << UCRXRST); + } + + if(uart->tx_enabled) { + tmp |= (1 << UCTXRST); + } + + USC0(uart->uart_nr) |= (tmp); + USC0(uart->uart_nr) &= ~(tmp); +} + +void uart_set_baudrate(uart_t* uart, int baud_rate) +{ + if(uart == NULL) { + return; + } + uart->baud_rate = baud_rate; + USD(uart->uart_nr) = (ESP8266_CLOCK / uart->baud_rate); +} + +int uart_get_baudrate(uart_t* uart) +{ + if(uart == NULL) { + return 0; + } + return uart->baud_rate; +} + +uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin) +{ + uart_t* uart = (uart_t*) malloc(sizeof(uart_t)); + if(uart == NULL) { + return NULL; + } + + uart->uart_nr = uart_nr; + + switch(uart->uart_nr) { + case UART0: + uart->rx_enabled = (mode != UART_TX_ONLY); + uart->tx_enabled = (mode != UART_RX_ONLY); + uart->rx_pin = (uart->rx_enabled)?3:255; + if(uart->rx_enabled) { + if (tx_pin == 2) { + uart->tx_pin = 2; + pinMode(uart->rx_pin, FUNCTION_4); + } else { + uart->tx_pin = 1; + pinMode(uart->rx_pin, SPECIAL); + } + } else { + uart->tx_pin = 255; + } + if(uart->tx_enabled) { + pinMode(uart->tx_pin, SPECIAL); + } + IOSWAP &= ~(1 << IOSWAPU0); + break; + case UART1: + // Note: uart_interrupt_handler does not support RX on UART 1. + uart->rx_enabled = false; + uart->tx_enabled = (mode != UART_RX_ONLY); + uart->rx_pin = 255; + uart->tx_pin = (uart->tx_enabled)?2:255; // GPIO7 as TX not possible! See GPIO pins used by UART + if(uart->tx_enabled) { + pinMode(uart->tx_pin, SPECIAL); + } + break; + case UART_NO: + default: + // big fail! + free(uart); + return NULL; + } + + uart_set_baudrate(uart, baudrate); + USC0(uart->uart_nr) = config; + uart_flush(uart); + USC1(uart->uart_nr) = 0; + + return uart; +} + +void uart_uninit(uart_t* uart) +{ + if(uart == NULL) { + return; + } + + switch(uart->rx_pin) { + case 3: + pinMode(3, INPUT); + break; + case 13: + pinMode(13, INPUT); + break; + } + + switch(uart->tx_pin) { + case 1: + pinMode(1, INPUT); + break; + case 2: + pinMode(2, INPUT); + break; + case 15: + pinMode(15, INPUT); + break; + } + + os_free(uart); +} + +void uart_swap(uart_t* uart, int tx_pin) +{ + if(uart == NULL) { + return; + } + switch(uart->uart_nr) { + case UART0: + if(((uart->tx_pin == 1 || uart->tx_pin == 2) && uart->tx_enabled) || (uart->rx_pin == 3 && uart->rx_enabled)) { + if(uart->tx_enabled) { //TX + pinMode(uart->tx_pin, INPUT); + uart->tx_pin = 15; + } + if(uart->rx_enabled) { //RX + pinMode(uart->rx_pin, INPUT); + uart->rx_pin = 13; + } + if(uart->tx_enabled) { + pinMode(uart->tx_pin, FUNCTION_4); //TX + } + if(uart->rx_enabled) { + pinMode(uart->rx_pin, FUNCTION_4); //RX + } + IOSWAP |= (1 << IOSWAPU0); + } else { + if(uart->tx_enabled) { //TX + pinMode(uart->tx_pin, INPUT); + uart->tx_pin = (tx_pin == 2)?2:1; + } + if(uart->rx_enabled) { //RX + pinMode(uart->rx_pin, INPUT); + uart->rx_pin = 3; + } + if(uart->tx_enabled) { + pinMode(uart->tx_pin, (tx_pin == 2)?FUNCTION_4:SPECIAL); //TX + } + if(uart->rx_enabled) { + pinMode(3, SPECIAL); //RX + } + IOSWAP &= ~(1 << IOSWAPU0); + } + + break; + case UART1: + // Currently no swap possible! See GPIO pins used by UART + break; + default: + break; + } +} + +void uart_set_tx(uart_t* uart, int tx_pin) +{ + if(uart == NULL) { + return; + } + switch(uart->uart_nr) { + case UART0: + if(uart->tx_enabled) { + if (uart->tx_pin == 1 && tx_pin == 2) { + pinMode(uart->tx_pin, INPUT); + uart->tx_pin = 2; + pinMode(uart->tx_pin, FUNCTION_4); + } else if (uart->tx_pin == 2 && tx_pin != 2) { + pinMode(uart->tx_pin, INPUT); + uart->tx_pin = 1; + pinMode(uart->tx_pin, SPECIAL); + } + } + + break; + case UART1: + // GPIO7 as TX not possible! See GPIO pins used by UART + break; + default: + break; + } +} + +void uart_set_pins(uart_t* uart, int tx, int rx) +{ + if(uart == NULL) { + return; + } + + if(uart->uart_nr == UART0) { // Only UART0 allows pin changes + if(uart->tx_enabled && uart->tx_pin != tx) { + if( rx == 13 && tx == 15) { + uart_swap(uart, 15); + } else if (rx == 3 && (tx == 1 || tx == 2)) { + if (uart->rx_pin != rx) { + uart_swap(uart, tx); + } else { + uart_set_tx(uart, tx); + } + } + } + if(uart->rx_enabled && uart->rx_pin != rx && rx == 13 && tx == 15) { + uart_swap(uart, 15); + } + } +} + + +bool uart_tx_enabled(uart_t* uart) +{ + if(uart == NULL) { + return false; + } + return uart->tx_enabled; +} + +bool uart_rx_enabled(uart_t* uart) +{ + if(uart == NULL) { + return false; + } + return uart->rx_enabled; +} + + +static void uart_ignore_char(char c) +{ +} + +static void uart0_write_char(char c) +{ + while(((USS(0) >> USTXC) & 0xff) >= 0x7F) { + delay(0); + } + USF(0) = c; +} + +static void uart1_write_char(char c) +{ + while(((USS(1) >> USTXC) & 0xff) >= 0x7F) { + delay(0); + } + USF(1) = c; +} + +void uart_set_debug(int uart_nr) +{ + s_uart_debug_nr = uart_nr; + switch(s_uart_debug_nr) { + case UART0: + system_set_os_print(1); + ets_install_putc1((void *) &uart0_write_char); + break; + case UART1: + system_set_os_print(1); + ets_install_putc1((void *) &uart1_write_char); + break; + case UART_NO: + default: + system_set_os_print(0); + ets_install_putc1((void *) &uart_ignore_char); + break; + } +} + +int uart_get_debug() +{ + return s_uart_debug_nr; +} diff --git a/cores/esp8266/uart.h b/cores/esp8266/uart.h new file mode 100644 index 0000000000..27b6f56b15 --- /dev/null +++ b/cores/esp8266/uart.h @@ -0,0 +1,100 @@ +/* + uart.h - UART HAL + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ +#ifndef ESP_UART_H + +#include +#include +#include + +#if defined (__cplusplus) +extern "C" { +#endif + +#define UART0 0 +#define UART1 1 +#define UART_NO -1 + +// Options for `config` argument of uart_init +#define UART_5N1 0x10 +#define UART_6N1 0x14 +#define UART_7N1 0x18 +#define UART_8N1 0x1c +#define UART_5N2 0x30 +#define UART_6N2 0x34 +#define UART_7N2 0x38 +#define UART_8N2 0x3c +#define UART_5E1 0x12 +#define UART_6E1 0x16 +#define UART_7E1 0x1a +#define UART_8E1 0x1e +#define UART_5E2 0x32 +#define UART_6E2 0x36 +#define UART_7E2 0x3a +#define UART_8E2 0x3e +#define UART_5O1 0x13 +#define UART_6O1 0x17 +#define UART_7O1 0x1b +#define UART_8O1 0x1f +#define UART_5O2 0x33 +#define UART_6O2 0x37 +#define UART_7O2 0x3b +#define UART_8O2 0x3f + +// Options for `mode` argument of uart_init +#define UART_FULL 0 +#define UART_RX_ONLY 1 +#define UART_TX_ONLY 2 + +#define UART_TX_FIFO_SIZE 0x80 + +struct uart_; +typedef struct uart_ uart_t; + +uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin); +void uart_uninit(uart_t* uart); + +void uart_swap(uart_t* uart, int tx_pin); +void uart_set_tx(uart_t* uart, int tx_pin); +void uart_set_pins(uart_t* uart, int tx, int rx); +bool uart_tx_enabled(uart_t* uart); +bool uart_rx_enabled(uart_t* uart); + +void uart_set_baudrate(uart_t* uart, int baud_rate); +int uart_get_baudrate(uart_t* uart); + +void uart_write_char(uart_t* uart, char c); +void uart_write(uart_t* uart, const char* buf, size_t size); +int uart_read_char(uart_t* uart); +size_t uart_rx_available(uart_t* uart); +size_t uart_tx_free(uart_t* uart); +void uart_wait_tx_empty(uart_t* uart); +void uart_flush(uart_t* uart); + +void uart_set_debug(int uart_nr); +int uart_get_debug(); + + +#if defined (__cplusplus) +} // extern "C" +#endif + +#endif // ESP_UART_H From 16c0f3f1d5fa0cb7ded90e3c1b764e10dd9756e5 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 25 Jan 2016 12:05:02 +0300 Subject: [PATCH 3/5] Implement HardwareSerial::peek --- cores/esp8266/HardwareSerial.cpp | 17 +++++++++++++++-- cores/esp8266/HardwareSerial.h | 3 ++- cores/esp8266/uart.c | 3 +++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 3e9b8e5398..f15782607c 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -33,7 +33,6 @@ HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr) - , _uart(0) {} void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin) @@ -47,6 +46,7 @@ void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode m } _uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin); + _peek_char = -1; } void HardwareSerial::end() @@ -118,6 +118,9 @@ int HardwareSerial::available(void) } int result = static_cast(uart_rx_available(_uart)); + if (_peek_char != -1) { + result += 1; + } if (!result) { optimistic_yield(USD(_uart_nr) / 128); } @@ -126,7 +129,12 @@ int HardwareSerial::available(void) int HardwareSerial::peek(void) { - return -1; + if (_peek_char != -1) { + return _peek_char; + } + // this may return -1, but that's okay + _peek_char = uart_read_char(_uart); + return _peek_char; } int HardwareSerial::read(void) @@ -135,6 +143,11 @@ int HardwareSerial::read(void) return -1; } + if (_peek_char != -1) { + auto tmp = _peek_char; + _peek_char = -1; + return tmp; + } return uart_read_char(_uart); } diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h index 51ce09b2a0..bf3dc68cb6 100644 --- a/cores/esp8266/HardwareSerial.h +++ b/cores/esp8266/HardwareSerial.h @@ -136,7 +136,8 @@ class HardwareSerial: public Stream protected: int _uart_nr; - uart_t* _uart; + uart_t* _uart = nullptr; + int _peek_char = -1; }; extern HardwareSerial Serial; diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c index d7a3640082..f2db9ae429 100644 --- a/cores/esp8266/uart.c +++ b/cores/esp8266/uart.c @@ -80,6 +80,9 @@ int uart_read_char(uart_t* uart) if(uart == NULL || !uart->rx_enabled) { return -1; } + if (!uart_rx_available(uart)) { + return -1; + } return USF(uart->uart_nr) & 0xff; } From af18612a4c48527a48f70b4d69ec8256e94f4316 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 25 Jan 2016 12:37:57 +0300 Subject: [PATCH 4/5] Turn of '--verbose' option in Travis builds to place log size within limits --- tests/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common.sh b/tests/common.sh index b4e935168d..1d674081c6 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -12,7 +12,7 @@ function build_sketches() continue fi echo -e "\n\n ------------ Building $sketch ------------ \n\n"; - $arduino --verify --verbose $sketch; + $arduino --verify $sketch; local result=$? if [ $result -ne 0 ]; then echo "Build failed ($1)" From d1149c53e68ef79292486368e2b01da408422ab4 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 26 Jan 2016 16:21:44 +0300 Subject: [PATCH 5/5] Remove UART register reference from HardwareSerial --- cores/esp8266/HardwareSerial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index f15782607c..fb9019a2c6 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -122,7 +122,7 @@ int HardwareSerial::available(void) result += 1; } if (!result) { - optimistic_yield(USD(_uart_nr) / 128); + optimistic_yield(10000); } return result; }