TWAI ISR with IRAM_ATTR causing errors on ESP32-S3 despite CONFIG_TWAI_ISR_IN_IRAM

badr.bo
Posts: 3
Joined: Sat May 17, 2025 10:37 pm

TWAI ISR with IRAM_ATTR causing errors on ESP32-S3 despite CONFIG_TWAI_ISR_IN_IRAM

Postby badr.bo » Sat May 17, 2025 10:50 pm

Hello ESP community,

I'm trying to achieve ultra-low latency handling of TWAI (CAN bus) messages on an ESP32-S3 by placing the ISR in IRAM. I've followed the documentation on -Placing ISR into IRAM- and enabled CONFIG_TWAI_ISR_IN_IRAM in my project configuration.
https://docs.espressif.com/projects/esp ... /twai.html

Here's my current implementation:

Code: Select all

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "driver/twai.h"
#include "esp_log.h"
#include "esp_timer.h"

#include "esp_attr.h"

#include "esp_private/periph_ctrl.h"
#include "soc/soc.h"
#include "soc/interrupts.h"
#include "esp_intr_types.h"

// CAN Configuration
#define CAN_TX_GPIO_NUM    GPIO_NUM_5
#define CAN_RX_GPIO_NUM    GPIO_NUM_4

#define TWAI_RX_QUEUE_LENGTH 10

static const char *TAG = "CANBUS";

static QueueHandle_t twai_rx_queue = NULL;
static intr_handle_t twai_intr_handle = NULL;

// === IRAM ISR Handler ===
static void IRAM_ATTR twai_isr_handler(void *arg) {

    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    twai_message_t msg;
    while (twai_receive(&msg, 0) == ESP_OK) {
        xQueueSendFromISR(twai_rx_queue, &msg, &xHigherPriorityTaskWoken);
    }

    if (xHigherPriorityTaskWoken) {
        portYIELD_FROM_ISR();
    }
}
// === Task to Process Messages from ISR ===
void twai_receive_task(void *arg) {
    twai_message_t msg;

    while (1) {
        if (xQueueReceive(twai_rx_queue, &msg, portMAX_DELAY) == pdTRUE) {
			
            ESP_LOGI(TAG, "RX ID: 0x%"PRIu32" DLC: %d", msg.identifier, msg.data_length_code);
            for (int i = 0; i < msg.data_length_code; i++) {
                printf("0x%02X ", msg.data[i]);
            }
            printf("\n");
            
        }
    }
}

// === TWAI Init ===
void twai_init(void) {
	
	// Initialize configuration structures using macro initializers
    twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(CAN_TX_GPIO_NUM, CAN_RX_GPIO_NUM, TWAI_MODE_NORMAL);
        
    g_config.controller_id = 0;
    g_config.mode = TWAI_MODE_NORMAL;
    g_config.tx_io = CAN_TX_GPIO_NUM;
    g_config.rx_io = CAN_RX_GPIO_NUM;
    g_config.clkout_io = TWAI_IO_UNUSED;
    g_config.bus_off_io = TWAI_IO_UNUSED;
    g_config.tx_queue_len = 5;
    g_config.rx_queue_len = 5;
    g_config.alerts_enabled = TWAI_ALERT_NONE;
    g_config.clkout_divider = 0;
    g_config.intr_flags = ESP_INTR_FLAG_IRAM;
    
    twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS();
    twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

    // Install TWAI driver
    ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
    ESP_LOGI(TAG, "Driver installed");
    
    // SAFE ONLY IF YOU CONFIRMED ETS_TWAI_INTR_SOURCE EXISTS ON YOUR BUILD
    ESP_ERROR_CHECK(esp_intr_alloc(ETS_TWAI_INTR_SOURCE, ESP_INTR_FLAG_IRAM, twai_isr_handler, NULL, &twai_intr_handle));
    // Start TWAI driver
    esp_err_t ret = twai_start();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to start driver: %s", esp_err_to_name(ret));
        twai_driver_uninstall();
    }
    
}

void app_main() {

	twai_rx_queue = xQueueCreate(TWAI_RX_QUEUE_LENGTH, sizeof(twai_message_t));
    if (!twai_rx_queue) {
        ESP_LOGE(TAG, "Failed to create TWAI RX queue");
        return;
    }
    
	twai_init();
	
	xTaskCreatePinnedToCore(twai_receive_task, "twai_receive_task", 4096, NULL, 10, NULL, 1);
	
    // Keep the task alive
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}
However, I'm continuously getting the following error:
  • E (2531) intr_alloc: No free interrupt inputs for TWAI interrupt (flags 0x40E)
I've verified that:
  • CONFIG_TWAI_ISR_IN_IRAM=y is set in my sdkconfig
  • The ISR handler is properly marked with IRAM_ATTR
  • I'm using ESP-IDF v5.3.3
Any suggestions or insights would be greatly appreciated!

MicroController
Posts: 2663
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: TWAI ISR with IRAM_ATTR causing errors on ESP32-S3 despite CONFIG_TWAI_ISR_IN_IRAM

Postby MicroController » Sun May 18, 2025 11:15 am

The TWAI driver includes the interrupt handler, and twai_driver_install() allocates the TWAI interrupt to the driver's own handler. Trying to esp_intr_alloc() the interrupt a second time, when the handler has already allocated it, won't work.

badr.bo
Posts: 3
Joined: Sat May 17, 2025 10:37 pm

Re: TWAI ISR with IRAM_ATTR causing errors on ESP32-S3 despite CONFIG_TWAI_ISR_IN_IRAM

Postby badr.bo » Sun May 18, 2025 1:24 pm

Thank you for your helpful explanation! I understand that twai_driver_install() already handles the interrupt allocation.

I'd like to ask: Is there a way to assign my own IRAM_ATTR function to be called by the TWAI driver's interrupt handler? For example, can I register a callback or override the default handler in some way without conflicting with the driver's internals?

I appreciate any guidance you can provide!

MicroController
Posts: 2663
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: TWAI ISR with IRAM_ATTR causing errors on ESP32-S3 despite CONFIG_TWAI_ISR_IN_IRAM

Postby MicroController » Mon May 19, 2025 10:12 am

Is there a way to assign my own IRAM_ATTR function to be called by the TWAI driver's interrupt handler?
There doesn't seem to be a way to do this without modifying the driver's code yourself.

Have you confirmed that twai_receive() does not meet your timing requirements?

badr.bo
Posts: 3
Joined: Sat May 17, 2025 10:37 pm

Re: TWAI ISR with IRAM_ATTR causing errors on ESP32-S3 despite CONFIG_TWAI_ISR_IN_IRAM

Postby badr.bo » Mon May 19, 2025 11:48 am

The TWAI driver's interrupt handler is not configured to be in IRAM by default, causing delays compared to an IRAM ISR.
Actiually I modfied the twai_intr_handler_main with IRAM_ATTR and calling twai_receive() from a FreeRTOS task,to reach the expected perfrmance.
Maybe the developper team consider adding IRAM configuration support for the TWAI interrupt handler in future versions, similar to

Code: Select all

#ifdef CONFIG_TWAI_ISR_IN_IRAM
static void IRAM_ATTR twai_intr_handler_main(void *arg) {
#else
static void twai_intr_handler_main(void *arg) {
#endif
This would allow users to optimize ISR latency when needed while maintaining backward compatibility.

Who is online

Users browsing this forum: Applebot, Barkrowler, Bing [Bot] and 6 guests