I'm working with an ESP32 using ESP-IDF-4.4. I want to enable interactive remote serial sessions, so I'm implementing my own interrupt handler. The problem I'm running into is that wifi seems to die whenever I send "a lot" of data via the UART and the UART speed is above around 38400 baud.
My interrupt handler looks something like this:
Code: Select all
#if CONFIG_TARGET_UART_IDX == 0
#define TARGET_UART_DEV UART0
#define PERIPH_UART_MODULE PERIPH_UART0_MODULE
#define PERIPH_UART_IRQ ETS_UART0_INTR_SOURCE
#elif CONFIG_TARGET_UART_IDX == 1
#define TARGET_UART_DEV UART1
#define PERIPH_UART_MODULE PERIPH_UART1_MODULE
#define PERIPH_UART_IRQ ETS_UART1_INTR_SOURCE
#elif CONFIG_TARGET_UART_IDX == 2
#define TARGET_UART_DEV UART2
#define PERIPH_UART_MODULE PERIPH_UART2_MODULE
#define PERIPH_UART_IRQ ETS_UART2_INTR_SOURCE
#else
#error "No target UART defined"
#endif
static uart_isr_handle_t console_isr_handle;
static void IRAM_ATTR console_isr(void *param)
{
uint32_t uart_intr_status = uart_ll_get_intsts_mask(&TARGET_UART_DEV);
int bytes_read = 0;
uart_irq_count += 1;
if ((uart_intr_status & UART_INTR_RXFIFO_TOUT) || (uart_intr_status & UART_INTR_RXFIFO_FULL) ||
(uart_intr_status & UART_INTR_CMD_CHAR_DET)) {
while (TARGET_UART_DEV.mem_rx_status.wr_addr != TARGET_UART_DEV.mem_rx_status.rd_addr) {
bytes_read += 1;
char c = (*((volatile uint32_t *)UART_FIFO_REG(CONFIG_TARGET_UART_IDX)));
(void)c;
}
uart_rx_count += bytes_read;
}
uart_ll_clr_intsts_mask(&TARGET_UART_DEV, uart_intr_status);
}
static void setup_uart(void) {
uart_config_t uart_config;
memset(&uart_config, 0, sizeof(uart_config));
uart_config.baud_rate = 460800;
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
ESP_ERROR_CHECK(uart_param_config(CONFIG_TARGET_UART_IDX, &uart_config));
const uart_intr_config_t uart_intr = {
.intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M | UART_FRM_ERR_INT_ENA_M | UART_RXFIFO_OVF_INT_ENA_M
/*|UART_TXFIFO_EMPTY_INT_ENA_M*/,
.rx_timeout_thresh = 9999,
.txfifo_empty_intr_thresh = 1,
.rxfifo_full_thresh = 126,
};
ESP_ERROR_CHECK(uart_intr_config(CONFIG_TARGET_UART_IDX, &uart_intr));
ESP_ERROR_CHECK(esp_intr_alloc(PERIPH_UART_IRQ, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1, console_isr,
&uart_context[CONFIG_TARGET_UART_IDX], &console_isr_handle));
}
I'm testing this connection by sending a copy of Pride & Prejudice, which is about 800 kB.
Almost immediately, the ESP32 stops responding to pings. I can tell from the serial console that it hasn't crashed. When I stop the serual transfer, it recovers after a few seconds.
If I set the serial port speed to around 38400 baud, it behaves much better. 57600 is a speed at which things start to really break down, and at 115200 it drops off wifi as soon as the transfer starts.
How can I track down what's going on here? Is this something odd like a clock-domain crossing issue? Or is there a resource starvation issue? What's causing the ESP32 to fall over after receiving such a small amount of data?