Hi,
I would like to understand whether the Delay and Delay_Microsecond functions are functionally equivalent, with the exception of course that the first specifies a millisecond delay, while the latter specifies a microsecond delay.
I can see that the former works off the SysTick_Handler interrupt and the latter works off the watchdog timer. So does this make a difference?
Obviously there is the maximum delay time difference, but using a 32-bit counter for a 1us tick means a maximum delay of approximately 59.65 s. So I wonder why there is even a Delay function (unless one wants to delay for up to approximately 16.5 hours(!) for the 1 ms delay function).
Background to my question is: I would like to use the SysTick_Handler for my own code, specifically moving the Timing_Decrement function to a different timer.
Iāve been thinking about allowing user code to hook the systick interrupt, see https://github.com/spark/firmware/issues/399. If this is useful to you, please let us know and please outline your use case so we can help you implement it. With a hook, you donāt need to move the Timing_Decrement to a new handler - chaining the existing handler will work just fine!
Also, just a heads up that neither of those functions (Delay, Delay_Milliseconds) are part of the public API and they wonāt be available to user code in the next release. There will be equivalent functions provided by our HAL layer.
@mdma, chaining the systick handler to a user is begging for trouble IMO, especially in a FreeRTOS environment. I believe this kind of requirement could be handled at the local compilation level with some compiler directives.
I do agree, and it will need to be managed well. Iāve not implemented it since itās also possible for the user to set up a timer to achieve the same. But always looking for use cases that might change our course!
So the background to my request is that Iād like to use the Quantam-Leaps QP state machine framework (www.state-machine.com) for my project. Iāve used it very successfully for my Arduino based projects.
On the ARM M3 Cortex platform, the framework uses the systick interrupt for scheduling purposes, at its own N ticks per second. Therefore I was thinking - and the reason for my question - to move all the existing spark core āsystem codeā off this interrupt, just to make sure everything is separated. (There indeed may be no need for this separation because I think the QP framework could co-exist, but I wanted to make things simple, i.e., make sure I knew what was driving whatā¦)
I realise there are various parts of the code using the Delay function - specifically some of the WLAN / CC3300 code. It wasnāt clear to me whether this Delay function was part of an underlying āRTOSā type system or could be driven from the watchdog timer.
If there was a hook from the systick interrupt service routine, it might work.i.e., it would call the ātickā function for the QP framework - QP::QF::TICK(). Of course this would be a 1 ms tick. However, the QP framework is the pseudo RTOS in this case.
And thus back to my thinking about the Delay vs. Delay_Milliseconds functions: I would move everything off the systick interrupt, i.e., to the watchdog timer; so the WLAN functionality, etc. Then I would drive everything which is in the Timing_Decrement() function from the RTOS state machine (LED display and button debounce). If that all make senseā¦
I donāt have my spark core with me right now - Iām travelling for work - but when I return, I can easily test out the possibility: Iāll put a call to QP::QF::TICK() into the SysTick_Handler() function to test things out.
@bit_cyber, this issue is really about the Coreās management of systick. The photon will give you a much better platform for QP as it could use a 1ms software timer (with callback) to drive the QP timebase. One thing I want to discuss with the Spark Team is the possibility of opening up a second user thread. One thread for setup()/loop() and another for a āparallelā task.
Eventually the user code will run on a separate thread and the system on another thread. Itās certainly possible, but by no means simple. Thereās lots of small but critical details that need working out, such as which thread does Spark.function() execute on? How are shared resources like the LED managed? Do variables need to be thread-safe since they can be set from both the user thread and read by the system thread? etc etcā¦
Itās interesting to note that iād decided on active objects as the principle design to achieve threading separation of system and user code. And with a pre-emptive scheduler, they donāt need to be co-oprative so we can ensure responsiveness even with long blocking delays in one thread.
@peekay123, Point taken in regard to the management of systick, but in my mind if QP is going to be the RTOS, then it should be driven off a hardware derived timer.
Also the QP framework does offer both vanilla (cooperative) and qk (preemptive) kernels. Certainly the latter would be best to run off a hardware timer.
@mdma, Have you considered the QP framework? It does enforce state-machine thinking, so a change in perspective, but I believe that on an embedded platform this is a definite benefit. (In a previous life I was a professional developer and now can see it would have been beneficial for some tasks to have used such a framework.)
Anyway, maybe something even that could be supported, rather than the absolutely must have to use.
If things go well with my experimentation, Iād be willing to contribute.
But - getting back to the my original question: do you think it will work to move tasks using the Delay() function, and therefore the systick interrupt, to the watchdog timer?
@bit_cyber, I would say you wonāt really know till you try it! As for using the preemptive QK kernel, itās a possibility but WICED is designed around FreeRTOS and ThreadX. Running QP (cooperative) as a separate thread may be possible.
With the Core firmware totally open and with HAL you can try anything!
You know, Iād not heard of it until you mentioned it! Although the principles and advantages of active objects are well documented (hence that being my chosen strategy to bring parallelism to the photon without all the pitfalls of traditional multithreading.)
Weāve also been looking at go-like channels as another high-level take on multithreading (which are hugely similar to active objects in some respects.) If you have any thoughts on the benefits of leveraging QP Iād love to hear them!
OK - so, Iāve done some further work⦠(Interspersed by work (the day job) and some holidays.) The system seems to be working pretty well, here are the details and some comments:
Things performed
The Delay function was replaced with the Delay_Microsecond function. Achieved via calling the Delay_Microsecond function within the Delay function, of course multiplying the delay time by 1000.
(The TimingDelay variable was also removed as part of this, as itās no longer necessary to track the delay, as āclockedā via the systick interrupt handler.)
A port of the QP framework - specifically QP/C++ Version 4.5.04, and that provided in one of the examples for the ARM CORTEX M3 (dpp-stm3210c-eval) - was used. STM3210C specific code was removed as itās irrelevant, particularly given that the STM3210C is an evaluation board with an LCD, etc., etc.
A basic āsupervisorā type active object was implemented to manage everything. The systick timing wasnāt changed, so itās still every 1 ms. This means that the QP framework is tickāed every 1 ms. Then there is a 1 ms user (QP) timer which checks on the network status.
The wlan specific code was moved from the main routine into the supervisor active object such that network connection is handled and then maintained.
Iām yet to move the button press handling from the Timing_Decrement routine. Based on what Iām thinking handling these this is best located in the supervisor active object.
Comments
The spark core (or rather: particle core) performs the network connection fine and connects to the cloud.
Currently I canāt put the particle core into listening mode - Iām sure thereās some minor issue here which Iāve missed. Although I can easily write new firmware (DFU mode) and then it connects to the wlan / cloud fine.
How to leverage the QP framework? (read: why QP?)
So a good question⦠Hereās my thinking:
Relating to state machines, but maybe not the prime focus: A lot of programming problems exist because of lack of knowledge of what will happen in the future (the classic example is: āHow many bytes to allocate in a buffer?ā). A state machine clearly indicates what to do when.
(And the particle core is powerful enough to require some form of realistic OS, nothing too complicated, but something that makes everything easy and possible.)
The QP framework makes developing embedded code easy(!). (Iāve developed a GPS Disciplined Oscialltor on an Arduino, with an LCD and button UI, not to mention the GPS message handlers. Everything just works.)
Active objects are a mechanism to provide for all of this. A good design pattern.
The framework offers both co-operative and pre-emptive scheduling options built-in.
The QP framework is freely available (GPL v2 licencing).
Of course preference for programming style is just that. But Iām a believer of state machines for embedded development, with the QP framework being readily available, quite well documented and it makes things easy.
Anyway, Iāll keep you posted of my adventuresā¦