-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Environment
- Development Kit: NodeMCU Board with ESP-12E
- IDF version (
git rev-parse --short HEADto get the commit id.):
02ffe0e - Development Env: [Make]
- Operating System: [Ubuntu]
- Power Supply: [USB]
Problem Description
I registered a custom ISR for UART0, but when connecting the RX pin the ESP8266 crashes running in ISR context. I initialized the UART0 with uart_init() and registered the custom ISR.
Actual Behavior
ESP8266 crashes when receaving UART messages.
Code to reproduce this issue
#define portYIELD_FROM_ISR() taskYIELD()
#define UART_ENTER_CRITICAL() portENTER_CRITICAL()
#define UART_EXIT_CRITICAL() portEXIT_CRITICAL()
#define UART_CHECK(a, str, ret_val) \
if (!(a)) { \
ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
static DRAM_ATTR uart_dev_t *const UART[UART_NUM_MAX] = {&uart0, &uart1};
void uart_init(void) {
uart_driver_delete(UART_NUM_0);
uart_config_t uart_config = { .baud_rate = 9600, .data_bits =
UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits =
UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE };
uart_param_config(UART_NUM_0, &uart_config);
uart_driver_install(UART_NUM_0, UART_BUF_SIZE * 2, 0, 0, NULL);
uart_intr_config_t uart_intr = {
.intr_enable_mask = UART_FRM_ERR_INT_ENA_M | UART_PARITY_ERR_INT_ENA_M
| UART_RXFIFO_OVF_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M
| UART_BRK_DET_INT_ENA,
.rxfifo_full_thresh = 1,
.rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT,
.txfifo_empty_intr_thresh = 0
};
uart_intr_config(UART_NUM_0, &uart_intr);
if (uart_isr_register(UART_NUM_0, UARTIntReceviceHandler, 0)
!= ESP_OK) {
ESP_LOGE(TAG, "Failed to register uart isr");
return FAILED;
} else {
ESP_LOGD(TAG, "SUCCEDED to register uart isr");
}
}
static void UARTIntReceviceHandler(void *param) {
uart_obj_t *p_uart = (uart_obj_t *) param;
uint8_t uart_num = p_uart->uart_num;
uart_dev_t *uart_reg = UART[uart_num];
int rx_fifo_len = uart_reg->status.rxfifo_cnt;
uint8_t buf_idx = 0;
uint32_t uart_intr_status = UART[uart_num]->int_st.val;
uart_event_t uart_event;
BaseType_t task_woken = 0;
while (uart_intr_status != 0x0) {
buf_idx = 0;
uart_event.type = UART_EVENT_MAX;
if (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) {
uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M);
uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
// TX semaphore will only be used when tx_buf_size is zero.
if (p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) {
p_uart->tx_waiting_fifo = false;
xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &task_woken);
if (task_woken == pdTRUE) {
portYIELD_FROM_ISR();
}
} else {
// We don't use TX ring buffer, because the size is zero.
if (p_uart->tx_buf_size == 0) {
continue;
}
int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt;
bool en_tx_flg = false;
// We need to put a loop here, in case all the buffer items are very short.
// That would cause a watch_dog reset because empty interrupt happens so often.
// Although this is a loop in ISR, this loop will execute at most 128 turns.
while (tx_fifo_rem) {
if (p_uart->tx_len_tot == 0 || p_uart->tx_ptr == NULL || p_uart->tx_len_cur == 0) {
size_t size;
p_uart->tx_head = (uart_tx_data_t *) xRingbufferReceiveFromISR(p_uart->tx_ring_buf, &size);
if (p_uart->tx_head) {
// The first item is the data description
// Get the first item to get the data information
if (p_uart->tx_len_tot == 0) {
p_uart->tx_ptr = NULL;
p_uart->tx_len_tot = p_uart->tx_head->tx_data.size;
// We have saved the data description from the 1st item, return buffer.
vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &task_woken);
if (task_woken == pdTRUE) {
portYIELD_FROM_ISR();
}
} else if (p_uart->tx_ptr == NULL) {
// Update the TX item pointer, we will need this to return item to buffer.
p_uart->tx_ptr = (uint8_t *) p_uart->tx_head;
en_tx_flg = true;
p_uart->tx_len_cur = size;
}
} else {
// Can not get data from ring buffer, return;
break;
}
}
if (p_uart->tx_len_tot > 0 && p_uart->tx_ptr && p_uart->tx_len_cur > 0) {
// To fill the TX FIFO.
int send_len = p_uart->tx_len_cur > tx_fifo_rem ? tx_fifo_rem : p_uart->tx_len_cur;
for (buf_idx = 0; buf_idx < send_len; buf_idx++) {
UART[uart_num]->fifo.rw_byte = *(p_uart->tx_ptr++) & 0xff;
}
p_uart->tx_len_tot -= send_len;
p_uart->tx_len_cur -= send_len;
tx_fifo_rem -= send_len;
if (p_uart->tx_len_cur == 0) {
// Return item to ring buffer.
vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &task_woken);
if (task_woken == pdTRUE) {
portYIELD_FROM_ISR();
}
p_uart->tx_head = NULL;
p_uart->tx_ptr = NULL;
}
if (p_uart->tx_len_tot == 0) {
en_tx_flg = false;
xSemaphoreGiveFromISR(p_uart->tx_done_sem, &task_woken);
if (task_woken == pdTRUE) {
portYIELD_FROM_ISR();
}
} else {
en_tx_flg = true;
}
}
}
if (en_tx_flg) {
uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M);
uart_enable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
}
}
} else if ((uart_intr_status & UART_RXFIFO_TOUT_INT_ST_M)
|| (uart_intr_status & UART_RXFIFO_FULL_INT_ST_M)
) {
rx_fifo_len = uart_reg->status.rxfifo_cnt;
if (p_uart->rx_buffer_full_flg == false) {
// We have to read out all data in RX FIFO to clear the interrupt signal
while (buf_idx < rx_fifo_len) {
p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte;
}
// Get the buffer from the FIFO
// After Copying the Data From FIFO ,Clear intr_status
uart_clear_intr_status(uart_num, UART_RXFIFO_TOUT_INT_CLR_M | UART_RXFIFO_FULL_INT_CLR_M);
uart_event.type = UART_DATA;
uart_event.size = rx_fifo_len;
p_uart->rx_stash_len = rx_fifo_len;
// If we fail to push data to ring buffer, we will have to stash the data, and send next time.
// Mainly for applications that uses flow control or small ring buffer.
if (pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &task_woken)) {
uart_disable_intr_mask(uart_num, UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M);
uart_event.type = UART_BUFFER_FULL;
p_uart->rx_buffer_full_flg = true;
} else {
p_uart->rx_buffered_len += p_uart->rx_stash_len;
}
if (task_woken == pdTRUE) {
portYIELD_FROM_ISR();
}
} else {
uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M);
uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M);
}
} else if (uart_intr_status & UART_RXFIFO_OVF_INT_ST_M) {
// When fifo overflows, we reset the fifo.
uart_reset_rx_fifo(uart_num);
uart_reg->int_clr.rxfifo_ovf = 1;
uart_event.type = UART_FIFO_OVF;
} else if (uart_intr_status & UART_FRM_ERR_INT_ST_M) {
uart_reg->int_clr.frm_err = 1;
uart_event.type = UART_FRAME_ERR;
} else if (uart_intr_status & UART_PARITY_ERR_INT_ST_M) {
uart_reg->int_clr.parity_err = 1;
uart_event.type = UART_PARITY_ERR;
} else {
uart_reg->int_clr.val = uart_intr_status; // simply clear all other intr status
uart_event.type = UART_EVENT_MAX;
}
if (uart_event.type != UART_EVENT_MAX && p_uart->xQueueUart) {
if (pdFALSE == xQueueSendFromISR(p_uart->xQueueUart, (void *)&uart_event, &task_woken)) {
ESP_EARLY_LOGV(TAG, "UART event queue full");
}
if (task_woken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
uart_intr_status = uart_reg->int_st.val;
}
}
Debug Logs
Core 0 was running in ISR context:
00000000 00000004 00000008 0000000c 00000010 00000014 00000018 0000001c 00000020 00000024 00000028 0000002c 00000030 00000034 00000038 0000003c
3ffe82e0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
3ffe8320 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
3ffe8360 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
3ffe83a0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
3ffe83e0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 40100715 00000000 00000000 00000000 40240ba2 4024b5dd 00000000 00000000 00000000
3ffe8420 00000000 00000000 00000000 40100715 00000004 00000000 40106efc 40240ba2 401066e4 40240540 00000000 40240ba2 4022435c 0000017a 00000000 4023f6ab
3ffe8460 3ffe8498 000000ff 3fff2878 4023efcd 3ffe84a0 000000ff 3fff3770 4010068b 00000400 00000400 3ffe84e8 4022eedd 00000005 00000000 00000001 00000001
3ffe84a0 00000020 00000020 00000000 40258049 40100779 4022ef08 3fff0348 4010078d 3fff1a28 00000002 40222300 00000000 00000000 00000000 4010552c 40105574
PC: 0x4024c53b PS: 0x00000031 A0: 0x40258049 A1: 0x3ffe8470
0x4024c53b: esp_aio_event at /home/may2lol/esp/ESP8266_RTOS_SDK/components/esp8266/source/esp_socket.c:179
A2: 0x00000000 A3: 0x4024c52c A4: 0x00003fff A5: 0x401065e0
0x4024c52c: esp_aio_sendto at /home/may2lol/esp/ESP8266_RTOS_SDK/components/esp8266/source/esp_socket.c:172
A6: 0xfc7000f7 A7: 0x3feffe00 A8: 0xfc70ffff A9: 0x22800000
A10: 0x20000000 A11: 0xcfffffff A12: 0x00000000 A13: 0x00000020
A14: 0x00000020 A15: 0x00000001 SAR: 0x0000001b EXCCAUSE: 0x0000001c