1

I've been trying to use spi.write() in a Ticker function, but the following error is thrown out onto the serial line:

Code: 324 Module: 255
Error Message: Assertion failed: _id
Location: 0xCE97
File: /extras/mbed-os.lib/rtos/Mutex.cpp+51
Error Value: 0x0
Current Thread: rtx_idle  Id: 0x1000037C Entry: 0xF117 StackSize: 0x200 StackMem: 0x10000408 SP: 0x10007F30
For more info, visit: https://armmbed.github.io/mbedos-error/?error=0x80FF0144
-- MbedOS Error Info --

I'm now starting to wonder whether mbed's SPI is non-reentrant.

If so, what are my options? Not using Ticker would involve a lot of code being re-written, which I really don't want to do. If I use the internal LPC1768 SPI registers instead of the mbed SPI class, would the problem go away?

Dave Tweed
  • 168,369
  • 17
  • 228
  • 393
19172281
  • 685
  • 1
  • 9
  • 24

2 Answers2

2

Mutexes cannot be acquired in an ISR context, and the SPI write function requires one. An easy way around would be to use an EventQueue to defer the operation to the main thread. Barely any code change required.

Jan Jongboom
  • 336
  • 1
  • 7
0

I'm now starting to wonder whether mbed's SPI is non-reentrant.

Browsing the source code, it definitely is not. spi.write() ends up calling spi_master_write() in the file mbed-os/targets/TARGET_NXP/TARGET_LPC176X/spi_api.c. Nowhere along the way that I can see is there any attempt to serialize accesses to the hardware.

The documentation says that the API is thread-safe, and it appears to be true. In embed-os/drivers/SPI.ccp, the code is essentially

int SPI::write(...)
{
    select();
    int ret = spi_master_[block_]write(...);
    deselect();
    return ret;
}

In order for this to be thread-safe, there would have to be a mutex around the first three statements. The select() function calls lock() as its first statement and the deselect() function calls unlock() as its final statement. But that still doesn't mean that it can be called from both interrupt and non-interrupt code.

To be safe, you'll have to add such protection at the application level. Specifically, disable interrupts when accessing the SPI controller in non-interrupt code.

How many different threads do you have, and how many SPI slaves do have connected?

If I use the internal LPC1768 SPI registers instead of the mbed SPI class, would the problem go away?

No, you'd still need to add protection among the various users of the SPI hardware.

Dave Tweed
  • 168,369
  • 17
  • 228
  • 393