nrfx_pwm_uninit fails to uninitialize PWM instance

In our project we have functions for outputting a single frequency via PWM for an indefinite amount of time until we call a function to turn it off. See attached code.

void speaker_output_freq(uint16_t freq) {
  ret_code_t err_code;
  const uint16_t counter_top = 1000000 / freq;
  static nrf_pwm_values_individual_t seq_values; // This array cannot be allocated on stack (hence "static") and it must be in RAM 
  seq_values.channel_0 = counter_top / 2; // always use 50% duty cycle for max volume

  
  nrfx_pwm_config_t const config0 = {
    .output_pins = {
      SPEAKER_PWM_PIN,		// channel 0
      NRFX_PWM_PIN_NOT_USED,	// channel 1
      NRFX_PWM_PIN_NOT_USED,	// channel 2
      NRFX_PWM_PIN_NOT_USED	// channel 3
    },
    .irq_priority = NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY,
    .base_clock   = NRF_PWM_CLK_1MHz,
    .count_mode   = NRF_PWM_MODE_UP,
    .top_value    = counter_top,
    .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
    .step_mode    = NRF_PWM_STEP_AUTO
  };

  nrf_pwm_sequence_t const seq = {
    .values.p_individual = &seq_values,
    .length              = NRF_PWM_VALUES_LENGTH(seq_values),
    .repeats             = 0,
    .end_delay           = 0
  };

  if (is_pwm_running == true) { 
    speaker_output_off();
  }

  err_code = nrfx_pwm_init(&pwm_instance, &config0, NULL);
  SFG_ERROR_CHECK(err_code, M_SPEAKER_OUTPUT);

  nrfx_pwm_simple_playback(&pwm_instance, &seq, 1, NRFX_PWM_FLAG_LOOP);
  is_pwm_running = true;
}

void speaker_output_off(void) {
  if (is_pwm_running == true) { // stop/uninit calls will cause reset if pwm is not initialized when called
    nrfx_pwm_stop(&pwm_instance, true); // waits until duty cycle is complete
    nrfx_pwm_uninit(&pwm_instance);
    is_pwm_running = false;
  }

  // Pin must be driven low so speaker FET doesn't get any signal. Must reconfigure as output each time since PWM module reconfigures pin
  nrf_gpio_cfg_output(SPEAKER_PWM_PIN);
  nrf_gpio_pin_clear(SPEAKER_PWM_PIN);
}

As you can see, we have a flag in place (is_pwm_running) to track if the PWM instance is running, and turn it off before attempting to start the next tone if so. Our SFG_ERROR_CHECK function serves to store errors in flash so we can retrieve and analyze them later.

What I am seeing is that occasionally nrfx_pwm_init() generates an error, NRFX_ERROR_INVALID_STATE, meaning the pwm instance was already initialized when we called nrfx_pwm_init(). Our logic ensures nrfx_pwm_uninit() was called prior the nrfx_pwm_init() call, so I am unsure how this error is being generated. I am unable to reproduce the error myself, but our error tracking indicates that it is indeed happening, albeit rarely.

So my questions are:

1. Am I misusing the PWM driver in some way I do not realize? Is my un-initialization procedure set up correctly?

2. If my driver usage is correct, are there any reasons why nrfx_pwm_uninit() would be failing? Is nrfx_pwm_uninit() non-blocking and I am simply calling nrfx_pwm_init too quickly for the driver to fully uninitialize? 

Related