HAL Hardware Timer Library Development

This topic is a continuation of the github request #437 and will serve as an area to discuss ongoing development of a HAL/System firmware based hardware timer API for the Core/Photon.

Ping @maghis :smile:

Hi

Any progress on this.

@maghis, it is time to resurrect this offert! I would like to simplify the allocation of timer-based functions which supports all possible timer functions like Input/Output Capture, PWM, etc. The API should be low level so that a SparkIntervalTimer-type library for auto-allocation and control could easily be built upon it. Something based on an Arduino timer framework like this may be a good start:

int every(long period, callback)

Run the ‘callback’ every ‘period’ milliseconds or microseconds (extra parameter?). Returns the ID of the timer event

int every(long period, callback, int repeatCount)

Run the ‘callback’ every ‘period’ milliseconds/microseconds for a total of ‘repeatCount’ times. Returns the ID of the timer event.

int after(long duration, callback)

Run the ‘callback’ once after ‘period’ milliseconds/microseconds. Returns the ID of the timer event.

int oscillate(int pin, long period, int startingValue)

Toggle the state of the digital output ‘pin’ every ‘period’ milliseconds/microseconds. The pin’s starting value is specified in ‘startingValue’, which should be HIGH or LOW. Returns the ID of the timer event.

int oscillate(int pin, long period, int startingValue, int repeatCount)

Toggle the state of the digital output ‘pin’ every ‘period’ milliseconds/ microseconds ‘repeatCount’ times. The pin’s starting value is specified in ‘startingValue’, which should be HIGH or LOW. Returns the ID of the timer event.

int pwm(int pin, long freq, long duty, int startingValue)

Set digital output ‘pin’ as pwm output with ‘freq’ frequency and ‘duty’ duty cycle. Returns the ID of the timer event.

int pulseIn(int pin, long period, int level)

Measure the length of the pulse on the digital input ‘pin’ with active ‘level’ with an expected ‘period’ in milliseconds/microseconds. Returns the measured period of the pulse.

int stop(int id)

Stop the timer events (ie disable interrupts?). Returns the ID of the timer event.

int release(int id)

Stops the timer events and releases the timer resource.

3 Likes

That all made sense to me. But what about stop, what does that mean? How about cancel(id) to cancel a previously registered event? EDIT: I see now that stop() temporarily disables the actions of the event. How are they resumed? release() is what I was calling cancel().

And +100 for doing this in layers. It you want to build auto allocation on top of this, then I feel there is a lower layer needed that manages the available hardware resources (e.g. reporting which timers are in use.)

@peekay123
How about

int pwmON(int id)
int pwmOFF(int id)

to pause/continue the PWM, instead of stop.

Also, in the context of Infrared remote control, it is neccessary to get at least 0.1uSec granularity on timer periods vs 1 uSec granuality. If you plan to use onchip hardware PWM via timers then this is less relevant. If you are generating the PWM via your other callbacks then it is likely an issue (for IR), but better than what we have on Photon today.

Have you condidered using nanoseconds for your period, with a minimum value, of course.

You have defined duty as long, normally it is expressed as a % - or are you using uSecs as the units for duty(HIGH).

A final note, it is useful to start a burst of PWM with a full period/cycle always starting on High. If you just suspend PWM with stop, the PWM may continue on iwhere it left off(?) when resumed , possibly on a LOW. The output needs to go to a known state (LOW?) when suspended and if possible when started/resumed.

I fully understand there may be limitations preventing the above.

cant wait :smile:

@AnalysIR, perhaps a more generic approach would be to have pause(int id) and resume(id) for any “pausable” timer mode. The pause() could set the specified pin to the startingValue. I wasn’t really focused on specifics when I used long for the duty cycle but you are correct!

As for 0.1uSec granularity, remember that the Photon is a busy little processor running FreeRTOS. If you want to service interrupts at that rate, latency and overhead make that impossible. In my experience so far with SparkIntervalTimer, anything below 5uS causes missed interrupts. You may, however, be able to exploit the InputCompare capability of a timer which will time a pulse for you. The entire management of all timer modes and interrupts in the system firmware is new to the Particle platform so optimization is still possible.

Hi, I was wondering if there has been any further development on this library or if anyone could point me towards another timer based interrupt source.

I’m looking to do some IoT light dimming which means I need to update the state of the triac pin about every 65uS to get 8bit levels of dimming. ie 1s / (60Hz*256 intervals). The only way I know to do this is with timer based interrupts. Even though the update rate is high the code per interrupt is tiny since it is a single pin.

Thanks!

Peekay123’s SparkIntervalTimer library is great. Works down to 10 uS; I highly recommend it when you need a hardware-based timer interrupt. It’s in the community libraries and also here: https://github.com/pkourany/SparkIntervalTimer

@rickkas7, thanks! The library uses the HAL layer for all timer interfaces so there is an overhead in ISR redirection versus going lower than the HAL. I have it on my to-do list to add user programmable ISR priority levels when a timer is created, as well as, add support for timers 8-14. :wink:

2 Likes

@IkeHayes

Why not try using hardware PWM, which should have little or no overhead except when altering the frequency or duty cycle.

see the full post here…

Glad to see that the library is alive and well! I was looking for the search term “Timer Interrupt” and this thread was the most recent response which is why I started here.

As for Hardware PWM, when working with AC circuits you have to synchronize the PWM with the zero-crossing of the mains sine wave since triacs hold themselves in the on state until the next zero-cross. I have a zero-cross detector circuit that triggers an external interrupt to clear the output pins and reset the interval counter. Then the timer interrupt counts intervals until the next zero-cross. This way you end up with a PWM like output synchronized with the mains voltage.

2 Likes