Why it is usually a bad idea to use I2C or SPI in an interrupt handler

The peripheral outputs an interrupt signal so it seems perfectly logical to connect it to an interrupt pin and have the interrupt handler read from the device, right...

NO!!!

Two reasons why this is not good practice:

Reason one is that newer MBED libraries will NOT LET YOU.

Recent versions of I2C set locks so that if the RTOS switches tasks mid transfer it won't mix up transfers. The thread that started the transfer gets a lock on the port until the transfer finishes at which point another thread may use it.

Locks cannot be set in an interrupt. I believe it simply fails to lock preventing the transfer.

Reason two on versions of MBED that don't have locks

Interrupt-triggered actions usually work fine for devices attached to the micro's data bus, provided all or most data transfers are "atomic" meaning they can't be interrupted mid transfer.

Some edge cases may require masking the interrupt during a sequence of actions.

So what's the problem with serial data transfer and interrupts...

You can't generally interrupt a transfer. communicate with a different device on the same bus. then resume the original transfer.

You could get around it by selectively masking the interrupt during transfers. This would work, but could seriously break time-critical functions. I2C transfers take typically 100us/byte, and might often be 5 bytes long or more. 500us is a long time to have interrupts masked, it defeats the point of having them.

You could add code to detect if a transfer is in progress, push the state of the interface, deselect the peripheral, carry out the interrupt transfer then restore the state of the interface. This would work with some peripherals that are designed to support split operations.

You could use a RTOS and worker threads. The interrupt would simply send a "message" to a thread and that thread would handle the transfer. If the bus was busy when the interrupt occured the message would be held till the bus became available.

THERE IS AN EVENTS MODULE SPECIFICALLY TO DO THIS. It allows interrupts to push a callback into a queue, and at a safe time the worker thread retrieves and calls the callback.

Alternatively you might just give up and poll the device instead. Since standard rate I2C takes 200us just to read a byte it is unsuitable for time-critical communication so just check the device periodically.

SO WHAT IS THAT INTERRUPT LINE GOOD FOR ANYWAY

Battery life. Say you are designing for minimum current consumption and you want to put the CPU in a deep sleep state. That hardware line can be used as a "wake from sleep" trigger, allowing the program to stop completely when idle.


Please log in to post comments.