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

Getting analog values from different channels using SAADC example

Hello ,

I want to read around 6 analog pins, not necessarily simultaneously. I could afford some delay in between them. i am using nrf52832 dev kit with sdk 15. How do i modify the SAADC example to achieve the same because the example only reads 1 channel. i did found this thread https://devzone.nordicsemi.com/f/nordic-q-a/5561/adc-from-various-pins/19481#19481 which looks similar but i was unable to open the GitHub link provided in the thread. Can you please direct me to the relevant examples. 

Thank you!

Parents
  • Hello,

    It should be fine to measure 6 ADC channels at once.

    Attached is a slightly modified project from the SDK15.0.0\examples\peripheral\saadc example. Only the main.c file is changed. It will measure the 6 pins AIN0 - AIN5, and print the values in the UART log.

    saadc_x_2.zip

     

    Remember that AIN0 is not the same as A0 printed on the PCB. The AINx pins are:

    AIN0 = P0.02
    AIN1 = P0.03
    AIN2 = P0.04
    AIN3 = P0.05
    AIN4 = P0.28
    AIN5 = P0.29


    Best regards,

    Edvin

  • Hello Edvin, that was a great help. I was wondering what would i have to do to take the readings from the other 2 analog pins? it does not have to be at same time. could be after a delay, but how do i take those readings as well?

    Thanks! 

  • Can you describe what you are seeing?

    I see that you initialize 5 ADC channels, and your buffer size is 5, but in the callback event, you try to fetch 10 values (from 0 to 9). Do you get random numbers on the last 5 samples? How about the first 5? Do you actually read 5 pins, or only 2?

    BR,

    Edvin

  • Hi Edvin, I am fetching only 5 values in the call back event . T, T1, T2, P1, P2 . Then I just split the 16bit values into two 8 bit values . That's why : value [0-9]. 

    I can't understand what exactly is happening. Like yesterday I hooked up a sensor on AIN4 pin which was my channel 0. So i should have gotten the value in T but instead I received value in P2 which is my channel 4 and pin AIN0. 

    Can you please review the code, only the saadc part and tell what am i doing wrong?

    Thanks,

    Arshdeep 

    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
            ret_code_t err_code;
            static int adc_value[SAADC_SAMPLES_IN_BUFFER];
            uint16_t T,T1, T2, P1, P2;
           
            uint8_t nus_to_send_array[2];
           
    
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
    
            int i;
            NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);
    
            for (i = 0; i < SAADC_SAMPLES_IN_BUFFER; i++)
            {
                 // printf("%d\r\n",p_event->data.done.p_buffer[i]);
                   adc_value[i] = p_event->data.done.p_buffer[i];
                
                                          
            }
    
                 
                 R = 10000*((825.5/adc_value[0])-1);
                float logR = log(R);
                 C = C1 + C2*logR + C3*logR*logR*logR;
                T = 1/C;
                T = T - 273.15;
                T = (T*9)/5 + 32;
                T = T/1.009;
    
                 R1 = 10000*((825.5/adc_value[1])-1);
                float logR1 = log(R1);
                 C = C1 + C2*logR1 + C3*logR1*logR1*logR1;
                T1 = 1/C;
                T1 = T1 - 273.15;
                T1 = (T1*9)/5 + 32;
                T1 = T1/1.009;
    
                R2 = 10000*((825.5/adc_value[2])-1);
                float logR2 = log(R2);
                 C = C1 + C2*logR2 + C3*logR2*logR2*logR2;
                T2 = 1/C;
                T2 = T2 - 273.15;
                T2 = (T2*9)/5 + 32;
                T2 = T2/1.009;
    
                P1 = ((adc_value[3] * 3.6)/1024);          
                P1 = P1*(Res2/Res2+Res1);
                P1 = (P1 - 0.5)/4;
                P1 = P1*2;
                P1 = P1*145.038;
    
                P2 = ((adc_value[4] * 3.6)/1024);          
                P2 = P2*(Res2/Res2+Res1);
                P2 = (P2 - 0.5)/4;
                P2 = P2*4;
                P2 = P2*145.038;
    
    
            
            value[0] = (T & 0xFF00) >> 8;
            value[1] = (T & 0x00FF);
            value[2] = (T1 & 0xFF00) >> 8;
            value[3] = (T1 & 0x00FF);
            value[4] = (T2 & 0xFF00) >> 8;
            value[5] = (T2 & 0x00FF);
            value[6] = (P1 & 0xFF00) >> 8;
            value[7] = (P1 & 0x00FF);
            value[8] = (P2 & 0xFF00) >> 8;
            value[9] = (P2 & 0x00FF);
          
    
           //  NRF_LOG_INFO("value1: %d     ",adc_value  );
     //NRF_LOG_INFO("value2: %d     ",  value[0]);
     //NRF_LOG_INFO("value3: %d",  value[1]);
    
       // if((SAADC_SAMPLES_IN_BUFFER*2) <= 20) 
      //      {
        //        bytes_to_send = 4;
        //    }
        //    else 
         //   {
         //       bytes_to_send = 1;
         //   }      
    
       
         //ble_nus_data_send(&m_nus, &value[1], &bytes_to_send , m_conn_handle);
             
             
             //err_code = ble_nus_data_send(&m_nus, &adc_value, &bytes_to_send, m_conn_handle);
    
    
            m_adc_evt_counter++;
    
            
        }
    }
    
    
    
    
    
    void saadc_init(void)
    {
             ret_code_t err_code;
    
    
             //TEMP 1
             nrf_saadc_channel_config_t channel_0_config =
             NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
    
             //TEMP2
               nrf_saadc_channel_config_t channel_1_config =
             NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);
    
             //TEMP3
               nrf_saadc_channel_config_t channel_2_config =
             NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
    
               nrf_saadc_channel_config_t channel_3_config =
             NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);
    
               nrf_saadc_channel_config_t channel_4_config =
             NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
    
        err_code = nrf_drv_saadc_init(NULL, saadc_callback);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(1, &channel_1_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(2, &channel_2_config);
        APP_ERROR_CHECK(err_code);
    
         err_code = nrf_drv_saadc_channel_init(3, &channel_3_config);
        APP_ERROR_CHECK(err_code);
    
         err_code = nrf_drv_saadc_channel_init(4, &channel_4_config);
        APP_ERROR_CHECK(err_code);
    
    
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
    
    }
    
    
    
    /**@brief Application main function.
     */
    int main(void)
    {
        bool erase_bonds;
    
        // Initialize.
        uart_init();
        log_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
        saadc_init();
    
    
        // Start execution.
        printf("\r\nUART started.\r\n");
        NRF_LOG_INFO("Debug logging for UART over RTT started.");
        advertising_start();
    
         //   nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
         //  spi_config.ss_pin   = SPI_SS_PIN;
        //    spi_config.miso_pin = SPI_MISO_PIN;
        //    spi_config.mosi_pin = SPI_MOSI_PIN;
        //    spi_config.sck_pin  = SPI_SCK_PIN;
        //    spi_config.mode = NRF_DRV_SPI_MODE_0;
        //    spi_config.frequency = NRF_DRV_SPI_FREQ_1M;
        //    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
    
        
          uint16_t bytes_to_send = 10;
    
        //  nrf_gpio_cfg_output(45);
       //   nrf_gpio_pin_write(45, level_0);
          
    
        // Enter main loop.
        for (;;)
        {     
         //  bytes_to_send = 19;
            
            nrf_drv_saadc_sample();
            nrf_delay_ms(2000);  
         //   DHT_task_callback(34, 10, 11, 12, 13);
         //   nrf_delay_ms(100);   
         //   DHT_task_callback(14, 15, 16, 17, 18);
         //   nrf_delay_ms(100);
            ble_nus_data_send(&m_nus, value, &bytes_to_send , m_conn_handle);
    
            
            
         //   bytes_to_send = 4;
    
         //   DHT_task_callback(2, 0, 1, 2, 3);
         //   nrf_delay_ms(100);
         //   ble_nus_data_send(&m_nus, value, &bytes_to_send , m_conn_handle);
          //  nrf_delay_ms(100);
          
            
    
         
           //  energy_measurement();
            // nrf_delay_ms(1000);
             idle_state_handle();
        }
    }
    
    

  • Hello.

    I am fetching only 5 values in the call back event . T, T1, T2, P1, P2 . Then I just split the 16bit values into two 8 bit values . That's why : value [0-9]. 

    I see. My bad.

    Are you sure that you are using the correct pins? Note that the AIN0-AIN4 are not the same as P0.00-P0.04.

    AIN0: P0.02
    AIN1: P0.03
    AIN2: P0.04
    AIN3: P0.05
    AIN4: P0.28

    Which means that your setup is:

    Ch.0: P0.28
    Ch.1: P0.03
    Ch.2: P0.04
    Ch.3: P0.05
    Ch.4: P0.02

    A couple of mentions regarding your main loop (for(;;)):

    I see that you call nrf_drv_saadc_sample(), and then nrf_delay_ms(2000);

    nrf_drv_saadc_sample() will do one sample. Note that you need SAMPLES_IN_BUFFER samples before you get the saadc_callback() callback. This means that you will only get this callback every 10th second, while you are sending the data every 2nd second. Not a problem in itself, but you should know that you only update the values in value[0-9] every 5th nrf_drv_saadc_sample();

    Another problem may be the nrf_delay_ms(2000). I am surprised if this works well. nrf_delay_ms(n) will keep the CPU running for n ms, without doing anything, blocking the softdevice, and drawing quite a bit of current. Hence, neither the softdevice nor the current consumption are particularly found of this function.

    You can expect to see disconnects from the device you are connected to, and that this project will reset when you are connected, because the softdevice is missing time critical events.

    Instead of using nrf_delay_ms, you should use a timer with a timeout callback. There are two different approaches to this:

    1: You can use the app_timer like it is used in the SDK\examples\ble_peripheral\ble_app_hrs example. Here the timer is used to update the battery service (note that it is only emulating battery values).

    2: You can use the timer together with ppi to trigger the nrf_drv_saadc_sample() calls, like it is done in the SDK\examples\peripheral\saadc example. 

    Then you can use the saadc callback function to set a flag telling the main loop that you should send a notification. Something like this:

    #include "something.h"
    ...
    
    static volatile bool m_send_data = false;
    
    static void saadc_callback(...)
    {
        ...
        m_send_data = true;
    }
    
    static void saadc_init(...)
    {
        ...
    }
    
    static void saadc_start(...)
    {
        ...
    }
    
    int main(void)
    {
        ...
        for(;;)
        {
            if (m_send_data)
            {
                m_send_data = false;
                ble_nus_data_send(...);
            }
            idle_state_handle();
        }
    }

    Best regards,

    Edvin

  • Very well explained Edvin. Thanks.

    So, I don't want the samples after every 10th second. I want them all at 1 second interval . What will be the best way to do so ? As you said, if I use app timer and set an interval of 1 sec. Will it work? And also, what should should be my timeout handler function? saadc_callback or nrf_drv_saadc_sample()  .

    Thanks,

  • The saadc will fetch one sample from every channel you have initialized when you call nrf_drv_saadc_sample(), so if you have 5 channels, and SAMPLES_IN_BUFFER == 5, then you must call nrf_drv_saadc_sample every second if you want to get a measurement from all channels every second. 

    please have a look at the saadc example in SDK\examples\peripheral\saadc

    If you copy the functions:

    saadc_sampling_event_init();
    saadc_sampling_event_enable();

    and only change this line in saadc_sampling_event_init():

    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);

    to

    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 1000);

    It will trigger one sampling every second.

Reply
  • The saadc will fetch one sample from every channel you have initialized when you call nrf_drv_saadc_sample(), so if you have 5 channels, and SAMPLES_IN_BUFFER == 5, then you must call nrf_drv_saadc_sample every second if you want to get a measurement from all channels every second. 

    please have a look at the saadc example in SDK\examples\peripheral\saadc

    If you copy the functions:

    saadc_sampling_event_init();
    saadc_sampling_event_enable();

    and only change this line in saadc_sampling_event_init():

    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);

    to

    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 1000);

    It will trigger one sampling every second.

Children
No Data
Related