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.

  • I used your example and modified the nrfx_pwm>grouped_mode example to get somewhat of a solution working. I've uploaded it to a github repo here.

    The only issue is that I'm unable to invert PWM polarity:

    The CH2 and CH4 signals should have inverted polarity. This is after I tried setting the POLARITY bit (bit 15) for the COMPARE values loaded from RAM as shown here:

    #define INV(_COMP) (_COMP | 1U << 16)
    
    static void set_biphasic_sequence(nrfx_pwm_config_t *conf, nrf_pwm_values_individual_t *arr, uint16_t pw)
    {
        uint16_t comp_on = conf->top_value - get_count_us(conf, pw);
        NRFX_LOG_INFO("On time COMP: %d", comp_on);
        NRFX_LOG_INFO("On time Inverted COMP: %d", INV(comp_on));
        uint16_t comp_on_dead = conf->top_value - get_count_us(conf, pw + 2 * DEAD_TIME_US);
        NRFX_LOG_INFO("On time COMP with deadband: %d", comp_on_dead);
    
        uint16_t max = conf->top_value;
        // arr[0] = (nrf_pwm_values_individual_t){comp_on, comp_on_dead, max, max};
        // arr[1] = (nrf_pwm_values_individual_t){max, max, comp_on, comp_on_dead};
        // arr[2] = (nrf_pwm_values_individual_t){max, max, max, max};
    
        arr[0] = (nrf_pwm_values_individual_t){comp_on, INV(comp_on_dead), max, INV(max)};
        arr[1] = (nrf_pwm_values_individual_t){max, INV(max), comp_on, INV(comp_on_dead)};
        arr[2] = (nrf_pwm_values_individual_t){max, INV(max), max, INV(max)};
    }
    

    Any idea what I'm doing wrong? I'm using an nrf52dk_nrf52832 board to test.

  • This code fails:

    #define INV(_COMP) (_COMP | 1U << 16)
    STATIC_ASSERT(0x8000 == 1U << 16,"0x8000 == 1U << 16 fails");
    STATIC_ASSERT(INV(7) == 0x8007,"INV(7) == 0x8007 fails");

    This code does not fail:

    #define INV(_COMP) (_COMP | 1U << 15)
    STATIC_ASSERT(0x8000 == 1U << 15,"0x8000 == 1U << 15 fails");
    STATIC_ASSERT(INV(7) == 0x8007,"INV(7) == 0x8007 fails");

    Moral: Be Assertive :-)

  • Gosh that was an embarrassing oversight. Glad I took that issue as a sign to log off for the day. Appreciate all the help you both :)

Related