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!

  • 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! 

  • The two other pins? AIN6 and AIN7?

    Just change the channel_X_config in saadc_init() to use NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(pin_nr) with the correct pin_nr. You can find the list of the AIN pins in the list on this page.

    AIN6 = P0.30 and AIN7 = P0.31.

     

    You can either add them to the list in saadc_init, like the other are added:

    nrf_saadc_channel_config_t channel_N_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN#);

    and use:

    nrf_drv_saadc_channel_init(channel_nr, &channel config);

     

    Note that you should match your #define SAMPLES_IN_BUFFER with the number of channels that you use. If you have 6 channels, and SAMPLES_IN_BUFFER is 5, then you will get the values from channel 0, 1, 2, 3, 4 in the first event, and 5, 0, 1, 2, 3 in the second, 4, 5, 0, 1, 2 in the third, and so on.

     

    Best regards,

    Edvin

  • 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;
            uint16_t adc_value;
            uint8_t value[SAADC_SAMPLES_IN_BUFFER*2];
            uint8_t bytes_to_send;
         
            // set buffers
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
    						
            // print samples on hardware UART and parse data for BLE transmission
            printf("ADC event number: %d\r\n",(int)m_adc_evt_counter);
            for (int i = 0; i < SAADC_SAMPLES_IN_BUFFER; i++)
            {
                printf("%d\r\n", p_event->data.done.p_buffer[i]);
    
                adc_value = p_event->data.done.p_buffer[i];
                value[i*2] = adc_value;
                value[(i*2)+1] = adc_value >> 8;
            }
    				
            // Send data over BLE via NUS service. Makes sure not to send more than 20 bytes.
            if((SAADC_SAMPLES_IN_BUFFER*2) <= 20) 
            {
                bytes_to_send = (SAADC_SAMPLES_IN_BUFFER*2);
            }
            else 
            {
                bytes_to_send = 20;
            }
            err_code = ble_nus_string_send(&m_nus, value, bytes_to_send);
            if (err_code != NRF_ERROR_INVALID_STATE) 
            {
                APP_ERROR_CHECK(err_code);
            }
    						
            m_adc_evt_counter++;
        }
    }

    Hello Edvin, thank you for your explanation. Regarding this attached saadc callback function. When is this function called, which interrupt calls this function? and also how do i convert the raw data into voltage. just take the data, then multiply by 5V and divide by 1023 ? or does it function differently? Thanks and Regards! 

  • Hello,

    In the SAADC example you can see two functions which sets up and enables the saadc callback:

    saadc_sampling_event_init() and saadc_sampling_event_enable().

    What they do is that they set up a timer and a PPI, and connect the two. This means that the timer interrupt is not called in the application, but when the timeout occurs, the chip will automatically call nrfx_saadc_sample().

    When this function is called N times, where N is the size of your SAADC buffer, that is N = SAMPLES_IN_BUFFER, you will get the callback function.

    I don't know whether you are familiar with the PPI, but it is a module which, when enabled, can perform tasks without involving the CPU. In this case, it works a bit like an advanced timer.

     

    I really recommend that you use this implementation to trigger the samples. It will not work to call nrfx_saadc_sample() N times in a row in the application, because the sample has to finish before calling nrfx_saadc_sample again.

     

    Regarding the conversion from the raw SAADC value to voltage, there are a few things to take into consideration:

    Your resolution (by default set to 10 bits, your gain, usually set to 1/6. 

    Please see this scheeme:

    http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fsaadc.html&anchor=saadc_overview

     

    From the link: 

    RESULT = [V(P) – V(N) ] * GAIN/REFERENCE * 2(RESOLUTION - m)

    Which means that V(P) - V(N) = RESULT/ (GAIN/REFERENCE * 2(RESOLUTION - m))


    The result is linear, so you can also do some measurements to known voltages (using a voltmeter), and map the result to voltage using this.


    Best regards,
    Edvin

     

Related