I've been fighting this bug for a few days now and I thought I'd share what I discovered in the process.
I wanted to set up a couple PWM channels to control a few LEDs, so I did what was suggested in the documentation (modified for my uses):
APP_PWM_INSTANCE(PWM1, 1);
app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_2CH(500L, 2, 6);
ret_code_t err_code = app_pwm_init(&PWM1, &pwm1_cfg, pwm_ready_callback);
APP_ERROR_CHECK(err_code);
But the LEDs never did anything. I ran the debugger and traced the problem down to app_pwm_init()
always returning NRF_ERROR_INVALID_STATE
, subsequently causing APP_ERROR_CHECK()
to trigger a reboot. The only place inside of app_pwm_init()
that throws that error is this code:
...
app_pwm_cb_t * p_cb = p_instance->p_cb;
if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED)
{
return NRF_ERROR_INVALID_STATE;
}
...
It seemed absurd to me that this condition would be met because I literally just started initializing the only PWM instance in my code, i.e., the PWM driver should not be in any state except uninitialized. So I dug a little deeper. Look at APP_PWM_INSTANCE()
:
const nrf_drv_timer_t m_pwm_PWM1_timer = {
.p_reg = ((NRF_TIMER_Type *) 0x40009000UL),
.irq = TIMER1_IRQn,
.instance_id = (0),
};
app_pwm_cb_t m_pwm_PWM1_cb; // <------ Never initialized
/*lint -e{545}*/
const app_pwm_t PWM1 = {
.p_cb = &m_pwm_PWM1_cb,
.p_timer = &m_pwm_PWM1_timer,
}
Notice anything? I did. The value that app_pwm_init()
is checking (m_pwm_PWM1_cb.state
) to make sure the PWM driver is not initialized is, well... not initialized. For me that value, for whatever reason, was being randomly set to NRF_DRV_STATE_INITIALIZED
(1), instead of being intentionally set to the much more sensible value of NRF_DRV_STATE_UNINITIALIZED
(0).
A quick change to my code fixed the problem:
APP_PWM_INSTANCE(PWM1, 1);
PWM1.p_cb->state = NRF_DRV_STATE_UNINITIALIZED; // The fix
app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_2CH(500L, 2, 6);
ret_code_t err_code = app_pwm_init(&PWM1, &pwm1_cfg, pwm_ready_callback);
APP_ERROR_CHECK(err_code);
Either the source code for the PWM library has a flaw, or the SDK documentation is missing a step. In either case this needs to be fixed!