[PWM] duty cycle missing in a sequence.

Hello Nordic team,

I come to you because I face a strange issue during developing a simple feature using PWM.

For a product, I need to make an LED blink smoothly 3 times, so the basic idea is to generate a PWM to provide this signal to the LED.

  With a period of 2 seconds.

I use a base clock of 1MHz. So the PWM frequency set uses a wave counter of 100Hz. In order to bring more light, we use a charge pump circuit clocked at 8kHz. This charge pump uses another PWM instance.

The problem is that there is a kind of outage when running on a LED. It blinks normally but periodically stops briefly before continuing. It happens for every period.

To illustrate what I'm describing, I used an oscilloscope to display voltage during a blink. Here is the result:

  We can observe that a PWM period is missing.

My first try to fix, was to check the hardware. I tried with another LED: the same issue. I tried with another board: the same issue.
Then, I checked my configuration and it seems to be normal (you'll tell me). And I also checked different values of the duty cycle and no step is missing. So I don't understand the problem.

Why I said "strange" at the beginning, it's because this issue doesn't happen all the time. Furthermore, the issue happens when I set my duty cycle sequence at the start of the MCU using a global array, but it doesn't happen when I set these values during each call of the blink function. It also happens when I set duty cycle values into a local array inside the blink function. Really strange behavior... And it happens with or without charge pump circuit.

Maybe it can be an easyDMA issue (because I faced other strange issues related to PWM sequence but I'll make other tickets) but I don't understand where or how to investigate...

Here is the source code of the blink function and its callback handling events:

/**@brief Callback function when blinking LED stops.
 * @function f_pwm_led_callback
 */
static void f_pwm_led_callback(nrfx_pwm_evt_type_t i_event_type)
{
    ret_code_t l_err_code = NRF_SUCCESS;

    switch(i_event_type)
    {
        case (NRFX_PWM_EVT_FINISHED):
          g_pwm_led_finished = true;
          break;
        default:
          break;
    }
}


/**@brief Function for making LED blink smoothly.
 * @function f_pwm_run_led_breath
 */
static void f_pwm_run_led_breath(const uint16_t i_led, const uint16_t i_nb_loop)
{
    uint16_t                  l_nb_loop                 = 1u;
    const uint16_t            l_max_signal              = 10000u;
    const uint16_t            l_step                    = 100u;
    const uint16_t            l_step_s                  = l_max_signal / l_step;

    nrf_pwm_values_common_t   l_pwm_val[l_step * 2u];
    ret_code_t                l_err_code                = NRF_SUCCESS;
    uint16_t                  l_val                     = 0u;

    // Define config PWM
    const nrfx_pwm_config_t l_pwm_cfg0 = {
                                            .output_pins =
                                            {
                                                i_led,
                                                NRFX_PWM_PIN_NOT_USED,
                                                NRFX_PWM_PIN_NOT_USED,
                                                NRFX_PWM_PIN_NOT_USED
                                            },
                                            .irq_priority   = APP_IRQ_PRIORITY_LOWEST,
                                            .base_clock     = NRF_PWM_CLK_1MHz,
                                            .count_mode     = NRF_PWM_MODE_UP,
                                            .top_value      = l_max_signal,
                                            .load_mode      = NRF_PWM_LOAD_COMMON,
                                            .step_mode      = NRF_PWM_STEP_AUTO
                                         };

    nrfx_pwm_uninit(&g_pwm_instance0);
    l_err_code = nrfx_pwm_init(&g_pwm_instance0, &l_pwm_cfg0, &f_pwm_led_callback);
    APP_ERROR_CHECK(l_err_code);


    // Define sequence PWM
    for(uint16_t i = 0u; i < l_step; i++)
    {
        g_pwm_duty_breath[i] = l_val;
        g_pwm_duty_breath[l_step + i] = l_max_signal - l_val;
        l_val += l_step;
    }

    nrf_pwm_sequence_t const l_seq0 =
    {
        .values.p_common  = g_pwm_duty_breath,
        .length           = NRF_PWM_VALUES_LENGTH(g_pwm_duty_breath) << PWM_SEQ_CNT_CNT_Pos,
        .repeats          = 0,
        .end_delay        = 0
    };

    // Play sequence PWM
    if(i_nb_loop > 1)
    {
        l_nb_loop = i_nb_loop;
    }
    (void)nrfx_pwm_stop(&g_pwm_instance0, true);
    (void)nrfx_pwm_simple_playback(&g_pwm_instance0, &l_seq0, l_nb_loop, NRFX_PWM_FLAG_STOP);
    while(g_pwm_led_finished == false && g_fsr_interrupt == false)
    {
        __NOP();
    }
    g_pwm_led_finished = false;
    (void)nrfx_pwm_stop(&g_pwm_instance0, true);
}

Can you help me to deeply understand the issue, please? I'm available to provide more information.

Thank you in advance.

Related