Page 1 of 1
ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Mon Apr 18, 2022 8:02 pm
by rjustice
For the
ESP32C3 according to the documentation:
https://docs.espressif.com/projects/esp ... alloc.html
...it is possible to allocate an interrupt to the TWAI interface, for example:
Code: Select all
esp_intr_alloc(ETS_CAN_INTR_SOURCE,0,CAN_isr,NULL,NULL);
When I complie the above I get the following error:
error: 'ETS_CAN_INTR_SOURCE' was not declared in this scope
esp_intr_alloc(ETS_CAN_INTR_SOURCE,0,CAN_isr,NULL,NULL);
I have included the following header file:
When I look at this header for the ESP32C3 it does indeed
not contain the above #define for ETS_CAN_INTR_SOURCE, for the ESP32 equivalent header it does. When I look at the "soc/soc.h" header for the ESP32C3 it states at line 271:
Code: Select all
//On RISC-V CPUs, the interrupt sources are all external interrupts, whose type, source and priority are configured by SW.
//There is no HW NMI conception. SW should controlled the masked levels through INT_THRESH_REG.
So how do I add an interrupt to the TWAI interface for the ESP32C3, I would like to have an interrupt for any TWAI messages recieved.
Thankyou
Re: ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Mon Apr 18, 2022 9:35 pm
by ESP_igrr
Could you try ETS_TWAI_INTR_SOURCE instead?
https://github.com/espressif/esp-idf/bl ... defs.h#L71
ETS_CAN_INTR_SOURCE macro is defined for backward compatibility, but only for the ESP32 chip:
https://github.com/espressif/esp-idf/bl ... soc.h#L265
Re: ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Tue Apr 19, 2022 9:38 am
by rjustice
Hi thankyou for that, the code now compiles but
esp_int_alloc returns with
ESP_ERR_NOT_FOUND error.
How do I fix this, does it matter where
esp_int_alloc is called?
Here is the code snippet:
Code: Select all
//Initialize configuration structures using macro initializers
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_4, GPIO_NUM_3, TWAI_MODE_NORMAL);
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS();
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
//Install TWAI driver
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
printf("Driver installed\n");
} else {
printf("Failed to install driver\n");
return;
}
//install CAN ISR
esp_err_t err = esp_intr_alloc(ETS_TWAI_INTR_SOURCE,0,CAN_isr,NULL,NULL);
if(err==ESP_OK){
printf("Interrupt allocated OK\n");
}
else if(err==ESP_ERR_INVALID_ARG) {
printf("Interrupt allocation failed, invalid argument: %i\n", int(err));
}
else if(err==ESP_ERR_NOT_FOUND){
printf("Interrupt allocation failed, no free interrupt found: %i\n", int(err));
}
//Start TWAI driver
if (twai_start() == ESP_OK) {
printf("Driver started\n");
} else {
printf("Failed to start driver\n");
return;
}
void ACAN_ESP32::CAN_isr(void *arg_p){
printf("CAN Intr\n");
}
Thanks
Re: ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Tue Apr 19, 2022 1:30 pm
by ESP_igrr
I'm sorry, i'm a bit confused... I thought that you are writing your own CAN driver but it seems that you are also using the one from IDF.
In the code snippet, you are installing the esp-idf CAN(TWAI) driver which sets up its own interrupt handler. Then you call esp_intr_alloc to set a different interrupt handler. I think this probably won't work because the driver has already installed a handler for the same interrupt.
Perhaps you are looking for some functionality in the driver, and trying to implement it yourself by adding the interrupt handler? If so, could you describe the functionality you are looking for?
Re: ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Tue Apr 19, 2022 2:23 pm
by rjustice
Yes, I'd like to use the one from IDF frame work ideally, in the IDF driver I'm not sure how an interrupt is raised on recieving a CAN message, how this interrupt can be handled and how to allocate a method to calback when a CAN message is recieved, I don't want to use freeRTOS ideally...
Hopefully that makes sense.
Thankyou
Re: ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Wed Apr 20, 2022 6:29 pm
by ESP_igrr
ESP-IDF driver provides three main functions which you can call from your app: twai_receive, twai_transmit and twai_read_alerts. When you call twai_receive or twai_read_alerts, the execution of the task is suspended until a message or an alert becomes available. Once the message or an alert arrives, the execution of the task is resumed. Please take a look at the examples in this section of the docs:
https://docs.espressif.com/projects/esp ... -reception
This mechanism does indeed use FreeRTOS primitives internally, as most other esp-idf drivers do. I think it's not possible to use this driver along with the custom interrupt handler, since the driver expects its own interrupt handler to be installed and functioning.
You have mentioned that you would prefer to not use FreeRTOS. Do you see some limitations or issues I'm doing so?
Re: ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Thu Apr 21, 2022 3:16 pm
by **txf**
ESP_igrr wrote: ↑Tue Apr 19, 2022 1:30 pm
If so, could you describe the functionality you are looking for?
I can describe the behaviour, I'm looking for. I'm looking to replicate the structure of this
https://github.com/miwagner/ESP32-Arduino-CAN .
Ideally, I'd like to have only one thread running to process RX. But be able to to have an interrupt handler so I can detect alerts like
TWAI_ALERT_TX_IDLE or TWAI_ALERT_TX_SUCCESS. That way I could send TWAI messages from any thread, but protect transmissions with a semaphore, that would would be released in the interrupt handler with something like this:
Code: Select all
xSemaphoreGiveFromISR(sem_tx_complete, &higherPriorityTaskWoken);
Additionally I could also have the RX thread be woken up immediately upon receiving a message, without having to wait for its turn.
Re: ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Fri Apr 22, 2022 3:16 am
by ESP_Sprite
From what I can tell, you can do that by having a Rx thread that calls twai_receive. FreeRTOS (in ESP-IDF) is pre-emptive multitasking, so there's no 'waiting for its turn', given the priority of the Rx thread is higher than what's currently running, the OS will switch to it as soon as an interrupt is received.
Re: ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Fri Apr 22, 2022 8:56 am
by **txf**
I've implemented this. Unfortunately if I want alerts to be updated in the same thread I have to do something like this:
Code: Select all
void ThreadMain(){
twai_reconfigure_alerts(TWAI_ALERT_ABOVE_ERR_WARN | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_OFF, NULL);
for(;;) {
processAlerts();
if(twai_receive(&rx_frame, pdMS_TO_TICKS(2) == ESP_OK)){
ESP_LOGI(CAN_TAG, "Msg received - Data = %d", rx_frame.data[0]);
}
taskYIELD();
}
}
void processAlerts(){
uint32_t alerts;
twai_read_alerts(&alerts, pdMS_TO_TICKS(0));
if (alerts & TWAI_ALERT_ABOVE_ERR_WARN) {
ESP_LOGI(CAN_TAG, "Surpassed Error Warning Limit");
}
if (alerts & TWAI_ALERT_ERR_PASS) {
ESP_LOGI(CAN_TAG, "Entered Error Passive state");
}
if (alerts & TWAI_ALERT_BUS_OFF) {
ESP_LOGI(CAN_TAG, "Bus Off state");
//Prepare to initiate bus recovery, reconfigure alerts to detect bus recovery completion
twai_reconfigure_alerts(TWAI_ALERT_BUS_RECOVERED, NULL);
for (int i = 3; i > 0; i--) {
ESP_LOGW(CAN_TAG, "Initiate bus recovery in %d", i);
vTaskDelay(pdMS_TO_TICKS(1000));
}
twai_initiate_recovery(); //Needs 128 occurrences of bus free signal
ESP_LOGI(CAN_TAG, "Initiate bus recovery");
}
if (alerts & TWAI_ALERT_BUS_RECOVERED) {
//Bus recovery was successful, exit control task to uninstall driver
ESP_LOGI(CAN_TAG, "Bus Recovered");
}
}
This way I only have one thread, but it is never pending or stopped for long, even when there isn't much RX traffic. If I had direct access to the interrupt handler I could specifically choose when to unblock, and I wouldn't need to worry about twai_receive() and twai_read_alerts() blocking each other, if I choose to pend forever on them.
Re: ESP32C3 esp_intr_alloc() on TWAI problems
Posted: Fri Apr 22, 2022 9:22 pm
by ESP_igrr
Thanks for explaining the use case! I think it should be possible to introduce a new driver function to return any event which arrives — either data or alert. This way one could have one thread which would be blocked most of the time.