From 1ee7ecdaa23bdc4112cb5937b597919eadd2e263 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Wed, 1 Apr 2015 22:47:13 +0200 Subject: [PATCH 1/2] rewrite HardwareSerial code for UART0 + UART1 support in ESP8266 --- cores/esp8266/HardwareSerial.cpp | 930 +++++++++++++++++++------------ cores/esp8266/HardwareSerial.h | 126 +++-- 2 files changed, 655 insertions(+), 401 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 6be711517..fc6d2c1a4 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -1,352 +1,578 @@ -/* - HardwareSerial.cpp - esp8266 UART support - - 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 -*/ - - -#include -#include -#include -#include -#include "Arduino.h" -#include "cbuf.h" - -extern "C" { -#include "osapi.h" -#include "ets_sys.h" -#include "mem.h" -#include "uart_register.h" -#include "user_interface.h" -} - -#include "HardwareSerial.h" - -HardwareSerial Serial; - -uart_t* uart0_init(int baud_rate); -void uart0_set_baudrate(uart_t* uart, int baud_rate); -int uart0_get_baudrate(uart_t* uart); -void uart0_uninit(uart_t* uart); -void uart0_transmit(uart_t* uart, const char* buf, size_t size); // may block on TX fifo -void uart0_wait_for_transmit(uart_t* uart); -void uart0_transmit_char(uart_t* uart, char c); // does not block, but character will be lost if FIFO is full - -void uart_set_debug(bool enabled); -bool uart_get_debug(); - -struct uart_ -{ - int baud_rate; -}; - -#define UART_TX_FIFO_SIZE 0x80 - -void ICACHE_FLASH_ATTR uart0_interrupt_handler(uart_t* uart) -{ - uint32_t status = READ_PERI_REG(UART_INT_ST(0)); - if (status & UART_RXFIFO_FULL_INT_ST) - { - while(true) - { - int rx_count = (READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT; - if (!rx_count) - break; - - while(rx_count--) - { - char c = READ_PERI_REG(UART_FIFO(0)) & 0xFF; - Serial._rx_complete_irq(c); - } - } - WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR); - } - if (status & UART_TXFIFO_EMPTY_INT_ST) - { - WRITE_PERI_REG(UART_INT_CLR(0), UART_TXFIFO_EMPTY_INT_CLR); - Serial._tx_empty_irq(); - } -} - -void ICACHE_FLASH_ATTR uart0_wait_for_tx_fifo(size_t size_needed) -{ - while (true) - { - size_t tx_count = (READ_PERI_REG(UART_STATUS(0)) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT; - if (tx_count <= (UART_TX_FIFO_SIZE - size_needed)) - break; - } -} - -size_t ICACHE_FLASH_ATTR uart0_get_tx_fifo_room() -{ - return UART_TX_FIFO_SIZE - ((READ_PERI_REG(UART_STATUS(0)) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT); -} - -void ICACHE_FLASH_ATTR uart0_wait_for_transmit(uart_t* uart) -{ - uart0_wait_for_tx_fifo(UART_TX_FIFO_SIZE); -} - -void ICACHE_FLASH_ATTR uart0_transmit_char(uart_t* uart, char c) -{ - WRITE_PERI_REG(UART_FIFO(0), c); -} - -void ICACHE_FLASH_ATTR uart0_transmit(uart_t* uart, const char* buf, size_t size) -{ - while (size) - { - size_t part_size = (size > UART_TX_FIFO_SIZE) ? UART_TX_FIFO_SIZE : size; - size -= part_size; - - uart0_wait_for_tx_fifo(part_size); - for(;part_size;--part_size, ++buf) - WRITE_PERI_REG(UART_FIFO(0), *buf); - } -} - -void ICACHE_FLASH_ATTR uart0_flush(uart_t* uart) -{ - SET_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST | UART_TXFIFO_RST); - CLEAR_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST | UART_TXFIFO_RST); -} - -void ICACHE_FLASH_ATTR uart0_interrupt_enable(uart_t* uart) -{ - WRITE_PERI_REG(UART_INT_CLR(0), 0x1ff); - ETS_UART_INTR_ATTACH(&uart0_interrupt_handler, uart); - SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA); - ETS_UART_INTR_ENABLE(); -} - -void ICACHE_FLASH_ATTR uart0_interrupt_disable(uart_t* uart) -{ - CLEAR_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA); - ETS_UART_INTR_DISABLE(); -} - -void ICACHE_FLASH_ATTR uart0_arm_tx_interrupt() -{ - SET_PERI_REG_MASK(UART_INT_ENA(0), UART_TXFIFO_EMPTY_INT_ENA); -} - -void ICACHE_FLASH_ATTR uart0_disarm_tx_interrupt() -{ - CLEAR_PERI_REG_MASK(UART_INT_ENA(0), UART_TXFIFO_EMPTY_INT_ENA); -} - -void ICACHE_FLASH_ATTR uart0_set_baudrate(uart_t* uart, int baud_rate) -{ - uart->baud_rate = baud_rate; - uart_div_modify(0, UART_CLK_FREQ / (uart->baud_rate)); -} - -int ICACHE_FLASH_ATTR uart0_get_baudrate(uart_t* uart) -{ - return uart->baud_rate; -} - -uart_t* ICACHE_FLASH_ATTR uart0_init(int baudrate) -{ - uart_t* uart = (uart_t*) os_malloc(sizeof(uart_t)); - - PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); - PIN_PULLUP_EN(PERIPHS_IO_MUX_U0RXD_U); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD); - - uart0_set_baudrate(uart, baudrate); - WRITE_PERI_REG(UART_CONF0(0), 0x3 << UART_BIT_NUM_S); // 8n1 - - uart0_flush(uart); - uart0_interrupt_enable(uart); - - WRITE_PERI_REG(UART_CONF1(0), ((0x01 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | - ((0x20 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S)); - - return uart; -} - -void ICACHE_FLASH_ATTR uart0_uninit(uart_t* uart) -{ - uart0_interrupt_disable(uart); - // TODO: revert pin functions - os_free(uart); -} - -void ICACHE_FLASH_ATTR uart0_swap(uart_t* uart) -{ - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_UART0_RTS); - //SWAP PIN : U0TXD<==>U0RTS(MTDO, GPIO15) , U0RXD<==>U0CTS(MTCK, GPIO13) - SET_PERI_REG_MASK(0x3ff00028 , BIT2); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_GPIO3); -} - -void ICACHE_FLASH_ATTR -uart_ignore_char(char c) -{ -} - -void ICACHE_FLASH_ATTR -uart_write_char(char c) -{ - if (c == '\n') - WRITE_PERI_REG(UART_FIFO(0), '\r'); - - WRITE_PERI_REG(UART_FIFO(0), c); -} - -bool s_uart_debug_enabled = true; -void ICACHE_FLASH_ATTR uart_set_debug(bool enabled) -{ - s_uart_debug_enabled = enabled; - if (enabled) - { - system_set_os_print(1); - ets_install_putc1((void *)&uart_write_char); - } - else - ets_install_putc1((void *)&uart_ignore_char); -} - -bool ICACHE_FLASH_ATTR uart_get_debug() -{ - return s_uart_debug_enabled; -} - -ICACHE_FLASH_ATTR HardwareSerial::HardwareSerial() : - _uart(0), _rx_buffer(0), _tx_buffer(0) -{ -} - -void ICACHE_FLASH_ATTR HardwareSerial::begin(unsigned long baud, byte config) -{ - _rx_buffer = new cbuf(SERIAL_RX_BUFFER_SIZE); - _tx_buffer = new cbuf(SERIAL_TX_BUFFER_SIZE); - uart_set_debug(false); - _uart = uart0_init(baud); - _written = false; - delay(1); -} - -void ICACHE_FLASH_ATTR HardwareSerial::end() -{ - uart0_uninit(_uart); - delete _rx_buffer; - delete _tx_buffer; - _uart = 0; - _rx_buffer = 0; - _tx_buffer = 0; -} - -void ICACHE_FLASH_ATTR HardwareSerial::swap() -{ - uart0_swap(_uart); - pinMode(1, INPUT); - pinMode(3, INPUT); -} - -void ICACHE_FLASH_ATTR HardwareSerial::setDebugOutput(bool en) -{ - uart_set_debug(en); -} - -int ICACHE_FLASH_ATTR HardwareSerial::available(void) -{ - return static_cast(_rx_buffer->getSize()); -} - -int ICACHE_FLASH_ATTR HardwareSerial::peek(void) -{ - return _rx_buffer->peek(); -} - -int ICACHE_FLASH_ATTR HardwareSerial::read(void) -{ - return _rx_buffer->read(); -} - -int ICACHE_FLASH_ATTR HardwareSerial::availableForWrite(void) -{ - return static_cast(_tx_buffer->room()); -} - -void ICACHE_FLASH_ATTR HardwareSerial::flush() -{ - if (!_written) - return; - - while (_tx_buffer->getSize() || uart0_get_tx_fifo_room() < UART_TX_FIFO_SIZE) - yield(); - - _written = false; -} - -size_t ICACHE_FLASH_ATTR HardwareSerial::write(uint8_t c) -{ - _written = true; - size_t room = uart0_get_tx_fifo_room(); - if (room > 0 && _tx_buffer->empty()) - { - uart0_transmit_char(_uart, c); - if (room < 10) - { - uart0_arm_tx_interrupt(); - } - return 1; - } - - while (_tx_buffer->room() == 0) - { - yield(); - } - - _tx_buffer->write(c); - return 1; -} - -ICACHE_FLASH_ATTR HardwareSerial::operator bool() const -{ - return _uart != 0; -} - -void ICACHE_FLASH_ATTR HardwareSerial::_rx_complete_irq(char c) -{ - _rx_buffer->write(c); -} - -void ICACHE_FLASH_ATTR HardwareSerial::_tx_empty_irq(void) -{ - size_t queued = _tx_buffer->getSize(); - if (!queued) - { - uart0_disarm_tx_interrupt(); - return; - } - - size_t room = uart0_get_tx_fifo_room(); - int n = static_cast((queued < room) ? queued : room); - while (n--) - { - uart0_transmit_char(_uart, _tx_buffer->read()); - } -} - +/* + HardwareSerial.cpp - esp8266 UART support + + 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 + + Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266) + + */ + +#include +#include +#include +#include +#include "Arduino.h" +#include "cbuf.h" + +extern "C" { +#include "osapi.h" +#include "ets_sys.h" +#include "mem.h" +#include "uart_register.h" +#include "user_interface.h" +} + +#include "HardwareSerial.h" + +#define UART_TX_FIFO_SIZE 0x80 + +/** + * 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); + +// #################################################################################################### +// #################################################################################################### +// #################################################################################################### + +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_init(UARTnr_t uart_nr, int baudrate); +void uart_uninit(uart_t* uart); +void uart_swap(uart_t* uart); + +void uart_ignore_char(char c); +void uart0_write_char(char c); +void uart1_write_char(char c); + +void uart_set_debug(UARTnr_t uart_nr); +UARTnr_t uart_get_debug(); + +// #################################################################################################### +// #################################################################################################### +// #################################################################################################### + +void ICACHE_FLASH_ATTR uart_interrupt_handler(uart_t* uart) { + + // -------------- UART 0 -------------- + uint32_t status = READ_PERI_REG(UART_INT_ST(0)); + if(Serial.isRxEnabled()) { + if(status & UART_RXFIFO_FULL_INT_ST) { + while(true) { + int rx_count = (READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT; + if(!rx_count) break; + + while(rx_count--) { + char c = READ_PERI_REG(UART_FIFO(0)) & 0xFF; + Serial._rx_complete_irq(c); + } + } + WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR); + } + } + if(Serial.isTxEnabled()) { + if(status & UART_TXFIFO_EMPTY_INT_ST) { + WRITE_PERI_REG(UART_INT_CLR(0), UART_TXFIFO_EMPTY_INT_CLR); + Serial._tx_empty_irq(); + } + } + + // -------------- UART 1 -------------- + + status = READ_PERI_REG(UART_INT_ST(1)); + if(Serial1.isRxEnabled()) { + if(status & UART_RXFIFO_FULL_INT_ST) { + while(true) { + int rx_count = (READ_PERI_REG(UART_STATUS(1)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT; + if(!rx_count) break; + + while(rx_count--) { + char c = READ_PERI_REG(UART_FIFO(1)) & 0xFF; + Serial1._rx_complete_irq(c); + } + } + WRITE_PERI_REG(UART_INT_CLR(1), UART_RXFIFO_FULL_INT_CLR); + } + } + if(Serial1.isTxEnabled()) { + status = READ_PERI_REG(UART_INT_ST(1)); + if(status & UART_TXFIFO_EMPTY_INT_ST) { + WRITE_PERI_REG(UART_INT_CLR(1), UART_TXFIFO_EMPTY_INT_CLR); + Serial1._tx_empty_irq(); + } + } +} + +// #################################################################################################### + +void ICACHE_FLASH_ATTR uart_wait_for_tx_fifo(uart_t* uart, size_t size_needed) { + if(uart->txEnabled) { + while(true) { + size_t tx_count = (READ_PERI_REG(UART_STATUS(uart->uart_nr)) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT; + if(tx_count <= (UART_TX_FIFO_SIZE - size_needed)) break; + } + } +} + +size_t ICACHE_FLASH_ATTR uart_get_tx_fifo_room(uart_t* uart) { + if(uart->txEnabled) { + return UART_TX_FIFO_SIZE - ((READ_PERI_REG(UART_STATUS(uart->uart_nr)) >> UART_TXFIFO_CNT_S) & UART_TXFIFO_CNT); + } + return 0; +} + +void ICACHE_FLASH_ATTR uart_wait_for_transmit(uart_t* uart) { + if(uart->txEnabled) { + uart_wait_for_tx_fifo(uart, UART_TX_FIFO_SIZE); + } +} + +void ICACHE_FLASH_ATTR uart_transmit_char(uart_t* uart, char c) { + if(uart->txEnabled) { + WRITE_PERI_REG(UART_FIFO(uart->uart_nr), c); + } +} + +void ICACHE_FLASH_ATTR uart_transmit(uart_t* uart, const char* buf, size_t size) { + 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) + WRITE_PERI_REG(UART_FIFO(uart->uart_nr), *buf); + } + } +} + +void ICACHE_FLASH_ATTR uart_flush(uart_t* uart) { + uint32_t tmp = 0x00000000; + + if(uart->rxEnabled) { + tmp |= UART_RXFIFO_RST; + } + + if(uart->txEnabled) { + tmp |= UART_TXFIFO_RST; + } + + SET_PERI_REG_MASK(UART_CONF0(uart->uart_nr), tmp); + CLEAR_PERI_REG_MASK(UART_CONF0(uart->uart_nr), tmp); +} + +void ICACHE_FLASH_ATTR uart_interrupt_enable(uart_t* uart) { + WRITE_PERI_REG(UART_INT_CLR(uart->uart_nr), 0x1ff); + ETS_UART_INTR_ATTACH(&uart_interrupt_handler, uart); // uart parameter is not osed in irq function! + if(uart->rxEnabled) { + SET_PERI_REG_MASK(UART_INT_ENA(uart->uart_nr), UART_RXFIFO_FULL_INT_ENA); + } + ETS_UART_INTR_ENABLE(); +} + +void ICACHE_FLASH_ATTR uart_interrupt_disable(uart_t* uart) { + if(uart->rxEnabled) { + CLEAR_PERI_REG_MASK(UART_INT_ENA(uart->uart_nr), UART_RXFIFO_FULL_INT_ENA); + } + if(uart->txEnabled) { + CLEAR_PERI_REG_MASK(UART_INT_ENA(uart->uart_nr), UART_TXFIFO_EMPTY_INT_ENA); + } + //ETS_UART_INTR_DISABLE(); // never disable irq complete may its needed by the other Serial Interface! +} + +void ICACHE_FLASH_ATTR uart_arm_tx_interrupt(uart_t* uart) { + if(uart->txEnabled) { + SET_PERI_REG_MASK(UART_INT_ENA(uart->uart_nr), UART_TXFIFO_EMPTY_INT_ENA); + } +} + +void ICACHE_FLASH_ATTR uart_disarm_tx_interrupt(uart_t* uart) { + if(uart->txEnabled) { + CLEAR_PERI_REG_MASK(UART_INT_ENA(uart->uart_nr), UART_TXFIFO_EMPTY_INT_ENA); + } +} + +void ICACHE_FLASH_ATTR uart_set_baudrate(uart_t* uart, int baud_rate) { + uart->baud_rate = baud_rate; + uart_div_modify(uart->uart_nr, UART_CLK_FREQ / (uart->baud_rate)); +} + +int ICACHE_FLASH_ATTR uart_get_baudrate(uart_t* uart) { + return uart->baud_rate; +} + +uart_t* ICACHE_FLASH_ATTR uart_init(UARTnr_t uart_nr, int baudrate) { + + uint32_t conf1 = 0x00000000; + uart_t* uart = (uart_t*) os_malloc(sizeof(uart_t)); + uart->uart_nr = uart_nr; + + switch(uart->uart_nr) { + case UART0: + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); + PIN_PULLUP_EN(PERIPHS_IO_MUX_U0RXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD); + uart->rxEnabled = true; + uart->txEnabled = true; + uart->rxPin = 3; + uart->txPin = 1; + break; + case UART1: + PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO2_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + uart->rxEnabled = false; + uart->txEnabled = true; + uart->rxPin = 255; + uart->txPin = 2; + break; + case UART_NO: + default: + // big fail! + break; + } + uart_set_baudrate(uart, baudrate); + WRITE_PERI_REG(UART_CONF0(uart->uart_nr), 0x3 << UART_BIT_NUM_S); // 8n1 + + uart_flush(uart); + uart_interrupt_enable(uart); + + if(uart->rxEnabled) { + conf1 |= ((0x01 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S); + } + + if(uart->txEnabled) { + conf1 |= ((0x20 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S); + } + + WRITE_PERI_REG(UART_CONF1(uart->uart_nr), conf1); + + return uart; +} + +void ICACHE_FLASH_ATTR uart_uninit(uart_t* uart) { + uart_interrupt_disable(uart); + + switch(uart->rxPin) { + case 3: + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0RXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_GPIO3); + break; + case 13: + PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTCK_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13); + break; + } + + switch(uart->rxPin) { + case 1: + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1); + break; + case 2: + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); + break; + case 15: + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO2); + break; + } + + + pinMode(uart->rxPin , INPUT); + pinMode(uart->txPin , INPUT); + + os_free(uart); +} + +void ICACHE_FLASH_ATTR uart_swap(uart_t* uart) { + switch(uart->uart_nr) { + case UART0: + if(uart->txPin == 1 && uart->rxPin == 3) { + + PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTCK_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS); + + PIN_PULLUP_EN(PERIPHS_IO_MUX_MTDO_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_UART0_RTS); + + //SWAP PIN : U0TXD<==>U0RTS(MTDO, GPIO15) , U0RXD<==>U0CTS(MTCK, GPIO13) + SET_PERI_REG_MASK(0x3ff00028, BIT2); + + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_GPIO3); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1); + + + pinMode(uart->rxPin, INPUT); + pinMode(uart->txPin, INPUT); + + uart->rxPin = 13; + uart->txPin = 15; + + } else { + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); + + PIN_PULLUP_EN(PERIPHS_IO_MUX_U0RXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD); + + CLEAR_PERI_REG_MASK(0x3ff00028, BIT2); + + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15); + + + pinMode(uart->rxPin, INPUT); + pinMode(uart->txPin, INPUT); + uart->rxPin = 3; + uart->txPin = 1; + } + + break; + case UART1: + // current no swap possible! see GPIO pins used by UART + break; + default: + break; + } +} + +// #################################################################################################### +// #################################################################################################### +// #################################################################################################### + +void ICACHE_FLASH_ATTR uart_ignore_char(char c) { +} + +void ICACHE_FLASH_ATTR uart0_write_char(char c) { + if(c == '\n') { + WRITE_PERI_REG(UART_FIFO(0), '\r'); + } + WRITE_PERI_REG(UART_FIFO(0), c); +} + +void ICACHE_FLASH_ATTR uart1_write_char(char c) { + if(c == '\n') { + WRITE_PERI_REG(UART_FIFO(1), '\r'); + } + WRITE_PERI_REG(UART_FIFO(1), c); +} + +static UARTnr_t s_uart_debug_nr = UART_NO; +void ICACHE_FLASH_ATTR uart_set_debug(UARTnr_t 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; + } +} + +UARTnr_t ICACHE_FLASH_ATTR uart_get_debug() { + return s_uart_debug_nr; +} + +// #################################################################################################### +// #################################################################################################### +// #################################################################################################### + +ICACHE_FLASH_ATTR HardwareSerial::HardwareSerial(UARTnr_t uart_nr) : + _uart(0), _tx_buffer(0), _rx_buffer(0), _written(false) { + _uart_nr = uart_nr; +} + +void ICACHE_FLASH_ATTR HardwareSerial::begin(unsigned long baud, byte config) { + + // disable debug for this interface + if(uart_get_debug() == _uart_nr) { + uart_set_debug(UART_NO); + } + + _uart = uart_init(_uart_nr, baud); + + if(_uart->rxEnabled) { + _rx_buffer = new cbuf(SERIAL_RX_BUFFER_SIZE); + } + if(_uart->txEnabled) { + _tx_buffer = new cbuf(SERIAL_TX_BUFFER_SIZE); + } + _written = false; + delay(1); +} + +void ICACHE_FLASH_ATTR HardwareSerial::end() { + uart_uninit(_uart); + delete _rx_buffer; + delete _tx_buffer; + _uart = 0; + _rx_buffer = 0; + _tx_buffer = 0; +} + +void ICACHE_FLASH_ATTR HardwareSerial::swap() { + uart_swap(_uart); +} + +void ICACHE_FLASH_ATTR HardwareSerial::setDebugOutput(bool en) { + if(en) { + uart_set_debug(_uart->uart_nr); + } else { + // disable debug for this interface + if(uart_get_debug() == _uart_nr) { + uart_set_debug(UART_NO); + } + } +} + +bool ICACHE_FLASH_ATTR HardwareSerial::isTxEnabled(void) { + if(_uart == 0) return false; + return _uart->txEnabled; +} + +bool ICACHE_FLASH_ATTR HardwareSerial::isRxEnabled(void) { + if(_uart == 0) return false; + return _uart->rxEnabled; +} + +int ICACHE_FLASH_ATTR HardwareSerial::available(void) { + if(_uart->rxEnabled) { + return static_cast(_rx_buffer->getSize()); + } else { + return 0; + } +} + +int ICACHE_FLASH_ATTR HardwareSerial::peek(void) { + if(_uart->rxEnabled) { + return _rx_buffer->peek(); + } else { + return -1; + } +} + +int ICACHE_FLASH_ATTR HardwareSerial::read(void) { + if(_uart->rxEnabled) { + return _rx_buffer->read(); + } else { + return -1; + } +} + +int ICACHE_FLASH_ATTR HardwareSerial::availableForWrite(void) { + if(_uart->txEnabled) { + return static_cast(_tx_buffer->room()); + } else { + return 0; + } +} + +void ICACHE_FLASH_ATTR HardwareSerial::flush() { + if(!_uart->txEnabled) return; + if(!_written) return; + + while(_tx_buffer->getSize() || uart_get_tx_fifo_room(_uart) < UART_TX_FIFO_SIZE) + yield(); + + _written = false; +} + +size_t ICACHE_FLASH_ATTR HardwareSerial::write(uint8_t c) { + if(!_uart->txEnabled) return 0; + _written = true; + size_t room = uart_get_tx_fifo_room(_uart); + if(room > 0 && _tx_buffer->empty()) { + uart_transmit_char(_uart, c); + if(room < 10) { + uart_arm_tx_interrupt(_uart); + } + return 1; + } + + while(_tx_buffer->room() == 0) { + yield(); + } + + _tx_buffer->write(c); + return 1; +} + +ICACHE_FLASH_ATTR HardwareSerial::operator bool() const { + return _uart != 0; +} + +void ICACHE_FLASH_ATTR HardwareSerial::_rx_complete_irq(char c) { + _rx_buffer->write(c); +} + +void ICACHE_FLASH_ATTR HardwareSerial::_tx_empty_irq(void) { + size_t queued = _tx_buffer->getSize(); + if(!queued) { + uart_disarm_tx_interrupt(_uart); + return; + } + + size_t room = uart_get_tx_fifo_room(_uart); + int n = static_cast((queued < room) ? queued : room); + while(n--) { + uart_transmit_char(_uart, _tx_buffer->read()); + } +} diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h index 143dd3061..5cffa261f 100644 --- a/cores/esp8266/HardwareSerial.h +++ b/cores/esp8266/HardwareSerial.h @@ -1,26 +1,27 @@ /* - HardwareSerial.h - Hardware serial library for Wiring - Copyright (c) 2006 Nicholas Zambetti. All right reserved. + HardwareSerial.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. - 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 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. + 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 + 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 - Modified 28 September 2010 by Mark Sproul - Modified 14 August 2012 by Alarus - Modified 3 December 2013 by Matthijs Kooijman - Modified 18 December 2014 by Ivan Grokhotkov (esp8266 platform support) -*/ + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman + Modified 18 December 2014 by Ivan Grokhotkov (esp8266 platform support) + Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266) + */ #ifndef HardwareSerial_h #define HardwareSerial_h @@ -59,44 +60,71 @@ // #define SERIAL_8O2 0x3E class cbuf; -typedef struct uart_ uart_t; -class HardwareSerial : public Stream -{ -public: - HardwareSerial(); +typedef enum { + UART0 = 0, + UART1 = 1, + UART_NO = 0xFF +} UARTnr_t; - void begin(unsigned long baud) { begin(baud, 0); } - void begin(unsigned long, uint8_t); - void end(); - void swap(); //use GPIO13 and GPIO15 as RX and TX - 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; +typedef struct { + UARTnr_t uart_nr; + int baud_rate; + bool rxEnabled; + bool txEnabled; + uint8_t rxPin; + uint8_t txPin; +} uart_t; - void setDebugOutput(bool); +class HardwareSerial: public Stream { + public: + HardwareSerial(UARTnr_t uart_nr); -protected: - friend void uart0_interrupt_handler(uart_t* uart); - void _rx_complete_irq(char c); - void _tx_empty_irq(void); + void begin(unsigned long baud) { + begin(baud, 0); + } + void begin(unsigned long, uint8_t); + void end(); + void swap(); //use GPIO13 and GPIO15 as RX and TX + 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; -protected: - uart_t* _uart; - cbuf* _tx_buffer; - cbuf* _rx_buffer; - bool _written; + void setDebugOutput(bool); + bool isTxEnabled(void); + bool isRxEnabled(void); + + protected: + friend void uart_interrupt_handler(uart_t* uart); + void _rx_complete_irq(char c); + void _tx_empty_irq(void); + + protected: + UARTnr_t _uart_nr; + uart_t* _uart; + cbuf* _tx_buffer; + cbuf* _rx_buffer; + bool _written; }; extern HardwareSerial Serial; +extern HardwareSerial Serial1; #endif From fb286ff1d4903022d6225352202b70a9724891c3 Mon Sep 17 00:00:00 2001 From: Markus Sattler Date: Wed, 1 Apr 2015 22:52:09 +0200 Subject: [PATCH 2/2] fix C&P Fail --- 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 fc6d2c1a4..1a0f87d28 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -323,7 +323,7 @@ void ICACHE_FLASH_ATTR uart_uninit(uart_t* uart) { PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); break; case 15: - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO2); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15); break; }