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

How to identify adc value from its adc channel?

I use nRF52840 and SDK16 with S140 softdevice. I need 3 ADC ports. The initial code as follows.

static void adc_configure(void)
{
ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);
APP_ERROR_CHECK(err_code);

nrf_saadc_channel_config_t config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);

err_code = nrf_drv_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code);

config.pin_p = NRF_SAADC_INPUT_AIN0;
err_code = nrf_drv_saadc_channel_init(1, &config);
APP_ERROR_CHECK(err_code);

config.pin_p = NRF_SAADC_INPUT_AIN4;
err_code = nrf_drv_saadc_channel_init(2, &config);
APP_ERROR_CHECK(err_code);

err_code = nrf_drv_saadc_buffer_convert(&adc_buf[0], 1);
APP_ERROR_CHECK(err_code);

err_code = nrf_drv_saadc_buffer_convert(&adc_buf[1], 1);
APP_ERROR_CHECK(err_code);
}

I call the function of nrf_drv_saadc_sample() once 2 seconds.  And the event handler will be called 3 times. The function of saadc_event_handler will display the channel information.

But it shows as follows: How to identify adc value from which channel? Why the channel isn't display 0/1/2?

<info> app: channel=156

<info> app: channel=158

<info> app: channel=156

void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
{
NRF_LOG_INFO("channel=%d", p_event->data.limit.channel);

....
}

  • Hello,

    I see that you print using the p_event->data.limit.channel, but I suspect that this is not a limit event. You can check this like this:

    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
        if (p_event->type == NRF_DRV_SAADC_EVT_LIMIT)
        {
            NRF_LOG_INFO("reached limit on channel %d", p_evt->data.limit.channel);
            return;
        }
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
            ret_code_t err_code;
    
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 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 < SAMPLES_IN_BUFFER; i++)
            {
                NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
            }
            m_adc_evt_counter++;
        }
    }

    You can't use the p_evt->data.limit. ... pointer if the event is not a NRFX_SAADC_EVT_LIMIT event, but a NRFX_SAADC_EVT_DONE event. In that case, the data in this pointer is not what you think it is.

    So in the "normal" event callbacks, you don't have a field saying what channel the measurements come from. But they will always come in the order of the channels. This is why you should have SAMPLES_IN_BUFFER = n*number of channels. Let us say you have 3 channels, and n=1, then SAMPLES_IN_BUFFER should be 3.

    If so, then p_buffer[0] will always belong to channel 0, buffer[1] to channel 1 and buffer[2] to channel 2. 

    If you set SAMPLES_IN_BUFFER = 4, then in the first event:

    buffer[0] belongs to channel 0,
    buffer[1] belongs to channel 1,
    buffer[2] belongs to channel 2,
    buffer[3] belongs to channel 0

    But in the next event, this will be shifted by one:

    buffer[0] belongs to channel 1,
    buffer[1] belongs to channel 2,
    buffer[2] belongs to channel 0,
    buffer[3] belongs to channel 1,

    This is because the channels are sampled in the order of the channels, but the buffer isn't aware of how many channels that are in use.

    Best regards,

    Edvin

  • Thank you very much. Another question. How to sample ADC at different times? For example, I want to sample ADC at NRF_SAADC_INPUT_AIN1 once 2 seconds. sample ADC at NRF_SAADC_INPUT_AIN0 and NRF_SAADC_INPUT_AIN4  once 50us. 

  • That is not possible with the ADC. You must then sample all 3 every 50µs. 

    That is at least almost true. You can uninit and init the AIN1 only when you want to sample it, but I don't think that is any more power efficient than just sampling AIN1, and discard it later, than doing changes to it all the time. Also, you would have to be very careful, what buffer item belongs to what channel when you add and remove AIN1. 

Related