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.