Timing the flashes

Today Xavier and I worked on a way to flash the LEDs at given absolute angular positions, as discussed in this article

Over the last few days we’ve refined an idea to naturally flash the LEDs at a given absolute angle thanks to the STM32 Timers.

The Idea

To retain awareness of the angular position of the Phyllo, we have a position sensor (either a hall or an optical sensor, both are on the board) that triggers a rising edge once per rotation. We consider the position at which the sensor fires to be the absolute angular position zero. This gives us an absolute reference that we’ll use to keep the flashes from drifting in time.

Right now we have a timer channel in slave reset mode set to capture the input of our sensor. Everytime a rising edge from the sensor occurs, the counter value is stored (and then read by us) and the counter is restarted from 0 (that’s thanks to the slave reset mode).

The idea now is to consider that once the speed is stable, the rotation period will be close to constant, meaning that we can fairly accurately predict when the Phyllo will be at a given angular position as a fraction of the last captured rotation time: if the previous rotation lasted 1000  timer ticks, to flash the LEDs when the Phyllo is at 90° we’ll want to flash them when the timer reaches 250 ticks. Even if the new rotation actually lasts 1001 or 999 ticks, it’ll still be accurate enough. And since that fraction will be computed for each new flash using the latest measured period, there won’t be any drift over time.

To achieve this, we’ll use another channel from that timer in output compare mode and set the compare value to the computed number of ticks (250 in this instance). We can then have a callback called when the channel reaches that value. Using this idea, everytime we enter the output compare callback, we can set the compare value for the following flash. 

An exemple

For instance, suppose we want to flash at 100°, 300° then 140° and 340° on the following rotation. 

Let’s say the latest rotation lasted 36 ticks: that means 100° corresponds to 10 ticks. The compare value is initially set at 10 ticks, at 10 ticks we enter the callback, send the flash, and set the compare value to 30 ticks (for 300°). The same thing happens at 20 ticks and we set the compare value at 14 ticks.

Then, the current rotation completes; let’s say it lasted 34 ticks. The counter resets back to 0, and the next callback is called at 14 ticks. At this point we compute the compare value for 340° using the new rotation period, which yields 33 ticks (and not the 34 ticks we would have had if the rotation had again lasted 36 ticks).

This means we don’t have to worry whether the compare value we’re setting corresponds to the current turn or the next one 🙂 

Issues and solutions

First, we need to be sure the compare value is set before the next flash needs to occur, but the flashes are sufficiently spaced to not worry about this.

Then, there will be a delay depending on what happens in the callback. We could try to use DMAs in a smart way to ensure almost no delay, but we’ll first try to just wake up a thread in the callback that will send the SPI frames. Since with this method we’re always relying on pre-computed absolute angular positions, we’re only worried about the jitter instead of the latency (we can always compensate by subtracting a constant offset to the angles). 

The jitter requirements shouldn’t be too strict, as we only want to ensure the angular error caused by the jitter will not be visible to the naked eye.

There is another issue which could derail the whole chain: consider the case where one rotation lasts 12 ticks, the following lasts 10 ticks and the compare value computed (base on the 12 ticks rotation) turns out to be 11. The second rotation being shorter will cause the compare value of 11 ticks to not be reached.

To fix this, our first plan is to simply check in the capture callback whether the rotation time fell short of the compare value, and flash immediately if that is the case.

Apart from this, we’re still getting used to the STM32CubeMX code generation tool and the FreRTOS HAL API, so we didn’t move much forward today. We’ll get back to it tomorrow.

Stay tuned !

Leave a Reply

Your email address will not be published. Required fields are marked *