This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Best way to do high frequency writes to SPI - using ticker?

I'm using the mbed platform and have been battling hard faults as I try to find the best way to write with high frequency to SPI to update a series of LEDs while still allowing for intermittent data to come in on BLE to change settings for the LEDs, (color, speed, etc).

After quite a bit of experimentation I’m doing this by setting up a ticker in the main loop of the program which consistently calls the LEDupdate function that sends LED data via SPI. In my BLE onDataWrittenCallback the very first line uses a pointer to my ticker to disable the ticker. Then I parse the data written, put it in the correct spots so that it can change whatever LED settings it needs to change and set a flag that my ticker needs to be turned back on. Once I hit the main BLE wait loop again the ticker is re attached, the ticker flag is set to false since the ticker is now active and my LEDs resume updating.

The issue at first was that if I had my ticker on too short an interval then trying to write to the BLE would hard fault the chip. By making the ticker a longer interval I was able to get things to stabilize, but I would have thought there would be no default since the ticker isnt turned back on until the data has been processed.

  • My question then is whether this is the best approach to writing at high frequency to the SPI?

  • Furthermore, are the hard faults because when I restart my ticker the soft device is not quite done doing what it needs to do behind the scenes after receiving data and so my ticker is bumping into the soft device?

Along those lines I had a relatively stable implementation of this setup working but then I added another characteristic to my service and it caused the chip to lock after receiving data via BLE. After many tests I was able to solve this by making the ticker interval much slower. To me this is strange, the new characteristic is never referenced or written too, just initialized, but still it seems to be slowing down how quickly the soft device finishes its work after getting data and forces me to slow my ticker. Additionally writing one byte to the BLE device or writing a full 20 bytes didn't seem to make any difference to locking the chip up, while simply having the extra characteristic made a big difference.

Here is the simple code I'm using

void onDataWrittenCallback(const GattWriteCallbackParams *params) {

ptrTicker->detach();

if (params->handle == ledServicePtr->getColorHandle()) {
    currentSettings.color[0].r = params->data[0];
    currentSettings.color[0].g = params->data[1];
    currentSettings.color[0].b = params->data[2];
} else if (params->handle == ledServicePtr->getColorRawHandle()) {
    currentSettings.color[0].r = params->data[0];
    currentSettings.color[0].g = params->data[1];
    currentSettings.color[0].b = params->data[2];    
}
OLEDdirty = true; 
TICKERdirty = true;}



Ticker ticker;
ptrTicker = &ticker;     

while (true) {
    if (OLEDdirty) {redrawOled();}
    if (LEDdirty) {
        LEDdirty = false;
        LEDs.update();
        }
    if (TICKERdirty) {    
         TICKERdirty = false;
         ticker.attach_us(LEDupdate, 8000);  //8ms ticker
       }  
    ble.waitForEvent();
}}

A couple weird formatting issues with the code embed but this is the gist of it, I can get it to be stable but when I am right on the edge of too short a ticker interval I'll lock up after a couple writes. I'll report back if I get any traction on the mbed forum or if I discover a solution.

  • @dmf3030: We don't have much experience with mbed so I would suggest you to also create a thread on mbed forum to seek for help.

    It sounds strange to me that a short interval tiker ( I assume you were using a timer to do the tick) would cause a hardfault.

    What if you try:

    • don't do any thing SPI related in the ticker handler, but just a simple delay in the ticker handler?

    • don't do anything in onDataWrittenCallback()

    What was your short ticker interval and what was the long one ? Also what was your connection interval ?

  • Sorry I understand the mbed API is its own world, I have posted this to the mbed forum but I've found the nordic forum to be much more responsive and I've found good info here so I decided to give it a shot. I will add the actual code I'm using to the main question for clarity and I will also try your two suggestions of just doing a delay instead of SPI and of doing nothing in the onDataWritten function.

    I guess the primary question still persists, is this the correct way to approach writing to the SPI repeatedly at a relatively short interval, (8-10ms at the shortest)?

  • Forgot to answer your final question, my connection interval is the default setup for mbed

     static const unsigned GAP_ADV_PARAMS_INTERVAL_MIN        = 0x0020; // 40ms
    static const unsigned GAP_ADV_PARAMS_INTERVAL_MIN_NONCON = 0x00A0; // 200ms
    static const unsigned GAP_ADV_PARAMS_INTERVAL_MAX        = 0x4000; // 20480ms
    static const unsigned GAP_ADV_PARAMS_TIMEOUT_MAX         = 0x3FFF; // 163830ms
    
  • @dmf3030: How long did it take in your ticker call back (LEDupdate) ? If it's a long process, you may consider doing it in the main loop. The ticker call back only set a flag.

    Have you tried to remove the SPI code in the call back and check if hardfault still occurs ?

  • The actual LEDupdate function that the ticker is pointing to is very quick, just moving some data around in an array. The SPI write where I actually push that data to a strip of LEDs happens in the LEDs.update(); call which is in the main loop. Basically the ticker updates the LED data then sets a flag so that the next time you hit the main loop the function to push that data to the SPI is called.

    I haven't had a chance to remove the SPI writes that are in the main loop, but I will do that now to see if I can still get a hardfault there. I also need to figure out why adding a characteristic to my service causes the a fault where the code was stable before. I'll report back with anything I find.

Related