Decoupling SPARK_WLAN_Loop() from the user loop()

Hello Sparknauts!
I have been working on making the WiFi loop independent of the user loop() for the past few days. This is implemented by setting up timer2 to generate an interrupt every 50mS and calling the WiFi loop from within it. What this means is that the user loop can now have long delays (more than ∞) without losing connection to the cloud.

This variation of the firmware is available on the feature/decouple-wlanloop branch on GitHub. It’s an experimental branch and I would love to get some feedback on this. Please give it a try!

The affected files are: main.cpp, main.h, spark_wlan.cpp


How will that influence writing code experience? I guess we should put more worries about changes happening to variables in middle of user code?
Will noInterrupts()/interrupts() help?

@mohit How are you multiplexing (mutex-ing) the cc3000?

By setting the interrupt priority of the wlan_loop lower and making it atomic, I’m able to have the CC3K routines run smoothly. I think things might get a little tricky when we start enabling the hardware interrupts. Need more testing there.

@mohit So consider the user code has issues a connect. The cc3000 has been sent the HCI_CMD_SONNECT and is in transit to the event loop. The timer ISR fires - the system is doomed! Seeing I have done this once already I can tell you is not a trivial undertaking.

Do you think by disabling the ISR (that calls the wlan_loop) when executing the TCP/UDP routines, we could avoid the conflicts?

I can see how this implementation of decoupling will not suit all use cases.

No. This requires a classic mutex approch and task synchronization

@mohit Update: To further complicate matters we have the new user space Serial Flash acess

Test Results

@mohit I tested this firmware branch a bit ago with some of my problematic user test code.

That code is for a SainSmart TFT LCD display and has many long delays to give me time to view the results on the display. The LCD communication is via SPI. The code also includes Serial1 output for debugging. Unfortunately, with all the 2-4 second delays in the user code, the Spark Core quickly drops off wireless such that the test code cannot be updated via the web IDE.

This build fixes those issues. :smiley:

The Spark Core stays online such that I can continue to tweak the code in the web UI and push those changes over wireless.

Regarding the concerns raised above…

To at least partially address some of the concerns above, is it possible to only do the WiFi loop if the user code is already executing a delay call? In other words, if the user code isn’t doing anything but waiting for the next 100ms or longer, then allow the system code to do a WiFi loop. I think this should be the default behavior.

If someone needs a “hard delay” that is more accurate and doesn’t yield, then they can call a new function, say, delayHard or wait that works like delay did prior to this change.

BTW, you may also want to add a yield function that explicitly allows the WiFi loop to run during long user code sequences.

Bottom line: If I specify a 2000ms delay in my test code, I don’t care if that delay really takes 2050ms. However, I do care that I can’t update my user code because the Spark Core drops off of WiFi permanently. I like this decoupling feature but I think the user code should be able to control whether it’s enabled (the default) or not.

You and I think alike :slight_smile: I suggested that here:

On a high level, Interrupting every 50ms to run a 5-6ms background task will also add randomly 5-6ms delays in your user code, unless you wrap sensitive code with __disable_irq(); and __enable_irq();

Thx @BDub. I missed your earlier post but, yes, I agree there should be a mechanism to have long delays run background tasks without adding complexity to simple user code. By simple, I mean Arduino-like stuff that new Spark users will expect to “just work” without having their Core go offline.

For more complex scenarios, I don’t plan on having long delays in “production” code. I can ensure the main loop just does one task per cycle so it frequently yields to the Core system loop.