Author Topic: ESP32 - not possible to use I2C functions in an ISR?  (Read 3112 times)

0 Members and 1 Guest are viewing this topic.

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1476
  • Country: gb
ESP32 - not possible to use I2C functions in an ISR?
« on: October 16, 2021, 04:05:02 pm »
I was playing around with an ESP32 yesterday, writing some code that communicated with an I2C slave device. I'm using the Arduino IDE and environment, as I couldn't be arsed to install all the ESP-IDF Eclipse toolchain. The slave device has an interrupt output signal that I wanted to handle, so I created an ISR (using Arduino framework attachInterrupt), within which I performed an I2C read of a register in the slave device. But whenever the ISR executed, the ESP32 would crash and reset, with "Guru Meditation Error: Core 1 panic’ed (Interrupt wdt timeout on CPU1)".

All the info I could find with a brief search was related to getting that error when you try to use delay, etc. within an ISR. But I'm not doing so here - just calling a sequence of IDF i2c_* functions. The only relation I can see is that i2c_master_cmd_begin takes a timeout value in ticks. Does that behind the scenes use similar mechanisms that don't work in an ISR?

I don't know anything about the inner workings of the ESP32 RTOS (FreeRTOS, right?), so I don't know how ISRs are actually handled or what mechanisms delay/timeout code would use that are incompatible with that, but I am curious.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: ESP32 - not possible to use I2C functions in an ISR?
« Reply #1 on: October 16, 2021, 04:15:56 pm »
ETA:  What follows is probably not a good solution considering an RTOS...

I don't know anything about ESP32 interrupts but usually, when you have responded to an interrupt and entered an ISR, further interrupts are disabled until a Return-From-Interrupt instruction is issued.  This type of thing is often handled by the compiler.  It knows when it is executing interrupt code versus mainline code.  This blocking means the WDT interrupt won't happen and the timer times out before the I2C interrupt is complete.  Some CPUs don't have a Return-From-Interrupt instruction and rely on the programmer deliberately enabling interrupts just before returning from the handler.  Are you re-enabling interrupts?

Depending on the overall architecture of the project in terms of interrupts used and whether there is a priority scheme in place, it is sometimes as easy as just re-enabling interrupts while in the handler knowing that you won't get another pin interrupt (specific to that pin) until you leave the handler.

That's why many ARM devices use the NVIC interrupt controller.  It allows nested interrupts in a priority order and each level can be turned off and on individually.
« Last Edit: October 16, 2021, 04:26:52 pm by rstofer »
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: ESP32 - not possible to use I2C functions in an ISR?
« Reply #2 on: October 16, 2021, 04:26:09 pm »
If you're using an RTOS, you need to rethink doing much of anything in the ISR.  You should post something to an event queue and let the RTOS handle scheduling.

https://esp32.com/viewtopic.php?t=6480
 
The following users thanked this post: I wanted a rude username

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1476
  • Country: gb
Re: ESP32 - not possible to use I2C functions in an ISR?
« Reply #3 on: October 16, 2021, 06:22:00 pm »
I note that the ESP-IDF documentation says the following about i2c_master_cmd_begin:

Quote
The I2C APIs are not thread-safe, if you want to use one I2C port in different tasks, you need to take care of the multi-thread issue.

Does an ISR function count as a separate 'task'?
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: ESP32 - not possible to use I2C functions in an ISR?
« Reply #4 on: October 16, 2021, 07:54:55 pm »
I wouldn't think so, you don't start up an ISR the way you do a task.  That's why there are separate '...FromISR()' functions that set queues and semaphores from an unscheduled function (interrupt handler).

Like xSemaphoreGiveFromISR() on page 197

https://freertos.org/fr-content-src/uploads/2018/07/161204_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf

The interrupt happens without notifying the RTOS, it is strictly hardware.  Then when the ISR gets activated, it sets a semaphore which the RTOS scheduler notices (because you called a ..FromISR() function to tell it) and then schedules a task to respond to the interrupt semaphore.  Essentially nothing gets done in the interrupt handler itself.  It simply sets a semaphore or inserts a value into a queue.

Keep the interrupt handler short!
« Last Edit: October 16, 2021, 07:57:38 pm by rstofer »
 
The following users thanked this post: TomS_

Offline PlainName

  • Super Contributor
  • ***
  • Posts: 6838
  • Country: va
Re: ESP32 - not possible to use I2C functions in an ISR?
« Reply #5 on: October 17, 2021, 12:27:32 am »
Quote
Does an ISR function count as a separate 'task'?

Yes - it's how tasks are switched in a RTOS, after all. If the API docs say code isn't re-entrant then you really don't want to call it from an ISR.

Also, I would be quite circumspect about calling library code from an ISR simply because it's not known what it might be doing. Although, actually, you know " that i2c_master_cmd_begin takes a timeout value in ticks" so therefore must sit around waiting in order to have a timeout. Definitely an ISR no-no.

As already mentioned, use the ISR to notify a non-ISR task that the I2C stuff needs handling. It's easy enough to do in FreeRTOS, but I don't know Arduino-speak so can't say how it might look there.
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 3717
  • Country: us
Re: ESP32 - not possible to use I2C functions in an ISR?
« Reply #6 on: October 17, 2021, 02:56:10 am »
Does an ISR function count as a separate 'task'?

Yes, basically.  It's actually more restrictive than that.

At the simplest level a function is not thread safe if, while executing, it leaves global memory in a state where a second call to the function would not behave properly,  It doesn't matter if these are from two threads or a main thread and ISR.

The difference is that generally an ISR should never try to acquire a mutex or take any operation that blocks or waits. The reason is that the main task is not able to continue executing until the ISR completes and returns.  So if you try to acquire a mutex and it is already held you will just block.  Some functions are thread safe due to using a lock to protect shared data: these are not safe to call from an ISR.
 

Online rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf