ESP32C3 esp_intr_alloc() on TWAI problems

rjustice
Posts: 16
Joined: Mon Sep 06, 2021 9:12 am

ESP32C3 esp_intr_alloc() on TWAI problems

Postby rjustice » Mon Apr 18, 2022 8:02 pm

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:

Code: Select all

#include "soc/soc.h"
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

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: ESP32C3 esp_intr_alloc() on TWAI problems

Postby ESP_igrr » Mon Apr 18, 2022 9:35 pm

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

rjustice
Posts: 16
Joined: Mon Sep 06, 2021 9:12 am

Re: ESP32C3 esp_intr_alloc() on TWAI problems

Postby rjustice » Tue Apr 19, 2022 9:38 am

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

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: ESP32C3 esp_intr_alloc() on TWAI problems

Postby ESP_igrr » Tue Apr 19, 2022 1:30 pm

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?

rjustice
Posts: 16
Joined: Mon Sep 06, 2021 9:12 am

Re: ESP32C3 esp_intr_alloc() on TWAI problems

Postby rjustice » Tue Apr 19, 2022 2:23 pm

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

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: ESP32C3 esp_intr_alloc() on TWAI problems

Postby ESP_igrr » Wed Apr 20, 2022 6:29 pm

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?

**txf**
Posts: 11
Joined: Thu Apr 21, 2022 3:03 pm

Re: ESP32C3 esp_intr_alloc() on TWAI problems

Postby **txf** » Thu Apr 21, 2022 3:16 pm

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.

ESP_Sprite
Posts: 9709
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32C3 esp_intr_alloc() on TWAI problems

Postby ESP_Sprite » Fri Apr 22, 2022 3:16 am

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.

**txf**
Posts: 11
Joined: Thu Apr 21, 2022 3:03 pm

Re: ESP32C3 esp_intr_alloc() on TWAI problems

Postby **txf** » Fri Apr 22, 2022 8:56 am

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.

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: ESP32C3 esp_intr_alloc() on TWAI problems

Postby ESP_igrr » Fri Apr 22, 2022 9:22 pm

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.

Who is online

Users browsing this forum: No registered users and 309 guests