Jitter in high priority thread loop with irq_lock and k_sched_lock

I've been working on a custom device utilising the nRF52832 that needs to switch GPIOs in tightly controlled pulses. The problematic section is part of a much larger project written using nRF Connect SDK v2.6.1:

k_sched_lock();
key = irq_lock();
positive_electrodes();
k_busy_wait(50);

float_electrodes();
k_busy_wait(40);

negative_electrodes();
k_busy_wait(50);

ground_electrodes();
irq_unlock(key);
k_sched_unlock();   

k_usleep(10e3);

The code block is the body of an infinite while loop in a thread function. The thread priority is 1 (higher than every other created thread). The positive_electrodes, float_electrodes, negative_electrodes, and ground_electrodes functions are just wrappers around a series of log and gpio_pin_set_dt statements.

I am checking the GPIO waveforms on an oscilloscope, I would expect to see pulses that are 50us and 40us long. This is mostly what I see, however, every other second or so, I see a jump on the pulse width with a maximum of 190us when it should be 50us.

Pulse width jitter has been a major problem in previous versions of my software, that I drastically reduced by utilising k_busy_wait instead of k_usleep, and by adding the irq_lock. However, the jitter has not disappeared. Based on a sample size of 1000 pulses, the deviation for each of the 50us pulses I am scoping is about 10us, which is a lot higher than I would expect. 

Does anyone have any ideas of what could be causing the occasional extremely long pulses despite all the mitigation I have tried (irq_lock, k_sched_lock, highest priority thread)? I have tried moving from the thread based implementation to a chain of timers that start the next one on expiry but that just exacerbated the jitter beyond reason. 

Edit: I forgot to mention that while I extensively use the logging module, logging is turned off in the project config file since we have to way of interfacing with the MCU once in production.

Parents
  • Was there a reason to not just use hardware PWM to drive the GPIO? The pulses would then have no jitter; if code is required for each part of the pulse or some parts of the pulse the EGU could be used to generate interrupts which would handle any semaphores and the like; no need for thread interaction for the actual pulse timing.

    Maybe share the driving circuit for the electrodes; a 4-output PWM can control the Pos-Float-neg-ground phases by selectively setting each of the 4 outputs to (say) H1D0, D1D0, H0D1, H1D0 but need to see how the outputs are driven to confirm. It is possible to use more than one PWM synchronously with 0nSec phase delay as well as no jitter. I provide an example here; the nRF52832 is simple but the changed PWM implementation on the nRF52833 required slightly different code: pwm-anomaly-nrf52832-vs-nrf52833 and start-pwms-synchronous

Reply
  • Was there a reason to not just use hardware PWM to drive the GPIO? The pulses would then have no jitter; if code is required for each part of the pulse or some parts of the pulse the EGU could be used to generate interrupts which would handle any semaphores and the like; no need for thread interaction for the actual pulse timing.

    Maybe share the driving circuit for the electrodes; a 4-output PWM can control the Pos-Float-neg-ground phases by selectively setting each of the 4 outputs to (say) H1D0, D1D0, H0D1, H1D0 but need to see how the outputs are driven to confirm. It is possible to use more than one PWM synchronously with 0nSec phase delay as well as no jitter. I provide an example here; the nRF52832 is simple but the changed PWM implementation on the nRF52833 required slightly different code: pwm-anomaly-nrf52832-vs-nrf52833 and start-pwms-synchronous

Children
No Data
Related