Skip to main content
Graduate
December 4, 2023
Solved

Interrupt Service Routine Jitter

  • December 4, 2023
  • 10 replies
  • 6908 views

Hi,

I use a STM32F767 Nucleo-144 board with a STM32F767ZIT6 processor.

With CubeIDE I configure SPI1 as I2S1 input and pump the data via DMA2/Stream0  in a short 8x16Bit circular buffer. The clock of the SPI1 is at ~ 3MHz .I set up the HAL_I2S_RxHalfCpltCallback() and  HAL_I2S_RxCpltCallback() routines. In both routines i toggle a GPIO and get a ~23.8kHz square wave.  This all works as exspected. 

But: The square wave suffers from a big jitter. First, there is a constant jitter in the range of 100ns. Second, sometimes the duty cycle (not the frequency) of the signal changes by ~330ns for some parts of a second. 330ns ist the reciprocal of my 3MHz clock.

How can I get rid of the jitter? I tried to slim down HAL_DMA_IRQHandler() to the necessary parts for my use case. That did not affect the jitter. I also changed the NVIC priorities with no effect.

How can I get rid of the jitter?

THX

Cheers

Detlef

 

    This topic has been closed for replies.
    Best answer by TDK

    Probably the SysTick occasionally adds a delay.

    You can make a synchronous square wave by using another SPI slave, hooking up the SCK between then and outputting 0x00FF or similar on the MISO pin in a circular buffer.

    10 replies

    Super User
    December 4, 2023

    You cannot eliminate the jitter entirely, at least not in the general case, but you can get it to within about 12 ticks. by discarding HAL (at least the interrupt portion) and writing your own interrupt routine and ensuring that particular interrupt has the highest priority.

    Why is jitter critical here? There are likely other ways to achieve what you want. Square waves can be generated by a PWM signal on a timer, for instance. The SPI signal should be constant with a 3 MHz clock despite the jitter in the IRQ handler.

     

    DetlefSAuthor
    Graduate
    December 5, 2023

    Hi, the uC runs at 192MHz, so 12 ticks result in a ~60ns jitter, which matches with the measured < 100ns jitter. But, as mentioned, I get these 1/3MHz~330ns jumps in the 'duty cycle' of the square wave.

    The 23.8kHz ultrasonic signal ist sampled with the 3MHz MEMS-mic. The phase of the audio signal is resolved with 0.5° accuracy which results in ~59ns. So the 12ticks jitter is 'noise' for me but I clearly see the 330ns jumps as artefacts. I do understand the 12ticks jitter but I do not understand the 330ns jitter.

    I also tried to generate a square wave with a timer, which is syncronous to the SPI clock. The datasheet claims '95238Hz' sample rate for '96k' I2S mode. The exact number could be 192E6/2016=95238.09524 Hz. So dividing the uC clock by 192E6/(4*2016) could result in a syncronous 23.80952381kHz clock :) . Until now I could not get the timer output syncronous to the SPI clock, but with the 4*2016 division it could work, worth a try.

    THX Cheers Detlef

    TDKAnswer
    Super User
    December 5, 2023

    Probably the SysTick occasionally adds a delay.

    You can make a synchronous square wave by using another SPI slave, hooking up the SCK between then and outputting 0x00FF or similar on the MISO pin in a circular buffer.

    DetlefSAuthor
    Graduate
    December 5, 2023

    Hi, I managed to configure a timer so that the square wave is syncronous to the SPI interrupt, no phase slipping. I'm not happy with the solution, because I do not understand the origin of the 330ns jitter (It is not from the systick interrupt). I know that an issue you do not understand will fire up problems at the worst point in time :| .

    THX

    Cheers

    Detlef

    Super User
    December 5, 2023

    Glad you could get what you wanted.

    If you wanted to chase it down, one way to understand what interrupts are happening is to, within your main loop, do __disable_irq(), wait a few seconds, then examine NVIC registers to see what interrupts are pending. That will show them all 100%.

    Could be that you have DMA and I2S happening and they're not happening in the order that you want.

    But the processor is a state machine and should behave the same given the same conditions. It is not prone to fickle behavior. The M7 core is complex and can vary by a few cycles due to various optimizations and internal shortcuts, but not by 330ns.

    Graduate II
    December 5, 2023

    First, there is a constant jitter in the range of 100ns.


    If you mean "constant delay", then that is not jitter, but latency. Jitter is a timing noise, not a constant offset. The same with the 12 clock cycles - that is an interrupt enter/exit latency.

    On this MCU for I2S the SAI peripheral is preferred instead of the SPI peripheral. And you haven't explained what you are trying to achieve. For example, the two SAI peripherals can provide up to four synchronized I2S streams.

    DetlefSAuthor
    Graduate
    December 6, 2023

    Hi, I mean jitter, not delay. A constant jitter of 100ns is timing noise of max 100ns. Stochastic timing noise for interrupts is normal, because the delay from interrupt happening to servicing is dependent on processor state.

    I service a raw pulsetrain from a MEMS-MIC. I want to measure the ultrasonic time-of-flight by its phase.

    Cheers Detlef

    Graduate II
    December 6, 2023

    So basically you need to somehow count the 3 MHz pulses? The MEMS microphone outputs a digital PDM stream. Why don't you just count the bits in the captured bytes?

    DetlefSAuthor
    Graduate
    December 6, 2023

    The bitstream is my broadband signal including my 23.8kHz audio signal of interest. I use Goertzel algorithm to calculate the phase ( and amplitude ) at that frequency. Goertzel is represented by a recursive 2.order IIR-filter. I pump the bits through that filter and get the phase. The sampling frequency  ~3MHz and the audio 23.8kHz need a common, syncronous source, a single missing bit shows up as a jump in phase.

    DetlefSAuthor
    Graduate
    December 6, 2023

    A full cycle of my audio ie 360° is 1/23800 sec long. A full cycle of my sampling freq. is 1/3E6 long, which results in 2.856° in phase of my audio. My target accuracy is 0.5° for the audio, 58ns, 6 times as short as a single 3MHz pulse.

    Graduate II
    December 6, 2023

     I also changed the NVIC priorities with no effect.

    What about other active interrupts?
    If the MCU is working on another ISR when the higher priority I2S interrupt occurs, could that take some additional time, going from within the current ISR to the I2S ISR ?

    Maybe @TDK or @Piranha can answer this?

    Super User
    December 6, 2023

    > a single missing bit

    Why would you miss a bit with hardware I2S? It runs continuously, I presume, with cyclic DMA, so there's no way you miss a bit. The only requirement is, that interrupt has to be handled within half the DMA buffer.

    Latency and jitter of interrupt is given by quite a couple of things in 'M7, but if it's thousands of cycles, then it's very likely some other interrupt with same or higher priority, so start perhaps looking into other parts of your code for that. Any library you are using is now part of that code of yours.

    Using Cube/HAL in a timing constrained application is never a good idea.

    JW

    DetlefSAuthor
    Graduate
    December 6, 2023

    >>Why would you miss a bit with hardware I2S?

    I do not miss a bit. I do not see phase jumps, I see phase jitter.

    >>Using Cube/HAL in a timing constrained application is never a good idea.

    I've come to the same conclusion.

    THX Cheers Detlef

    Super User
    December 6, 2023

    >> Why would you miss a bit with hardware I2S?

    > I do not miss a bit. I do not see phase jumps, I see phase jitter.

    And what is the cause of that jitter? Data are read in by I2S synchronously with I2S clock, and timing of interrupt can't change this relationship.

    If you need to *generate* a square waveform synchronous with I2S clock, don't generate it in interrupt; rather, use a timer to generate it.

    JW

    DetlefSAuthor
    Graduate
    December 6, 2023

    >> And what is the cause of that jitter?

    This was my question. I dunno.

    Why shouldnt I generate the square wave in the  I2S? Syncronicity is forced.

    I now use a syncronous timer pwm. That raised some issues as well. The calculated number of counts only works in 'up' mode, not 'down' or the centered modes. No idea why.

    Thx cheers Detlef 

     

     

    Super User
    December 6, 2023

    > Why shouldnt I generate the square wave in the I2S?

    You mean, in the I2S interrupt? Exactly because there are many possible sources of jitter.

    > The calculated number of counts only works in 'up' mode, not 'down' or the centered modes.

    I don't know what do you mean by "calculated number of counts" here, and why is it a problem.

    JW

    Graduate II
    December 8, 2023

    Any other interrupts active?

    For clean 96 kHz with a F767 you need a dedicated 24.576 MHz (or better 49.152 MHz if you want to switch to 192 kHz later on) oscillator at I2S_CKIN. Or as HSE, then again you might get some PLL jitter (which is not too bad, as I found out by using PLL driven TX SPDIF, actually with a F767).

    Super User
    December 8, 2023

    One way to solve this is to feed back externally the bit clock from SPI/I2S into a timer's pin and use that timer in external clock mode to generate framing using PWM. There may be some sub-TIM-clock-period jitter from mismatch of I2S and TIM clock.

    A better way may be to use PLL so that the system clock and I2S clock are set up identically or having an integer mutual ratio, that should remove source of abovementioned jitter. In that case you also might be able to start timer and I2S in a way that they are synchronous, although it's not simple, removing the need to feed back clock externally. As LCE said above, this will probably require a specific frequency crystal, if you are after some particular frequency, although it may quite well be that you don't need some of the "usual audio" frequencies anyway, as you are going to process the signal locally (i.e. don't depend on other equipment into which digital signal is going to be fed, which might require the "usual frequencies").

    Yet another, and possibly better, way may be to use SAI set up so that the framing clock output fulfills your requirement, or use two synchronized SAIs, one generating the I2S signal and other generating the framing signal.

    A similar method may be to use two I2S clocked from the same PLL tap (if they are available), use one to generate the I2S signal and the other to generate framing alone, with different divider setting.

    JW

     

    Graduate II
    December 9, 2023

    As I told previously, the SAI peripheral is preferred. Not only the SAI streams can be run from the same clock, but they are also designed to be started synchronously. One stream can capture the PDM audio and the other can generate basically any bitstream, including a square wave.