This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Bug in APP_PWM_INSTANCE() in SDK 9.0.0

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!

Related