Timing the flashes, Act 3

TL;DR

  • Yesterday the latency and jitter of the SPI “FLASH”  frames was a little high: around 80µs for the jitter
  • We had originally planned to solve this by bypassing the interrupts with a DMA request, but sadly this turned out to be unfeasible.
  • Investigating ways to reduce the interruption jitter revealed two main factors:
    • The interrupt priority was too low
    • A scheduled flash and a capture at the same time would cause the flash to be handled after the capture event.
  • Fixing this reduced the jitter from 80µs to 2.5µs

Unfeasible DMA

Yesterday Vlaya and I ended our post with a plan to use a DMA request line (triggered by a comparison match on our Timer channel) to send the “FLASH” SPI frame instead of doing it by software in an interrupt. This would neatly bypass the processor and other interrupts as a source of jitter. Because we will need to send this frame on 3 different buses, that means we would need to be able to trigger 3 separate DMA Streams with the same DMA request line (the request triggered by our Timer Channel).

Sadly, contrary to what we thought, while the DMA Multiplexer (DMAMUX) allows any DMA request line to be routed to any DMA channel, the same request line can only be routed at most once. In other words, any request line from any peripheral can be routed to trigger any DMA Stream, but not routed to trigger more than one Stream.

Increasing the interrupt priority

To improve the interruption jitter anyway, we instead set a higher priority for the interruptions from our Timer (TIM4). To do this, we had to (truthfully) tell the STM32CubeMX code generator we were not using any freeRTOS functions in the TIM4 interruptions. So now our Timer interruptions have higher priority than all other peripheral and kernel interrupts.

Surprisingly, this did not seem to have much effect on its own, meaning most of the delay was not caused by other interruptions.

A matter of interruption handling order

Then we realized that in the HAL (Hardware Abstraction Layer) IRQ Handler the channel 1 one interruptions (on which we capture the rotation period) are handled before the channel 1 interruptions (which we use to trigger a flash).

This means that when a flash was set to occur simultaneously with the next rotation capture – when the angular position of the flash is zero for instance – the rotation period would be recorded first, delaying the sending of the “FLASH” SPI frame.

To bypass this, we check first thing in the capture interruption whether a flash is pending (in other words, whether the channel 2 interrupt flag is set), in which case we clear the flag and trigger a flash.

New results and next steps

This reduced the jitter from 80us to 2.5us , which is more than small enough. Most of this jitter is actually due to the imprecision when converting our absolute angles to the timer tick count.

Later on, we might write our own IRQ Handler for use in this specific case, instead of working around the HAL library IRQ Handler as we do for now. We’ll need to figure out how to convince STM32CubeMX to not overwrite our code when it generates initialization code.

Right now we need to test the jitter when sending a “FLASH” on multiple SPI buses, since eventually we will need to send them on 3 different SPI buses.

We’ll keep you posted 🙂

Leave a Reply

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