Implements UART SerialHardware Refactoring on top of IDF (#5549)
## Summary This PR is a complete reffactoring of UART Serial Hardware and respective HAL in order to use IDF instead of current Register manipulation approach. It implements Arduino SerialEvent functionality. Fix #5287 Fix #5273 Fix #5519 Fix #5247 Fix #5403 Fix #5429 Fix #5047 Fix #5463 Fix #5362 Fix #5112 Fix #5443 ## Impact It solves many reported issues related to UART. It was tested and works fine for ESP32, ESP-S2 and ESP32-C3.
This commit is contained in:
parent
929cf2c2d5
commit
b1d072df9f
@ -5,36 +5,73 @@
|
|||||||
|
|
||||||
#include "pins_arduino.h"
|
#include "pins_arduino.h"
|
||||||
#include "HardwareSerial.h"
|
#include "HardwareSerial.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
|
#ifndef SOC_RX0
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
#define SOC_RX0 3
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||||
|
#define SOC_RX0 44
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
#define SOC_RX0 20
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SOC_TX0
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
#define SOC_TX0 1
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||||
|
#define SOC_TX0 43
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
#define SOC_TX0 21
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void serialEvent(void) __attribute__((weak));
|
||||||
|
void serialEvent(void) {}
|
||||||
|
|
||||||
|
#if SOC_UART_NUM > 1
|
||||||
|
|
||||||
#ifndef RX1
|
#ifndef RX1
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
#define RX1 9
|
#define RX1 9
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||||
|
#define RX1 18
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
#define RX1 18
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TX1
|
#ifndef TX1
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
#define TX1 10
|
#define TX1 10
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||||
|
#define TX1 17
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
#define TX1 19
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void serialEvent1(void) __attribute__((weak));
|
||||||
|
void serialEvent1(void) {}
|
||||||
|
#endif /* SOC_UART_NUM > 1 */
|
||||||
|
|
||||||
|
#if SOC_UART_NUM > 2
|
||||||
#ifndef RX2
|
#ifndef RX2
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
#define RX2 16
|
#define RX2 16
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef TX2
|
#ifndef TX2
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
#define TX2 17
|
#define TX2 17
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifndef RX1
|
|
||||||
#define RX1 18
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TX1
|
void serialEvent2(void) __attribute__((weak));
|
||||||
#define TX1 17
|
void serialEvent2(void) {}
|
||||||
#endif
|
#endif /* SOC_UART_NUM > 2 */
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
||||||
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
||||||
@ -42,50 +79,63 @@ HardwareSerial Serial0(0);
|
|||||||
#else
|
#else
|
||||||
HardwareSerial Serial(0);
|
HardwareSerial Serial(0);
|
||||||
#endif
|
#endif
|
||||||
|
#if SOC_UART_NUM > 1
|
||||||
HardwareSerial Serial1(1);
|
HardwareSerial Serial1(1);
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#endif
|
||||||
|
#if SOC_UART_NUM > 2
|
||||||
HardwareSerial Serial2(2);
|
HardwareSerial Serial2(2);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void serialEventRun(void)
|
||||||
|
{
|
||||||
|
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
||||||
|
if(Serial0.available()) serialEvent();
|
||||||
|
#else
|
||||||
|
if(Serial.available()) serialEvent();
|
||||||
|
#endif
|
||||||
|
#if SOC_UART_NUM > 1
|
||||||
|
if(Serial1.available()) serialEvent1();
|
||||||
|
#endif
|
||||||
|
#if SOC_UART_NUM > 2
|
||||||
|
if(Serial2.available()) serialEvent2();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}
|
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}
|
||||||
|
|
||||||
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
|
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
|
||||||
{
|
{
|
||||||
if(0 > _uart_nr || _uart_nr > 2) {
|
if(0 > _uart_nr || _uart_nr >= SOC_UART_NUM) {
|
||||||
log_e("Serial number is invalid, please use 0, 1 or 2");
|
log_e("Serial number is invalid, please use numers from 0 to %u", SOC_UART_NUM - 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(_uart) {
|
if(_uart) {
|
||||||
end();
|
// in this case it is a begin() over a previous begin() - maybe to change baud rate
|
||||||
|
// thus do not disable debug output
|
||||||
|
end(false);
|
||||||
}
|
}
|
||||||
if(_uart_nr == 0 && rxPin < 0 && txPin < 0) {
|
if(_uart_nr == 0 && rxPin < 0 && txPin < 0) {
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
rxPin = SOC_RX0;
|
||||||
rxPin = 3;
|
txPin = SOC_TX0;
|
||||||
txPin = 1;
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
||||||
rxPin = 44;
|
|
||||||
txPin = 43;
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
|
||||||
rxPin = 20;
|
|
||||||
txPin = 21;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#if SOC_UART_NUM > 1
|
||||||
if(_uart_nr == 1 && rxPin < 0 && txPin < 0) {
|
if(_uart_nr == 1 && rxPin < 0 && txPin < 0) {
|
||||||
rxPin = RX1;
|
rxPin = RX1;
|
||||||
txPin = TX1;
|
txPin = TX1;
|
||||||
}
|
}
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#endif
|
||||||
|
#if SOC_UART_NUM > 2
|
||||||
if(_uart_nr == 2 && rxPin < 0 && txPin < 0) {
|
if(_uart_nr == 2 && rxPin < 0 && txPin < 0) {
|
||||||
rxPin = RX2;
|
rxPin = RX2;
|
||||||
txPin = TX2;
|
txPin = TX2;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert, rxfifo_full_thrhd);
|
|
||||||
_tx_pin = txPin;
|
|
||||||
_rx_pin = rxPin;
|
|
||||||
|
|
||||||
if(!baud) {
|
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert, rxfifo_full_thrhd);
|
||||||
|
if (!baud) {
|
||||||
|
// using baud rate as zero, forces it to try to detect the current baud rate in place
|
||||||
uartStartDetectBaudrate(_uart);
|
uartStartDetectBaudrate(_uart);
|
||||||
time_t startMillis = millis();
|
time_t startMillis = millis();
|
||||||
unsigned long detectedBaudRate = 0;
|
unsigned long detectedBaudRate = 0;
|
||||||
@ -93,7 +143,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
|||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
end();
|
end(false);
|
||||||
|
|
||||||
if(detectedBaudRate) {
|
if(detectedBaudRate) {
|
||||||
delay(100); // Give some time...
|
delay(100); // Give some time...
|
||||||
@ -101,8 +151,6 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
|||||||
} else {
|
} else {
|
||||||
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
|
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
|
||||||
_uart = NULL;
|
_uart = NULL;
|
||||||
_tx_pin = 255;
|
|
||||||
_rx_pin = 255;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,21 +160,16 @@ void HardwareSerial::updateBaudRate(unsigned long baud)
|
|||||||
uartSetBaudRate(_uart, baud);
|
uartSetBaudRate(_uart, baud);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HardwareSerial::end()
|
void HardwareSerial::end(bool turnOffDebug)
|
||||||
{
|
{
|
||||||
if(uartGetDebug() == _uart_nr) {
|
if(turnOffDebug && uartGetDebug() == _uart_nr) {
|
||||||
uartSetDebug(0);
|
uartSetDebug(0);
|
||||||
}
|
}
|
||||||
delay(10);
|
delay(10);
|
||||||
log_v("pins %d %d",_tx_pin, _rx_pin);
|
uartEnd(_uart);
|
||||||
uartEnd(_uart, _tx_pin, _rx_pin);
|
|
||||||
_uart = 0;
|
_uart = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HardwareSerial::setRxBufferSize(size_t new_size) {
|
|
||||||
return uartResizeRxBuffer(_uart, new_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HardwareSerial::setDebugOutput(bool en)
|
void HardwareSerial::setDebugOutput(bool en)
|
||||||
{
|
{
|
||||||
if(_uart == 0) {
|
if(_uart == 0) {
|
||||||
@ -212,10 +255,16 @@ uint32_t HardwareSerial::baudRate()
|
|||||||
}
|
}
|
||||||
HardwareSerial::operator bool() const
|
HardwareSerial::operator bool() const
|
||||||
{
|
{
|
||||||
return true;
|
return uartIsDriverInstalled(_uart);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HardwareSerial::setRxInvert(bool invert)
|
void HardwareSerial::setRxInvert(bool invert)
|
||||||
{
|
{
|
||||||
uartSetRxInvert(_uart, invert);
|
uartSetRxInvert(_uart, invert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HardwareSerial::setPins(uint8_t rxPin, uint8_t txPin)
|
||||||
|
{
|
||||||
|
uartSetPins(_uart, rxPin, txPin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
|
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
#include "esp32-hal.h"
|
#include "esp32-hal.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
class HardwareSerial: public Stream
|
class HardwareSerial: public Stream
|
||||||
{
|
{
|
||||||
@ -56,7 +57,7 @@ public:
|
|||||||
HardwareSerial(int uart_nr);
|
HardwareSerial(int uart_nr);
|
||||||
|
|
||||||
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112);
|
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112);
|
||||||
void end();
|
void end(bool turnOffDebug = true);
|
||||||
void updateBaudRate(unsigned long baud);
|
void updateBaudRate(unsigned long baud);
|
||||||
int available(void);
|
int available(void);
|
||||||
int availableForWrite(void);
|
int availableForWrite(void);
|
||||||
@ -98,16 +99,14 @@ public:
|
|||||||
uint32_t baudRate();
|
uint32_t baudRate();
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
|
|
||||||
size_t setRxBufferSize(size_t);
|
|
||||||
void setDebugOutput(bool);
|
void setDebugOutput(bool);
|
||||||
|
|
||||||
void setRxInvert(bool);
|
void setRxInvert(bool);
|
||||||
|
void setPins(uint8_t rxPin, uint8_t txPin);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int _uart_nr;
|
int _uart_nr;
|
||||||
uart_t* _uart;
|
uart_t* _uart;
|
||||||
uint8_t _tx_pin;
|
|
||||||
uint8_t _rx_pin;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void serialEventRun(void) __attribute__((weak));
|
extern void serialEventRun(void) __attribute__((weak));
|
||||||
@ -123,8 +122,10 @@ extern HardwareSerial Serial0;
|
|||||||
#else
|
#else
|
||||||
extern HardwareSerial Serial;
|
extern HardwareSerial Serial;
|
||||||
#endif
|
#endif
|
||||||
|
#if SOC_UART_NUM > 1
|
||||||
extern HardwareSerial Serial1;
|
extern HardwareSerial Serial1;
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#endif
|
||||||
|
#if SOC_UART_NUM > 2
|
||||||
extern HardwareSerial Serial2;
|
extern HardwareSerial Serial2;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,207 +14,88 @@
|
|||||||
|
|
||||||
#include "esp32-hal-uart.h"
|
#include "esp32-hal-uart.h"
|
||||||
#include "esp32-hal.h"
|
#include "esp32-hal.h"
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "soc/uart_reg.h"
|
#include "driver/uart.h"
|
||||||
#include "soc/uart_struct.h"
|
|
||||||
#include "soc/io_mux_reg.h"
|
|
||||||
#include "soc/gpio_sig_map.h"
|
|
||||||
#include "soc/rtc.h"
|
|
||||||
#include "hal/uart_ll.h"
|
#include "hal/uart_ll.h"
|
||||||
#include "esp_intr_alloc.h"
|
#include "soc/soc_caps.h"
|
||||||
|
#include "soc/uart_struct.h"
|
||||||
#include "esp_system.h"
|
|
||||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
|
||||||
#include "soc/dport_reg.h"
|
|
||||||
#include "esp32/rom/ets_sys.h"
|
|
||||||
#include "esp32/rom/uart.h"
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
||||||
#include "soc/dport_reg.h"
|
|
||||||
#include "esp32s2/rom/ets_sys.h"
|
|
||||||
#include "esp32s2/rom/uart.h"
|
|
||||||
#include "soc/periph_defs.h"
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
|
||||||
#include "esp32c3/rom/ets_sys.h"
|
|
||||||
#include "esp32c3/rom/uart.h"
|
|
||||||
#include "soc/periph_defs.h"
|
|
||||||
#else
|
|
||||||
#error Target CONFIG_IDF_TARGET is not supported
|
|
||||||
#endif
|
|
||||||
#else // ESP32 Before IDF 4.0
|
|
||||||
#include "rom/ets_sys.h"
|
|
||||||
#include "rom/uart.h"
|
|
||||||
#include "esp_intr.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
#define UART_PORTS_NUM 3
|
|
||||||
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:( (u==2)?DR_REG_UART2_BASE:0)))
|
|
||||||
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:( (u==2)?U2RXD_IN_IDX:0)))
|
|
||||||
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:( (u==2)?U2TXD_OUT_IDX:0)))
|
|
||||||
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:((u==2)?ETS_UART2_INTR_SOURCE:0)))
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
||||||
#define UART_PORTS_NUM 2
|
|
||||||
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:0))
|
|
||||||
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:0))
|
|
||||||
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:0))
|
|
||||||
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:0))
|
|
||||||
#else
|
|
||||||
#define UART_PORTS_NUM 2
|
|
||||||
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:0))
|
|
||||||
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:0))
|
|
||||||
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:0))
|
|
||||||
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:0))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int s_uart_debug_nr = 0;
|
static int s_uart_debug_nr = 0;
|
||||||
|
|
||||||
struct uart_struct_t {
|
struct uart_struct_t {
|
||||||
uart_dev_t * dev;
|
|
||||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||||
xSemaphoreHandle lock;
|
xSemaphoreHandle lock;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t num;
|
uint8_t num;
|
||||||
xQueueHandle queue;
|
bool has_peek;
|
||||||
intr_handle_t intr_handle;
|
uint8_t peek_byte;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if CONFIG_DISABLE_HAL_LOCKS
|
#if CONFIG_DISABLE_HAL_LOCKS
|
||||||
|
|
||||||
#define UART_MUTEX_LOCK()
|
#define UART_MUTEX_LOCK()
|
||||||
#define UART_MUTEX_UNLOCK()
|
#define UART_MUTEX_UNLOCK()
|
||||||
|
|
||||||
static uart_t _uart_bus_array[] = {
|
static uart_t _uart_bus_array[] = {
|
||||||
{&UART0, 0, NULL, NULL},
|
{0, false, 0},
|
||||||
{&UART1, 1, NULL, NULL},
|
#if SOC_UART_NUM > 1
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
{1, false, 0},
|
||||||
{&UART2, 2, NULL, NULL}
|
#endif
|
||||||
|
#if SOC_UART_NUM > 2
|
||||||
|
{2, false, 0},
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS)
|
#define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS)
|
||||||
#define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock)
|
#define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock)
|
||||||
|
|
||||||
static uart_t _uart_bus_array[] = {
|
static uart_t _uart_bus_array[] = {
|
||||||
{&UART0, NULL, 0, NULL, NULL},
|
{NULL, 0, false, 0},
|
||||||
{&UART1, NULL, 1, NULL, NULL},
|
#if SOC_UART_NUM > 1
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
{NULL, 1, false, 0},
|
||||||
{&UART2, NULL, 2, NULL, NULL}
|
#endif
|
||||||
|
#if SOC_UART_NUM > 2
|
||||||
|
{NULL, 2, false, 0},
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
|
bool uartIsDriverInstalled(uart_t* uart)
|
||||||
|
|
||||||
static void ARDUINO_ISR_ATTR _uart_isr(void *arg)
|
|
||||||
{
|
|
||||||
uint8_t i, c;
|
|
||||||
BaseType_t xHigherPriorityTaskWoken;
|
|
||||||
uart_t* uart;
|
|
||||||
|
|
||||||
for(i=0;i<UART_PORTS_NUM;i++){
|
|
||||||
uart = &_uart_bus_array[i];
|
|
||||||
if(uart->intr_handle == NULL){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uart->dev->int_clr.rxfifo_full = 1;
|
|
||||||
uart->dev->int_clr.frm_err = 1;
|
|
||||||
uart->dev->int_clr.rxfifo_tout = 1;
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
while(uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
|
||||||
c = uart->dev->fifo.rw_byte;
|
|
||||||
#else
|
|
||||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(i);
|
|
||||||
while(uart->dev->status.rxfifo_cnt) {
|
|
||||||
c = ESP_REG(fifo_reg);
|
|
||||||
#endif
|
|
||||||
if(uart->queue != NULL) {
|
|
||||||
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xHigherPriorityTaskWoken) {
|
|
||||||
portYIELD_FROM_ISR();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uartEnableInterrupt(uart_t* uart, uint8_t rxfifo_full_thrhd)
|
|
||||||
{
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
uart->dev->conf1.rxfifo_full_thrhd = rxfifo_full_thrhd;
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
uart->dev->conf1.rx_tout_thrhd = 2;
|
|
||||||
#else
|
|
||||||
uart->dev->mem_conf.rx_tout_thrhd = 2;
|
|
||||||
#endif
|
|
||||||
uart->dev->conf1.rx_tout_en = 1;
|
|
||||||
uart->dev->int_ena.rxfifo_full = 1;
|
|
||||||
uart->dev->int_ena.frm_err = 1;
|
|
||||||
uart->dev->int_ena.rxfifo_tout = 1;
|
|
||||||
uart->dev->int_clr.val = 0xffffffff;
|
|
||||||
|
|
||||||
esp_intr_alloc(UART_INTR_SOURCE(uart->num), (int)ARDUINO_ISR_FLAG, _uart_isr, NULL, &uart->intr_handle);
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uartDisableInterrupt(uart_t* uart)
|
|
||||||
{
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
uart->dev->conf1.val = 0;
|
|
||||||
#endif
|
|
||||||
uart->dev->int_ena.val = 0;
|
|
||||||
uart->dev->int_clr.val = 0xffffffff;
|
|
||||||
|
|
||||||
esp_intr_free(uart->intr_handle);
|
|
||||||
uart->intr_handle = NULL;
|
|
||||||
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uartDetachRx(uart_t* uart, uint8_t rxPin)
|
|
||||||
{
|
{
|
||||||
if(uart == NULL) {
|
if(uart == NULL) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
pinMatrixInDetach(UART_RXD_IDX(uart->num), false, false);
|
|
||||||
uartDisableInterrupt(uart);
|
if (uart_is_driver_installed(uart->num)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uartDetachTx(uart_t* uart, uint8_t txPin)
|
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin)
|
||||||
{
|
{
|
||||||
if(uart == NULL) {
|
if(uart == NULL || rxPin >= SOC_GPIO_PIN_COUNT || txPin >= SOC_GPIO_PIN_COUNT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pinMatrixOutDetach(txPin, false, false);
|
UART_MUTEX_LOCK();
|
||||||
|
ESP_ERROR_CHECK(uart_set_pin(uart->num, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||||
|
UART_MUTEX_UNLOCK();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted, uint8_t rxfifo_full_thrhd)
|
|
||||||
{
|
|
||||||
if(uart == NULL || rxPin >= GPIO_PIN_COUNT) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMode(rxPin, INPUT);
|
|
||||||
uartEnableInterrupt(uart, rxfifo_full_thrhd);
|
|
||||||
pinMatrixInAttach(rxPin, UART_RXD_IDX(uart->num), inverted);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uartAttachTx(uart_t* uart, uint8_t txPin, bool inverted)
|
|
||||||
{
|
|
||||||
if(uart == NULL || txPin >= GPIO_PIN_COUNT) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMode(txPin, OUTPUT);
|
|
||||||
pinMatrixOutAttach(txPin, UART_TXD_IDX(uart->num), inverted, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd)
|
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd)
|
||||||
{
|
{
|
||||||
if(uart_nr >= UART_PORTS_NUM) {
|
if(uart_nr >= SOC_UART_NUM) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,6 +105,10 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
|
|||||||
|
|
||||||
uart_t* uart = &_uart_bus_array[uart_nr];
|
uart_t* uart = &_uart_bus_array[uart_nr];
|
||||||
|
|
||||||
|
if (uart_is_driver_installed(uart_nr)) {
|
||||||
|
uartEnd(uart);
|
||||||
|
}
|
||||||
|
|
||||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||||
if(uart->lock == NULL) {
|
if(uart->lock == NULL) {
|
||||||
uart->lock = xSemaphoreCreateMutex();
|
uart->lock = xSemaphoreCreateMutex();
|
||||||
@ -233,189 +118,143 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(queueLen && uart->queue == NULL) {
|
|
||||||
uart->queue = xQueueCreate(queueLen, sizeof(uint8_t)); //initialize the queue
|
|
||||||
if(uart->queue == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32C3
|
|
||||||
|
|
||||||
#else
|
|
||||||
if(uart_nr == 1){
|
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
|
|
||||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
} else if(uart_nr == 2){
|
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
|
|
||||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
|
|
||||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
uartFlush(uart);
|
|
||||||
uartSetBaudRate(uart, baudrate);
|
|
||||||
UART_MUTEX_LOCK();
|
UART_MUTEX_LOCK();
|
||||||
uart->dev->conf0.val = config;
|
|
||||||
#define TWO_STOP_BITS_CONF 0x3
|
|
||||||
#define ONE_STOP_BITS_CONF 0x1
|
|
||||||
|
|
||||||
if ( uart->dev->conf0.stop_bit_num == TWO_STOP_BITS_CONF) {
|
uart_config_t uart_config;
|
||||||
uart->dev->conf0.stop_bit_num = ONE_STOP_BITS_CONF;
|
uart_config.baud_rate = baudrate;
|
||||||
uart->dev->rs485_conf.dl1_en = 1;
|
uart_config.data_bits = (config & 0xc) >> 2;
|
||||||
|
uart_config.parity = (config & 0x3);
|
||||||
|
uart_config.stop_bits = (config & 0x30) >> 4;
|
||||||
|
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
||||||
|
uart_config.rx_flow_ctrl_thresh = rxfifo_full_thrhd;
|
||||||
|
uart_config.source_clk = UART_SCLK_APB;
|
||||||
|
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(uart_driver_install(uart_nr, 2*queueLen, 0, 0, NULL, 0));
|
||||||
|
ESP_ERROR_CHECK(uart_param_config(uart_nr, &uart_config));
|
||||||
|
ESP_ERROR_CHECK(uart_set_pin(uart_nr, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||||
|
|
||||||
|
// Is it right or the idea is to swap rx and tx pins?
|
||||||
|
if (inverted) {
|
||||||
|
// invert signal for both Rx and Tx
|
||||||
|
ESP_ERROR_CHECK(uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV));
|
||||||
}
|
}
|
||||||
|
|
||||||
// tx_idle_num : idle interval after tx FIFO is empty(unit: the time it takes to send one bit under current baudrate)
|
|
||||||
// Setting it to 0 prevents line idle time/delays when sending messages with small intervals
|
|
||||||
uart->dev->idle_conf.tx_idle_num = 0; //
|
|
||||||
|
|
||||||
UART_MUTEX_UNLOCK();
|
UART_MUTEX_UNLOCK();
|
||||||
|
|
||||||
if(rxPin != -1) {
|
uartFlush(uart);
|
||||||
uartAttachRx(uart, rxPin, inverted, rxfifo_full_thrhd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(txPin != -1) {
|
|
||||||
uartAttachTx(uart, txPin, inverted);
|
|
||||||
}
|
|
||||||
addApbChangeCallback(uart, uart_on_apb_change);
|
|
||||||
return uart;
|
return uart;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uartEnd(uart_t* uart, uint8_t txPin, uint8_t rxPin)
|
void uartEnd(uart_t* uart)
|
||||||
{
|
{
|
||||||
if(uart == NULL) {
|
if(uart == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
removeApbChangeCallback(uart, uart_on_apb_change);
|
|
||||||
|
|
||||||
UART_MUTEX_LOCK();
|
UART_MUTEX_LOCK();
|
||||||
if(uart->queue != NULL) {
|
uart_driver_delete(uart->num);
|
||||||
vQueueDelete(uart->queue);
|
|
||||||
uart->queue = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uart->dev->conf0.val = 0;
|
|
||||||
|
|
||||||
UART_MUTEX_UNLOCK();
|
UART_MUTEX_UNLOCK();
|
||||||
|
|
||||||
uartDetachRx(uart, rxPin);
|
|
||||||
uartDetachTx(uart, txPin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
|
|
||||||
if(uart == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
if(uart->queue != NULL) {
|
|
||||||
vQueueDelete(uart->queue);
|
|
||||||
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
|
|
||||||
if(uart->queue == NULL) {
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
|
|
||||||
return new_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartSetRxInvert(uart_t* uart, bool invert)
|
void uartSetRxInvert(uart_t* uart, bool invert)
|
||||||
{
|
{
|
||||||
if (uart == NULL)
|
if (uart == NULL)
|
||||||
return;
|
return;
|
||||||
|
#if 0
|
||||||
|
// POTENTIAL ISSUE :: original code only set/reset rxd_inv bit
|
||||||
|
// IDF or LL set/reset the whole inv_mask!
|
||||||
if (invert)
|
if (invert)
|
||||||
uart->dev->conf0.rxd_inv = 1;
|
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV));
|
||||||
else
|
else
|
||||||
uart->dev->conf0.rxd_inv = 0;
|
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE));
|
||||||
|
|
||||||
|
#else
|
||||||
|
// this implementation is better over IDF API because it only affects RXD
|
||||||
|
// this is supported in ESP32, ESP32-S2 and ESP32-C3
|
||||||
|
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||||
|
if (invert)
|
||||||
|
hw->conf0.rxd_inv = 1;
|
||||||
|
else
|
||||||
|
hw->conf0.rxd_inv = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t uartAvailable(uart_t* uart)
|
uint32_t uartAvailable(uart_t* uart)
|
||||||
{
|
{
|
||||||
if(uart == NULL || uart->queue == NULL) {
|
|
||||||
|
if(uart == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#ifdef UART_READ_RX_FIFO
|
|
||||||
return (uxQueueMessagesWaiting(uart->queue) + uart->dev->status.rxfifo_cnt) ;
|
UART_MUTEX_LOCK();
|
||||||
#else
|
size_t available;
|
||||||
return uxQueueMessagesWaiting(uart->queue);
|
uart_get_buffered_data_len(uart->num, &available);
|
||||||
#endif
|
if (uart->has_peek) available++;
|
||||||
|
UART_MUTEX_UNLOCK();
|
||||||
|
return available;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t uartAvailableForWrite(uart_t* uart)
|
uint32_t uartAvailableForWrite(uart_t* uart)
|
||||||
{
|
{
|
||||||
if(uart == NULL) {
|
if(uart == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 0x7f - uart->dev->status.txfifo_cnt;
|
UART_MUTEX_LOCK();
|
||||||
|
uint32_t available = uart_ll_get_txfifo_len(UART_LL_GET_HW(uart->num));
|
||||||
|
UART_MUTEX_UNLOCK();
|
||||||
|
return available;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UART_READ_RX_FIFO
|
|
||||||
void uartRxFifoToQueue(uart_t* uart)
|
|
||||||
{
|
|
||||||
uint8_t c;
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
//disable interrupts
|
|
||||||
uart->dev->int_ena.val = 0;
|
|
||||||
uart->dev->int_clr.val = 0xffffffff;
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
while (uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
|
||||||
c = uart->dev->fifo.rw_byte;
|
|
||||||
#else
|
|
||||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
|
|
||||||
while (uart->dev->status.rxfifo_cnt) {
|
|
||||||
c = ESP_REG(fifo_reg);
|
|
||||||
#endif
|
|
||||||
xQueueSend(uart->queue, &c, 0);
|
|
||||||
}
|
|
||||||
//enable interrupts
|
|
||||||
uart->dev->int_ena.rxfifo_full = 1;
|
|
||||||
uart->dev->int_ena.frm_err = 1;
|
|
||||||
uart->dev->int_ena.rxfifo_tout = 1;
|
|
||||||
uart->dev->int_clr.val = 0xffffffff;
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t uartRead(uart_t* uart)
|
uint8_t uartRead(uart_t* uart)
|
||||||
{
|
{
|
||||||
if(uart == NULL || uart->queue == NULL) {
|
if(uart == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint8_t c;
|
uint8_t c = 0;
|
||||||
#ifdef UART_READ_RX_FIFO
|
|
||||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
UART_MUTEX_LOCK();
|
||||||
{
|
|
||||||
uartRxFifoToQueue(uart);
|
if (uart->has_peek) {
|
||||||
|
uart->has_peek = false;
|
||||||
|
c = uart->peek_byte;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
|
||||||
|
if (len == 0) {
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
UART_MUTEX_UNLOCK();
|
||||||
if(xQueueReceive(uart->queue, &c, 0)) {
|
return c;
|
||||||
return c;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t uartPeek(uart_t* uart)
|
uint8_t uartPeek(uart_t* uart)
|
||||||
{
|
{
|
||||||
if(uart == NULL || uart->queue == NULL) {
|
if(uart == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint8_t c;
|
uint8_t c = 0;
|
||||||
#ifdef UART_READ_RX_FIFO
|
|
||||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
UART_MUTEX_LOCK();
|
||||||
{
|
|
||||||
uartRxFifoToQueue(uart);
|
if (uart->has_peek) {
|
||||||
|
c = uart->peek_byte;
|
||||||
|
} else {
|
||||||
|
int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
|
||||||
|
if (len == 0) {
|
||||||
|
c = 0;
|
||||||
|
} else {
|
||||||
|
uart->has_peek = true;
|
||||||
|
uart->peek_byte = c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
UART_MUTEX_UNLOCK();
|
||||||
if(xQueuePeek(uart->queue, &c, 0)) {
|
return c;
|
||||||
return c;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void uartWrite(uart_t* uart, uint8_t c)
|
void uartWrite(uart_t* uart, uint8_t c)
|
||||||
@ -424,12 +263,7 @@ void uartWrite(uart_t* uart, uint8_t c)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UART_MUTEX_LOCK();
|
UART_MUTEX_LOCK();
|
||||||
while(uart->dev->status.txfifo_cnt >= 0x7E);
|
uart_write_bytes(uart->num, &c, 1);
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
uart->dev->fifo.rw_byte = c;
|
|
||||||
#else
|
|
||||||
ESP_REG(UART_FIFO_AHB_REG(uart->num)) = c;
|
|
||||||
#endif
|
|
||||||
UART_MUTEX_UNLOCK();
|
UART_MUTEX_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,25 +272,15 @@ void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
|
|||||||
if(uart == NULL) {
|
if(uart == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UART_MUTEX_LOCK();
|
UART_MUTEX_LOCK();
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
uart_write_bytes(uart->num, data, len);
|
||||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
|
|
||||||
#endif
|
|
||||||
while(len) {
|
|
||||||
while(uart->dev->status.txfifo_cnt >= 0x7E);
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
uart->dev->fifo.rw_byte = *data++;
|
|
||||||
#else
|
|
||||||
ESP_REG(fifo_reg) = *data++;
|
|
||||||
#endif
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
UART_MUTEX_UNLOCK();
|
UART_MUTEX_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void uartFlush(uart_t* uart)
|
void uartFlush(uart_t* uart)
|
||||||
{
|
{
|
||||||
uartFlushTxOnly(uart,true);
|
uartFlushTxOnly(uart, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uartFlushTxOnly(uart_t* uart, bool txOnly)
|
void uartFlushTxOnly(uart_t* uart, bool txOnly)
|
||||||
@ -464,28 +288,13 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly)
|
|||||||
if(uart == NULL) {
|
if(uart == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UART_MUTEX_LOCK();
|
UART_MUTEX_LOCK();
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
ESP_ERROR_CHECK(uart_wait_tx_done(uart->num, portMAX_DELAY));
|
||||||
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
|
|
||||||
|
|
||||||
if( !txOnly ){
|
|
||||||
//Due to hardware issue, we can not use fifo_rst to reset uart fifo.
|
|
||||||
//See description about UART_TXFIFO_RST and UART_RXFIFO_RST in <<esp32_technical_reference_manual>> v2.6 or later.
|
|
||||||
|
|
||||||
// we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`.
|
if ( !txOnly ) {
|
||||||
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
ESP_ERROR_CHECK(uart_flush_input(uart->num));
|
||||||
READ_PERI_REG(UART_FIFO_REG(uart->num));
|
|
||||||
}
|
|
||||||
|
|
||||||
xQueueReset(uart->queue);
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
while(uart->dev->status.txfifo_cnt);
|
|
||||||
uart->dev->conf0.txfifo_rst = 1;
|
|
||||||
uart->dev->conf0.txfifo_rst = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UART_MUTEX_UNLOCK();
|
UART_MUTEX_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,100 +304,41 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UART_MUTEX_LOCK();
|
UART_MUTEX_LOCK();
|
||||||
uart_ll_set_baudrate(uart->dev, baud_rate);
|
uart_ll_set_baudrate(UART_LL_GET_HW(uart->num), baud_rate);
|
||||||
UART_MUTEX_UNLOCK();
|
UART_MUTEX_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
|
|
||||||
{
|
|
||||||
uart_t* uart = (uart_t*)arg;
|
|
||||||
if(ev_type == APB_BEFORE_CHANGE){
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
//disabple interrupt
|
|
||||||
uart->dev->int_ena.val = 0;
|
|
||||||
uart->dev->int_clr.val = 0xffffffff;
|
|
||||||
// read RX fifo
|
|
||||||
uint8_t c;
|
|
||||||
// BaseType_t xHigherPriorityTaskWoken;
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
|
||||||
c = uart->dev->fifo.rw_byte;
|
|
||||||
#else
|
|
||||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
|
|
||||||
while(uart->dev->status.rxfifo_cnt != 0) {
|
|
||||||
c = ESP_REG(fifo_reg);
|
|
||||||
#endif
|
|
||||||
if(uart->queue != NULL ) {
|
|
||||||
xQueueSend(uart->queue, &c, 1); //&xHigherPriorityTaskWoken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
|
|
||||||
// wait TX empty
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
|
|
||||||
#else
|
|
||||||
while(uart->dev->status.txfifo_cnt);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
//todo:
|
|
||||||
// set baudrate
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
|
|
||||||
uint32_t baud_rate = ((old_apb<<4)/clk_div);
|
|
||||||
clk_div = ((new_apb<<4)/baud_rate);
|
|
||||||
uart->dev->clk_div.div_int = clk_div>>4 ;
|
|
||||||
uart->dev->clk_div.div_frag = clk_div & 0xf;
|
|
||||||
//enable interrupts
|
|
||||||
uart->dev->int_ena.rxfifo_full = 1;
|
|
||||||
uart->dev->int_ena.frm_err = 1;
|
|
||||||
uart->dev->int_ena.rxfifo_tout = 1;
|
|
||||||
uart->dev->int_clr.val = 0xffffffff;
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t uartGetBaudRate(uart_t* uart)
|
uint32_t uartGetBaudRate(uart_t* uart)
|
||||||
{
|
{
|
||||||
if(uart == NULL) {
|
if(uart == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
|
UART_MUTEX_LOCK();
|
||||||
if(!clk_div) {
|
uint32_t baud_rate = uart_ll_get_baudrate(UART_LL_GET_HW(uart->num));
|
||||||
return 0;
|
UART_MUTEX_UNLOCK();
|
||||||
}
|
return baud_rate;
|
||||||
|
|
||||||
return ((getApbFrequency()<<4)/clk_div);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ARDUINO_ISR_ATTR uart0_write_char(char c)
|
static void ARDUINO_ISR_ATTR uart0_write_char(char c)
|
||||||
{
|
{
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
while (uart_ll_get_txfifo_len(&UART0) == 0);
|
||||||
while(((ESP_REG(0x01C+DR_REG_UART_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) >= 0x7E);
|
uart_ll_write_txfifo(&UART0, (const uint8_t *) &c, 1);
|
||||||
ESP_REG(DR_REG_UART_BASE) = c;
|
|
||||||
#else
|
|
||||||
while(UART0.status.txfifo_cnt == 0x7F);
|
|
||||||
WRITE_PERI_REG(UART_FIFO_AHB_REG(0), c);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SOC_UART_NUM > 1
|
||||||
static void ARDUINO_ISR_ATTR uart1_write_char(char c)
|
static void ARDUINO_ISR_ATTR uart1_write_char(char c)
|
||||||
{
|
{
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
while (uart_ll_get_txfifo_len(&UART1) == 0);
|
||||||
while(((ESP_REG(0x01C+DR_REG_UART1_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) >= 0x7E);
|
uart_ll_write_txfifo(&UART1, (const uint8_t *) &c, 1);
|
||||||
ESP_REG(DR_REG_UART1_BASE) = c;
|
|
||||||
#else
|
|
||||||
while(UART1.status.txfifo_cnt == 0x7F);
|
|
||||||
WRITE_PERI_REG(UART_FIFO_AHB_REG(1), c);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if SOC_UART_NUM > 2
|
||||||
static void ARDUINO_ISR_ATTR uart2_write_char(char c)
|
static void ARDUINO_ISR_ATTR uart2_write_char(char c)
|
||||||
{
|
{
|
||||||
while(((ESP_REG(0x01C+DR_REG_UART2_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) >= 0x7E);
|
while (uart_ll_get_txfifo_len(&UART2) == 0);
|
||||||
ESP_REG(DR_REG_UART2_BASE) = c;
|
uart_ll_write_txfifo(&UART2, (const uint8_t *) &c, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -598,10 +348,12 @@ void uart_install_putc()
|
|||||||
case 0:
|
case 0:
|
||||||
ets_install_putc1((void (*)(char)) &uart0_write_char);
|
ets_install_putc1((void (*)(char)) &uart0_write_char);
|
||||||
break;
|
break;
|
||||||
|
#if SOC_UART_NUM > 1
|
||||||
case 1:
|
case 1:
|
||||||
ets_install_putc1((void (*)(char)) &uart1_write_char);
|
ets_install_putc1((void (*)(char)) &uart1_write_char);
|
||||||
break;
|
break;
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#endif
|
||||||
|
#if SOC_UART_NUM > 2
|
||||||
case 2:
|
case 2:
|
||||||
ets_install_putc1((void (*)(char)) &uart2_write_char);
|
ets_install_putc1((void (*)(char)) &uart2_write_char);
|
||||||
break;
|
break;
|
||||||
@ -614,7 +366,7 @@ void uart_install_putc()
|
|||||||
|
|
||||||
void uartSetDebug(uart_t* uart)
|
void uartSetDebug(uart_t* uart)
|
||||||
{
|
{
|
||||||
if(uart == NULL || uart->num >= UART_PORTS_NUM) {
|
if(uart == NULL || uart->num >= SOC_UART_NUM) {
|
||||||
s_uart_debug_nr = -1;
|
s_uart_debug_nr = -1;
|
||||||
//ets_install_putc1(NULL);
|
//ets_install_putc1(NULL);
|
||||||
//return;
|
//return;
|
||||||
@ -669,6 +421,7 @@ int log_printf(const char *format, ...)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void log_print_buf_line(const uint8_t *b, size_t len, size_t total_len){
|
static void log_print_buf_line(const uint8_t *b, size_t len, size_t total_len){
|
||||||
for(size_t i = 0; i<len; i++){
|
for(size_t i = 0; i<len; i++){
|
||||||
log_printf("%s0x%02x,",i?" ":"", b[i]);
|
log_printf("%s0x%02x,",i?" ":"", b[i]);
|
||||||
@ -705,42 +458,89 @@ void log_print_buf(const uint8_t *b, size_t len){
|
|||||||
*/
|
*/
|
||||||
unsigned long uartBaudrateDetect(uart_t *uart, bool flg)
|
unsigned long uartBaudrateDetect(uart_t *uart, bool flg)
|
||||||
{
|
{
|
||||||
while(uart->dev->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
|
if(uart == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||||
|
|
||||||
|
while(hw->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
|
||||||
if(flg) return 0;
|
if(flg) return 0;
|
||||||
ets_delay_us(1000);
|
ets_delay_us(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
UART_MUTEX_LOCK();
|
UART_MUTEX_LOCK();
|
||||||
unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12;
|
//log_i("lowpulse_min_cnt = %d hightpulse_min_cnt = %d", hw->lowpulse.min_cnt, hw->highpulse.min_cnt);
|
||||||
|
unsigned long ret = ((hw->lowpulse.min_cnt + hw->highpulse.min_cnt) >> 1);
|
||||||
UART_MUTEX_UNLOCK();
|
UART_MUTEX_UNLOCK();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is
|
* To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is
|
||||||
* detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is
|
* detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is
|
||||||
* rounded to the closed real baudrate.
|
* rounded to the closed real baudrate.
|
||||||
|
*
|
||||||
|
* ESP32-C3 reports wrong baud rate detection as shown below:
|
||||||
|
*
|
||||||
|
* This will help in a future recall for the C3.
|
||||||
|
* Baud Sent: Baud Read:
|
||||||
|
* 300 --> 19536
|
||||||
|
* 2400 --> 19536
|
||||||
|
* 4800 --> 19536
|
||||||
|
* 9600 --> 28818
|
||||||
|
* 19200 --> 57678
|
||||||
|
* 38400 --> 115440
|
||||||
|
* 57600 --> 173535
|
||||||
|
* 115200 --> 347826
|
||||||
|
* 230400 --> 701754
|
||||||
|
*
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void uartStartDetectBaudrate(uart_t *uart) {
|
void uartStartDetectBaudrate(uart_t *uart) {
|
||||||
if(!uart) return;
|
if(uart == NULL) {
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
return;
|
||||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
}
|
||||||
uart->dev->auto_baud.en = 0;
|
|
||||||
uart->dev->auto_baud.en = 1;
|
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
|
||||||
|
// ESP32-C3 requires further testing
|
||||||
|
// Baud rate detection returns wrong values
|
||||||
|
|
||||||
|
log_e("ESP32-C3 baud rate detection is not supported.");
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Code bellow for C3 kept for future recall
|
||||||
|
//hw->rx_filt.glitch_filt = 0x08;
|
||||||
|
//hw->rx_filt.glitch_filt_en = 1;
|
||||||
|
//hw->conf0.autobaud_en = 0;
|
||||||
|
//hw->conf0.autobaud_en = 1;
|
||||||
|
|
||||||
|
#else
|
||||||
|
hw->auto_baud.glitch_filt = 0x08;
|
||||||
|
hw->auto_baud.en = 0;
|
||||||
|
hw->auto_baud.en = 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long
|
unsigned long
|
||||||
uartDetectBaudrate(uart_t *uart)
|
uartDetectBaudrate(uart_t *uart)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
if(uart == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 requires further testing - Baud rate detection returns wrong values
|
||||||
|
|
||||||
static bool uartStateDetectingBaudrate = false;
|
static bool uartStateDetectingBaudrate = false;
|
||||||
|
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||||
|
|
||||||
if(!uartStateDetectingBaudrate) {
|
if(!uartStateDetectingBaudrate) {
|
||||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
uartStartDetectBaudrate(uart);
|
||||||
uart->dev->auto_baud.en = 0;
|
|
||||||
uart->dev->auto_baud.en = 1;
|
|
||||||
uartStateDetectingBaudrate = true;
|
uartStateDetectingBaudrate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -748,11 +548,21 @@ uartDetectBaudrate(uart_t *uart)
|
|||||||
if (!divisor) {
|
if (!divisor) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
// log_i(...) below has been used to check C3 baud rate detection results
|
||||||
|
//log_i("Divisor = %d\n", divisor);
|
||||||
|
//log_i("BAUD RATE based on Positive Pulse %d\n", getApbFrequency()/((hw->pospulse.min_cnt + 1)/2));
|
||||||
|
//log_i("BAUD RATE based on Negative Pulse %d\n", getApbFrequency()/((hw->negpulse.min_cnt + 1)/2));
|
||||||
|
|
||||||
uart->dev->auto_baud.en = 0;
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
//hw->conf0.autobaud_en = 0;
|
||||||
|
#else
|
||||||
|
hw->auto_baud.en = 0;
|
||||||
|
#endif
|
||||||
uartStateDetectingBaudrate = false; // Initialize for the next round
|
uartStateDetectingBaudrate = false; // Initialize for the next round
|
||||||
|
|
||||||
unsigned long baudrate = getApbFrequency() / divisor;
|
unsigned long baudrate = getApbFrequency() / divisor;
|
||||||
|
//log_i("APB_FREQ = %d\nraw baudrate detected = %d", getApbFrequency(), baudrate);
|
||||||
|
|
||||||
static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};
|
static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};
|
||||||
|
|
||||||
@ -770,17 +580,7 @@ uartDetectBaudrate(uart_t *uart)
|
|||||||
|
|
||||||
return default_rates[i];
|
return default_rates[i];
|
||||||
#else
|
#else
|
||||||
return 0;
|
log_e("ESP32-C3 baud rate detection is not supported.");
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the status of the RX state machine, if the value is non-zero the state machine is active.
|
|
||||||
*/
|
|
||||||
bool uartRxActive(uart_t* uart) {
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
return uart->dev->status.st_urx_out != 0;
|
|
||||||
#else
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ struct uart_struct_t;
|
|||||||
typedef struct uart_struct_t uart_t;
|
typedef struct uart_struct_t uart_t;
|
||||||
|
|
||||||
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd);
|
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd);
|
||||||
void uartEnd(uart_t* uart, uint8_t rxPin, uint8_t txPin);
|
void uartEnd(uart_t* uart);
|
||||||
|
|
||||||
uint32_t uartAvailable(uart_t* uart);
|
uint32_t uartAvailable(uart_t* uart);
|
||||||
uint32_t uartAvailableForWrite(uart_t* uart);
|
uint32_t uartAvailableForWrite(uart_t* uart);
|
||||||
@ -68,17 +68,17 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly );
|
|||||||
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate);
|
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate);
|
||||||
uint32_t uartGetBaudRate(uart_t* uart);
|
uint32_t uartGetBaudRate(uart_t* uart);
|
||||||
|
|
||||||
size_t uartResizeRxBuffer(uart_t* uart, size_t new_size);
|
|
||||||
|
|
||||||
void uartSetRxInvert(uart_t* uart, bool invert);
|
void uartSetRxInvert(uart_t* uart, bool invert);
|
||||||
|
|
||||||
void uartSetDebug(uart_t* uart);
|
void uartSetDebug(uart_t* uart);
|
||||||
int uartGetDebug();
|
int uartGetDebug();
|
||||||
|
|
||||||
|
bool uartIsDriverInstalled(uart_t* uart);
|
||||||
|
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin);
|
||||||
|
|
||||||
void uartStartDetectBaudrate(uart_t *uart);
|
void uartStartDetectBaudrate(uart_t *uart);
|
||||||
unsigned long uartDetectBaudrate(uart_t *uart);
|
unsigned long uartDetectBaudrate(uart_t *uart);
|
||||||
|
|
||||||
bool uartRxActive(uart_t* uart);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user