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

Two saadc channels get switched if callback takes too long

I'm trying to read two ADC channels asynchronously.

I can setup two channels, and as mentioned on the forums, the data from channel 0 is at buffer[0].

The issue I'm trying to understand is that if there is a delay in the saadc_callback, channel 1 is at buffer[0] and channel 0 is at buffer[1].

I'm using the nRF52 DK with nRF5_SDK_15.3.0_59ac345.

I can demonstrate this in the saadc example code at nRF5_SDK_15.3.0_59ac345/examples/peripheral/saadc

Diff:

diff --git a/examples/peripheral/saadc/main.c b/examples/peripheral/saadc/main.c
index 8c956541..4e6289f5 100644
--- a/examples/peripheral/saadc/main.c
+++ b/examples/peripheral/saadc/main.c
@@ -66,7 +66,7 @@
 #include "nrf_log_ctrl.h"
 #include "nrf_log_default_backends.h"
 
-#define SAMPLES_IN_BUFFER 5
+#define SAMPLES_IN_BUFFER 2
 volatile uint8_t state = 1;
 
 static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
@@ -141,7 +141,9 @@ void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
         {
             NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
         }
-        m_adc_evt_counter++;
+        if(m_adc_evt_counter++ == 15) {
+            nrf_delay_ms(1000);
+        }
     }
 }
 
@@ -149,13 +151,18 @@ void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
 void saadc_init(void)
 {
     ret_code_t err_code;
-    nrf_saadc_channel_config_t channel_config =
-        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
+    nrf_saadc_channel_config_t channel_config0 =
+        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);
+
+    nrf_saadc_channel_config_t channel_config1 =
+        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
 
     err_code = nrf_drv_saadc_init(NULL, saadc_callback);
     APP_ERROR_CHECK(err_code);
 
-    err_code = nrf_drv_saadc_channel_init(0, &channel_config);
+    err_code = nrf_drv_saadc_channel_init(0, &channel_config0);
+    APP_ERROR_CHECK(err_code);
+    err_code = nrf_drv_saadc_channel_init(1, &channel_config1);
     APP_ERROR_CHECK(err_code);
 
     err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);

As you can see, I'm changing the number of samples to two, adding a second channel, and after 15 reads, delaying once for a second in the saadc_callback.

I put two resistor dividers from VDD to GND made of random resistors to get two different values on the ADC channels.

So as you can see, channel 1 reads higher voltage than channel 0, but in the 17th read, it switches.

<info> app: ADC event number:14
<info> app: 407
<info> app: 630
<info> app: ADC event number: 15
<info> app: 407
<info> app: 629
<info> app: ADC event number: 16
<info> app: 47
<info> app: 628
<info> app: ADC vent number: 17
<info> app: 628
<info> app: 408
<info> app: ADC event numbe: 18
<info> app: 630
<info> app: 408

Channel 0 reading 47 on the 16th read is just an artifact of logging I think, as other places in the log there are missing characters.

If I use RTT as the logging backend I don't see missing characters, this seems unrelated so I'm ignoring.

full modified saadc/main.c: http://ix.io/1Mk6

If I have an app_timer callback that has a delay in it that also causes the channels to switch.

  • Yep, that is the issue.

    I got it working from comments in that thread.

    Thank you.

    Working diff:

    diff --git a/examples/peripheral/saadc/main.c b/examples/peripheral/saadc/main.c
    index 8c956541..d80e9731 100644
    --- a/examples/peripheral/saadc/main.c
    +++ b/examples/peripheral/saadc/main.c
    @@ -72,6 +72,7 @@ volatile uint8_t state = 1;
     static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
     static nrf_saadc_value_t     m_buffer_pool[2][SAMPLES_IN_BUFFER];
     static nrf_ppi_channel_t     m_ppi_channel;
    +static nrf_ppi_channel_t     m_ppi_channel0;
     static uint32_t              m_adc_evt_counter;
     
     
    @@ -110,17 +111,27 @@ void saadc_sampling_event_init(void)
         err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
         APP_ERROR_CHECK(err_code);
     
    +    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel0);
    +    APP_ERROR_CHECK(err_code);
    +
         err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                               timer_compare_event_addr,
                                               saadc_sample_task_addr);
         APP_ERROR_CHECK(err_code);
    +
    +    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel0,
    +            nrf_saadc_event_address_get(NRF_SAADC_EVENT_END),
    +            nrf_saadc_task_address_get(NRF_SAADC_TASK_START));
    +    APP_ERROR_CHECK(err_code);
    +
     }
     
     
     void saadc_sampling_event_enable(void)
     {
         ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
    -
    +    APP_ERROR_CHECK(err_code);
    +    err_code = nrf_drv_ppi_channel_enable(m_ppi_channel0);
         APP_ERROR_CHECK(err_code);
     }

Related