2fc1e64319
Pasting more or less sizable text into ESP8266 REPL leads to random chars missing in the received input. Apparent cause is that using RTOS messages to pass individual chars one by one is to slow and leads to UART FIFO overflow. So, instead of passing chars one by one, use RTOS msg to signal that input data is available in FIFO, and then let task handler to read data directly from FIFO. With this change, lost chars problem is gone, but the pasted text is truncated after some position. At least 500 chars can be pasted reliably (at 115200 baud), but 1K never pastes completely.
236 lines
8.1 KiB
C
236 lines
8.1 KiB
C
/******************************************************************************
|
|
* Copyright 2013-2014 Espressif Systems (Wuxi)
|
|
*
|
|
* FileName: uart.c
|
|
*
|
|
* Description: Two UART mode configration and interrupt handler.
|
|
* Check your hardware connection while use this mode.
|
|
*
|
|
* Modification history:
|
|
* 2014/3/12, v1.0 create this file.
|
|
*******************************************************************************/
|
|
#include "ets_sys.h"
|
|
#include "osapi.h"
|
|
#include "uart.h"
|
|
#include "osapi.h"
|
|
#include "uart_register.h"
|
|
#include "etshal.h"
|
|
#include "c_types.h"
|
|
#include "user_interface.h"
|
|
#include "esp_mphal.h"
|
|
|
|
#define RX_BUF_SIZE (256)
|
|
#define UART_REPL UART0
|
|
|
|
// UartDev is defined and initialized in rom code.
|
|
extern UartDevice UartDev;
|
|
|
|
// circular buffer for RX buffering
|
|
static uint16_t rx_buf_in;
|
|
static uint16_t rx_buf_out;
|
|
static uint8_t rx_buf[RX_BUF_SIZE];
|
|
|
|
static os_event_t uart_evt_queue[16];
|
|
|
|
static void uart0_rx_intr_handler(void *para);
|
|
|
|
/******************************************************************************
|
|
* FunctionName : uart_config
|
|
* Description : Internal used function
|
|
* UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
|
|
* UART1 just used for debug output
|
|
* Parameters : uart_no, use UART0 or UART1 defined ahead
|
|
* Returns : NONE
|
|
*******************************************************************************/
|
|
static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) {
|
|
if (uart_no == UART1) {
|
|
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
|
|
} else {
|
|
ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, NULL);
|
|
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
|
|
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
|
|
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
|
|
}
|
|
|
|
uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
|
|
|
|
WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity
|
|
| UartDev.parity
|
|
| (UartDev.stop_bits << UART_STOP_BIT_NUM_S)
|
|
| (UartDev.data_bits << UART_BIT_NUM_S));
|
|
|
|
// clear rx and tx fifo,not ready
|
|
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
|
|
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
|
|
|
|
if (uart_no == UART0) {
|
|
// set rx fifo trigger
|
|
WRITE_PERI_REG(UART_CONF1(uart_no),
|
|
((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
|
|
((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
|
|
UART_RX_FLOW_EN |
|
|
(0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
|
|
UART_RX_TOUT_EN);
|
|
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |
|
|
UART_FRM_ERR_INT_ENA);
|
|
} else {
|
|
WRITE_PERI_REG(UART_CONF1(uart_no),
|
|
((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
|
|
}
|
|
|
|
// clear all interrupt
|
|
WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
|
|
// enable rx_interrupt
|
|
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
|
|
|
|
// init RX buffer
|
|
rx_buf_in = 0;
|
|
rx_buf_out = 0;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : uart1_tx_one_char
|
|
* Description : Internal used function
|
|
* Use uart1 interface to transfer one char
|
|
* Parameters : uint8 TxChar - character to tx
|
|
* Returns : OK
|
|
*******************************************************************************/
|
|
void uart_tx_one_char(uint8 uart, uint8 TxChar) {
|
|
while (true) {
|
|
uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
|
|
if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
|
|
break;
|
|
}
|
|
}
|
|
WRITE_PERI_REG(UART_FIFO(uart), TxChar);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : uart1_write_char
|
|
* Description : Internal used function
|
|
* Do some special deal while tx char is '\r' or '\n'
|
|
* Parameters : char c - character to tx
|
|
* Returns : NONE
|
|
*******************************************************************************/
|
|
static void ICACHE_FLASH_ATTR
|
|
uart_os_write_char(char c) {
|
|
if (c == '\n') {
|
|
uart_tx_one_char(UART_OS, '\r');
|
|
uart_tx_one_char(UART_OS, '\n');
|
|
} else if (c == '\r') {
|
|
} else {
|
|
uart_tx_one_char(UART_OS, c);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : uart0_rx_intr_handler
|
|
* Description : Internal used function
|
|
* UART0 interrupt handler, add self handle code inside
|
|
* Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
|
|
* Returns : NONE
|
|
*******************************************************************************/
|
|
|
|
static void uart0_rx_intr_handler(void *para) {
|
|
/* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
|
|
* uart1 and uart0 respectively
|
|
*/
|
|
|
|
uint8 uart_no = UART_REPL;
|
|
|
|
if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) {
|
|
// frame error
|
|
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
|
|
}
|
|
|
|
if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) {
|
|
// fifo full
|
|
goto read_chars;
|
|
} else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) {
|
|
read_chars:
|
|
#if 1 //MICROPY_REPL_EVENT_DRIVEN is not available here
|
|
ETS_UART_INTR_DISABLE();
|
|
system_os_post(UART_TASK_ID, 0, 0);
|
|
#else
|
|
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
|
|
uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
|
|
uint16_t rx_buf_in_next = (rx_buf_in + 1) % RX_BUF_SIZE;
|
|
if (rx_buf_in_next != rx_buf_out) {
|
|
rx_buf[rx_buf_in] = RcvChar;
|
|
rx_buf_in = rx_buf_in_next;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int uart0_rx(void) {
|
|
if (rx_buf_out != rx_buf_in) {
|
|
int chr = rx_buf[rx_buf_out];
|
|
rx_buf_out = (rx_buf_out + 1) % RX_BUF_SIZE;
|
|
return chr;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int uart_rx_one_char(uint8 uart_no) {
|
|
if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
|
|
return READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : uart_init
|
|
* Description : user interface for init uart
|
|
* Parameters : UartBautRate uart0_br - uart0 bautrate
|
|
* UartBautRate uart1_br - uart1 bautrate
|
|
* Returns : NONE
|
|
*******************************************************************************/
|
|
void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) {
|
|
// rom use 74880 baut_rate, here reinitialize
|
|
UartDev.baut_rate = uart0_br;
|
|
uart_config(UART0);
|
|
UartDev.baut_rate = uart1_br;
|
|
uart_config(UART1);
|
|
ETS_UART_INTR_ENABLE();
|
|
|
|
// install uart1 putc callback
|
|
os_install_putc1((void *)uart_os_write_char);
|
|
}
|
|
|
|
void ICACHE_FLASH_ATTR uart_reattach() {
|
|
uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880);
|
|
}
|
|
|
|
// Task-based UART interface
|
|
|
|
#include "py/obj.h"
|
|
#include "stmhal/pyexec.h"
|
|
|
|
void soft_reset(void);
|
|
|
|
void uart_task_handler(os_event_t *evt) {
|
|
int c, ret = 0;
|
|
while ((c = uart_rx_one_char(UART_REPL)) >= 0) {
|
|
ret = pyexec_event_repl_process_char(c);
|
|
if (ret & PYEXEC_FORCED_EXIT) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Clear pending FIFO interrupts
|
|
WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST);
|
|
// Enable UART interrupts, so our task will receive events again from IRQ handler
|
|
ETS_UART_INTR_ENABLE();
|
|
|
|
if (ret & PYEXEC_FORCED_EXIT) {
|
|
soft_reset();
|
|
}
|
|
}
|
|
|
|
void uart_task_init() {
|
|
system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue));
|
|
}
|