From 7960b633576fb5d64c1ff44324fd000af6b17020 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 25 Jan 2016 11:49:27 +0300 Subject: [PATCH] Move UART HAL into separate file, clean up code --- cores/esp8266/HardwareSerial.cpp | 531 +++++++------------------------ cores/esp8266/HardwareSerial.h | 185 +++++------ cores/esp8266/uart.c | 396 +++++++++++++++++++++++ cores/esp8266/uart.h | 100 ++++++ 4 files changed, 707 insertions(+), 505 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 beb4a498b..3e9b8e539 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); - - -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++); -} - -uint8_t uart_read_char(uart_t* uart){ - if(uart == 0 || !uart->rxEnabled) - return 0; - return USF(uart->uart_nr) & 0xff; -} - -uint8_t uart_rx_available(uart_t* uart){ - if(uart == 0 || !uart->rxEnabled) - return 0; - return (USS(uart->uart_nr) >> USRXC) & 0xff; -} - -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_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) { - 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 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); -} - -int uart_get_baudrate(uart_t* uart) { - if(uart == 0) - return 0; - return uart->baud_rate; -} - -// #################################################################################################### -// #################################################################################################### -// #################################################################################################### - -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); - } 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; - } - 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; - } -} - -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; -} - - -// #################################################################################################### -// #################################################################################################### -// #################################################################################################### HardwareSerial::HardwareSerial(int uart_nr) - : _uart_nr(uart_nr) - , _uart(0) + : _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); -} - -void HardwareSerial::swap(uint8_t 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); -} - -void HardwareSerial::pins(uint8_t tx, uint8_t 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 +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); + uart_set_debug(UART_NO); } - } + + if (_uart) { + free(_uart); + } + + _uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin); } -bool ICACHE_RAM_ATTR HardwareSerial::isTxEnabled(void) { - return _uart != 0 && _uart->txEnabled; +void HardwareSerial::end() +{ + if(uart_get_debug() == _uart_nr) { + uart_set_debug(UART_NO); + } + + uart_uninit(_uart); } -bool ICACHE_RAM_ATTR HardwareSerial::isRxEnabled(void) { - return _uart != 0 && _uart->rxEnabled; +void HardwareSerial::swap(uint8_t tx_pin) +{ + if(!_uart) { + return; + } + uart_swap(_uart, tx_pin); } -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; +void HardwareSerial::set_tx(uint8_t tx_pin) +{ + if(!_uart) { + return; + } + uart_set_tx(_uart, tx_pin); } -int HardwareSerial::peek(void) { - return -1; +void HardwareSerial::pins(uint8_t tx, uint8_t rx) +{ + if(!_uart) { + return; + } + uart_set_pins(_uart, tx, rx); } -int HardwareSerial::read(void) { - if(_uart == 0 || !_uart->rxEnabled) +void HardwareSerial::setDebugOutput(bool en) +{ + if(!_uart) { + return; + } + if(en) { + if(uart_tx_enabled(_uart)) { + uart_set_debug(_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 HardwareSerial::isTxEnabled(void) +{ + return _uart && uart_tx_enabled(_uart); +} + +bool HardwareSerial::isRxEnabled(void) +{ + return _uart && uart_rx_enabled(_uart); +} + +int HardwareSerial::available(void) +{ + if(!_uart || !uart_rx_enabled(_uart)) { + return 0; + } + + int result = static_cast(uart_rx_available(_uart)); + if (!result) { + optimistic_yield(USD(_uart_nr) / 128); + } + return result; +} + +int HardwareSerial::peek(void) +{ return -1; - - return static_cast(uart_read_char(_uart)); } -int HardwareSerial::availableForWrite(void) { - if(_uart == 0 || !_uart->txEnabled) - return 0; +int HardwareSerial::read(void) +{ + if(!_uart || !uart_rx_enabled(_uart)) { + return -1; + } - return static_cast(uart_tx_free(_uart)); + return uart_read_char(_uart); } -void HardwareSerial::flush() { - if(_uart == 0 || !_uart->txEnabled) - return; +int HardwareSerial::availableForWrite(void) +{ + if(!_uart || !uart_tx_enabled(_uart)) { + return 0; + } - uart_wait_tx_empty(_uart); + return static_cast(uart_tx_free(_uart)); } -size_t HardwareSerial::write(uint8_t c) { - if(_uart == 0 || !_uart->txEnabled) - return 0; +void HardwareSerial::flush() +{ + if(!_uart || !uart_tx_enabled(_uart)) { + return; + } - uart_write_char(_uart, c); - return 1; + uart_wait_tx_empty(_uart); } -HardwareSerial::operator bool() const { - return _uart != 0; +size_t HardwareSerial::write(uint8_t c) +{ + if(!_uart || !uart_tx_enabled(_uart)) { + 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 44484aa18..51ce09b2a 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" -#define SERIAL_TX_BUFFER_SIZE 256 -#define SERIAL_RX_BUFFER_SIZE 256 +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, +}; -// 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 +enum SerialMode { + SERIAL_FULL = UART_FULL, + SERIAL_RX_ONLY = UART_RX_ONLY, + SERIAL_TX_ONLY = UART_TX_ONLY +}; -#define SERIAL_FULL 0 -#define SERIAL_RX_ONLY 1 -#define SERIAL_TX_ONLY 2 +class HardwareSerial: public Stream +{ +public: + HardwareSerial(int uart_nr); + virtual ~HardwareSerial() {} -struct uart_; -typedef struct uart_ uart_t; + 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); + } -class HardwareSerial: public Stream { - public: - HardwareSerial(int uart_nr); - virtual ~HardwareSerial(){} + void begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin); - 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 + void end(); - /* - * 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); + 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 - /* - * 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); + /* + * 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); - 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; + /* + * 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); - void setDebugOutput(bool); - bool isTxEnabled(void); - bool isRxEnabled(void); + 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: + void setDebugOutput(bool); + bool isTxEnabled(void); + bool isRxEnabled(void); - protected: - int _uart_nr; - uart_t* _uart; +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 000000000..d7a364008 --- /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 000000000..27b6f56b1 --- /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