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

How to uninit SAADC on nRF52 Devkit Using Nordic's saadc Example

I have searched Nordic and the web and have seen several instances of "can't uninit saadc successfully". Neither Nordic support nor I am aware of a single example of saadc uninit working. My private thread with Nordic (in which I share more proprietary code details) has reached a dead end so I am looking for a solution from the community based only on Nordic's saadc example.

I see about ten different library calls that may be relevant to adding an uninit sequence to the SAADC example in SDK 14.2.0. My goal is, using Nordic's example on their DK board, to:

  1. measure DK power consumption before SAADC comes up
  2. measure DK power consumption while SAADC is up
  3. measure DK power consumption after SAADC has been uninit'd
  4. verify that #1 and #3 current measurements are the same

All I am asking for is a recommended uninit sequence for the Nordic SDK 14.2.0 saadc example. Then I will expand on that solution and apply it to my dual ADC channel code below.

Except for the fact that current consumption is (usually) too high after the uninit completes the following code sequence is working as intended. This code is a two adc channel extension of the Nordic example. The #3 current measurement is always 5,10,15, or 20 mA higher than the #1 current measurement which leads me to think that the random timing of the uninit relative to the sampling and clock may be the problem.

// Nordic SDK 14.2.0 example saadc - modified for TWO ADC channels
nrf_drv_saadc_init(NULL, saadc_bemf_callback);

// Two adc channels
nrf_drv_saadc_channel_init(FR_ADC_ISEN_CHANNEL, &m_adc_channel_config0);
nrf_drv_saadc_channel_init(FR_ADC_BEMF_CHANNEL, &m_adc_channel_config1);

nrf_drv_saadc_buffer_convert(l_buffer_pool[0], FR_ADC_BUFFER_SIZE);
nrf_drv_saadc_buffer_convert(l_buffer_pool[1], FR_ADC_BUFFER_SIZE);

nrf_drv_ppi_init();
nrf_drv_timer_init(&l_timer, &timer_cfg, timer_handler);
nrf_drv_timer_extended_compare(
    &l_timer,
    NRF_TIMER_CC_CHANNEL0,
    ticks,
    NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
    false
);

nrf_drv_timer_enable(&l_timer);
nrf_drv_timer_compare_event_address_get(
    &l_timer,
    NRF_TIMER_CC_CHANNEL0
);
nrf_drv_saadc_sample_task_get();
nrf_drv_ppi_channel_alloc(&l_ppi_channel();
nrf_drv_ppi_channel_enable(l_ppi_channel);

// The above, similar to Nordic's example but with TWO ADC channels works
// perfectly

// Init done, now try uninit

nrf_drv_ppi_channel_disable(l_ppi_channel);

nrf_drv_ppi_channel_free(l_ppi_channel);
nrf_drv_timer_disable(&l_timer);
nrf_drv_timer_uninit(&l_timer);
nrf_drv_ppi_uninit();

// Again, I'm using Two ADC channels
nrf_drv_saadc_channel_uninit(FR_ADC_BEMF_CHANNEL);
nrf_drv_saadc_channel_uninit(FR_ADC_ISEN_CHANNEL);

nrf_drv_saadc_uninit();

// Current draw is NOT back to initial levels, and the resulting draw varies
// by multiples of 5mA !!! What would cause the 5mA granularity (I'm using a
// microamp capable meter)

Parents
  • Hello,

    as I have lost quite some time with a similar problem (unable to correctly uninitialize the SAADC, therefore current not returning to the value it had before initiailzing the SAADC the first time), I wanted to share my findings, in the hope that it may help some colleague....

    The following observations were taken with SDK 15.0.0 and the Nordic chip is an nRF52840.

    My design is powered from USB and In order to meet the maximum allowable current limit of 500uA when in USB SUSPEND state, I had to find a way to disable the SAADC. I thought that (asynchronously) calling nrf_drv_saadc_uninit() after entering into USB SUSPEND state would suffice, but was proven widely wrong!

    I used the SAADC to sample 5 analog inputs and set SAADC_SAMPLES_IN_BUFFER to a multiple of the number of analog inputs (=10).

    I had BURST and OVERSAMPLE turned off.

    This means that the SAADC needs to be triggered twice (by the associated timer, either HF or a low power application timer) before a conversion is complete.

    Calling nrf_drv_saadc_uninit() after the first trigger (i.e. call of nrf_drv_saadc_sample() ) - therefore with only 5 of the 10 samples taken - but before the second one (and perhaps also stopping the timer in the hope to further reduce the power consumption) results in the SAADC actually left "half way enabled" with an extra current of at least 200-400uA.

    Also, any attempt to re-initialize the SAADC and start sampling again afterwards may lead to a fatal error, since the SAADC was actually not in a clean "uninitialized" state.

    Uninitializing the SAADC only after completing both sampling rounds (all 10 samples taken) eventually fixed the problem.

    My conclusions:

    • it is better to configure a 1:1 relationship between the number of analog input channels and SAADC_SAMPLES_IN_BUFFER. If there is a need to do some average filtering on the samples, it is better to do it in software and not rely on how the hardware would do it.
    • never attempt to "asynchronously" uninitialize the SAADC, if a conversion is still waiting for a sample (trigger) command to be complete: it will not uniinitialize the SAADC completely. The best place to uninitialize the SAADC is directly inside the SAADC event handler, at the end of a complete conversion (many of the "low power SAADC" Nordic examples do this).

    Good luck!

Reply
  • Hello,

    as I have lost quite some time with a similar problem (unable to correctly uninitialize the SAADC, therefore current not returning to the value it had before initiailzing the SAADC the first time), I wanted to share my findings, in the hope that it may help some colleague....

    The following observations were taken with SDK 15.0.0 and the Nordic chip is an nRF52840.

    My design is powered from USB and In order to meet the maximum allowable current limit of 500uA when in USB SUSPEND state, I had to find a way to disable the SAADC. I thought that (asynchronously) calling nrf_drv_saadc_uninit() after entering into USB SUSPEND state would suffice, but was proven widely wrong!

    I used the SAADC to sample 5 analog inputs and set SAADC_SAMPLES_IN_BUFFER to a multiple of the number of analog inputs (=10).

    I had BURST and OVERSAMPLE turned off.

    This means that the SAADC needs to be triggered twice (by the associated timer, either HF or a low power application timer) before a conversion is complete.

    Calling nrf_drv_saadc_uninit() after the first trigger (i.e. call of nrf_drv_saadc_sample() ) - therefore with only 5 of the 10 samples taken - but before the second one (and perhaps also stopping the timer in the hope to further reduce the power consumption) results in the SAADC actually left "half way enabled" with an extra current of at least 200-400uA.

    Also, any attempt to re-initialize the SAADC and start sampling again afterwards may lead to a fatal error, since the SAADC was actually not in a clean "uninitialized" state.

    Uninitializing the SAADC only after completing both sampling rounds (all 10 samples taken) eventually fixed the problem.

    My conclusions:

    • it is better to configure a 1:1 relationship between the number of analog input channels and SAADC_SAMPLES_IN_BUFFER. If there is a need to do some average filtering on the samples, it is better to do it in software and not rely on how the hardware would do it.
    • never attempt to "asynchronously" uninitialize the SAADC, if a conversion is still waiting for a sample (trigger) command to be complete: it will not uniinitialize the SAADC completely. The best place to uninitialize the SAADC is directly inside the SAADC event handler, at the end of a complete conversion (many of the "low power SAADC" Nordic examples do this).

    Good luck!

Children
No Data
Related