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.