I have a write function that should fire the ISR for the TX_FIFO_EMPTY interrupt. Sadly, this isn't working. From my debugging, I found that the problem is that the ISR is not getting fired when the FIFO is empty or has data in it. Writing to the FIFO register directly did work though and printed a character on the serial port, but it didn't do it using the ISR.
static UART_INPUT uart_input_ = { .UART_NUM = 0, .data = NULL, .length = 0 };
void uart_send(uint8_t UART_NUM, char* data) {
// change the values of data sent
uart_input_.UART_NUM = UART_NUM;
uart_input_.length = strlen(data);
uart_input_.data = data;
// clean the register and trigger the TX FIFO WRITE interrupt
WRITE_REG(UARTS_ENB_INT[UART_NUM], 0);
WRITE_REG(UARTS_ENB_INT[UART_NUM], (1 << 1));
}
The UARTS_ENB_INT is an array of defines of registers:
#define UART0_INTERRUPT_ENABLE (UART0_BASE + 0x0C)
#define UART1_INTERRUPT_ENABLE (UART1_BASE + 0x0C)
#define UART2_INTERRUPT_ENABLE (UART2_BASE + 0x0C)
#define UART0_INTERRUPT_DISABLE (UART0_BASE + 0x10)
#define UART1_INTERRUPT_DISABLE (UART1_BASE + 0x10)
#define UART2_INTERRUPT_DISABLE (UART2_BASE + 0x10)
const uint32_t UARTS_FIFO[] = { UART0_FIFO, UART1_FIFO, UART2_FIFO };
const uint32_t UARTS_DIS_INT[] = { UART0_INTERRUPT_DISABLE, UART1_INTERRUPT_DISABLE, UART2_INTERRUPT_DISABLE };
const uint32_t ETS_UARTS[] = { ETS_UART0_INTR_SOURCE, ETS_UART1_INTR_SOURCE, ETS_UART2_INTR_SOURCE };
const uint32_t UARTS_ENB_INT[] = { UART0_INTERRUPT_ENABLE, UART1_INTERRUPT_ENABLE, UART2_INTERRUPT_ENABLE };
const uint32_t UARTS_INT_ST[] = { UART0_INT_ST, UART1_INT_ST, UART2_INT_ST };
static RingBuffer *ring_buffer;
static uint8_t *buffer = NULL;
The ISR that should be fired checks for what type of interrupt is on (TX Empty or RX Full) and handles it:
void IRAM_ATTR uart_isr(void* arg) {
// For esp32, there's only one interrupt for each UART. We will have both read and write interrupts here
UART_INPUT* uart_input = (UART_INPUT*)arg;
// get uart number from arg
uint8_t UART_NUM = uart_input->UART_NUM;
// read the interrupt status to see if its a write or read
uint32_t status = READ_REG(UARTS_INT_ST[UART_NUM]);
// if RX FIFO FUll interrupt is enabled, continue
if (status & (1 << 0)) {
while (is_data_available_uart(UART_NUM)) {
// read data in the register and clear the reserved bits
uint8_t data = READ_REG(UARTS_FIFO[UART_NUM]) & 0xFF;
// write the data into the ring buffer so we can read it later
write_ring_buffer(ring_buffer, data);
}
}
// if TX FIFO EMPTY interrupt is enabled, continue
if (status & (1 << 1)) {
// get the data from uart_input
char* data = uart_input_.data;
// write user data using UART
// check if the interrupt is enabled
while (uart_input_.length > 0 && (READ_REG(UARTS_ENB_INT[UART_NUM]) & (1 << 1))) {
// go through the data and write it the FIFO register
WRITE_REG(UARTS_FIFO[UART_NUM], *data); // must derefrence the data before sending
uart_input_.length--;
data++;
}
if (uart_input_.length == 0) {
WRITE_REG(UARTS_DIS_INT[UART_NUM], (1 << 1));
}
}
// clear interrupts so they won't retrigger
WRITE_REG(UARTS_DIS_INT[UART_NUM], 1 >> 0);
WRITE_REG(UARTS_DIS_INT[UART_NUM], (1 << 1));
}
The problem is the above ISR doesn't get fired even though I have written to the UART Interrupt Enable register. This is the code that I use to insert the interrupt:
esp_err_t err = esp_intr_alloc(ETS_UARTS[UART_NUM], ESP_INTR_FLAG_IRAM, uart_isr, (void*) &uart_input_, NULL);
There's only one Interrupt Enable Register for the esp32. So I feel I'm doing something wrong here. I would really appreciate any support on how to make the interrupt work for a UART on an esp32.
I have tried writing to the FIFO register or clearing it to see if the ISR does get fired, but it didn't work.
The problem was that I didn't set the FIFO threshold register bits for the RX FULL interrupt. After doing that, the interrupt started to fire, and the interrupt RX Full bit at Raw Interrupt Register was getting set.
This was the needed line:
// UART_RXFIFO_FULL_THRHD 0-6 bits
config_1_uart |= (rx_thershold << 0);