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

Read a values of anolg input ( nRF52840, S140 )

Hi, I'm using an nRF52840 S140 card. I'm currently on saadc code, I want to be able to retrieve values from an analog input, but I have questions about this.

-> When I do not short-circuit the p0.02 a VCC and GND I get a value ranging from 18 to 21, when I short-circuit the p0.02 to VCC I get 580 to what these values correspond?

->I have a 3V analog generator that I plug into the P0.02 and GND of the board and I get values ranging from -2 to 2 why?

-> How to get the right value from the generator.

here the code that i use : 

#define SAMPLES_IN_BUFFER 5
volatile uint8_t state = 1;

static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(4);
static nrf_saadc_value_t     m_buffer_pool[2][SAMPLES_IN_BUFFER];
static nrf_ppi_channel_t     m_ppi_channel;
static uint32_t              m_adc_evt_counter;
int16_t values;

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}

void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

    APP_ERROR_CHECK(err_code);
}

void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event every 40ms */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 100);
    nrf_drv_timer_extended_compare(&m_timer,NRF_TIMER_CC_CHANNEL0,ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();
		 	

    /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    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);
		
		saadc_sampling_event_enable();
}





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;

        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);
        m_adc_evt_counter++;	
				values = p_event->data.done.p_buffer[1];
			
    }
}


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);

    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &channel_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);
	
		saadc_sampling_event_init();

}

thank's

  • When you short to ground you will see the dc offset of the saadc. All adc's have some offset. There is a cal process in the documentation that will reduce the offset. The reason it fluctuates a little is because the quant noise floor is random. This is why most adc designs throw away the bottom 1 or 2 bits.

    The max number when connected to nrf_vdd is determined by the prescaler value and the bit width of the sample. 

    For your analog generator, you need to have the max frequency of the generator inside the nyquist window of the saadc. This is basic sampling theory and would be useful to familiarize yourself with. When this is not true, since the input of an saadc is switched capacitive you will only see the mean value which for an ac signal is zero. Or in this case a couple of quanta.

  • I should add that the reason you don't see a fullscale reading when connected to vdd is due to both the prescaler and the saadc reference. Normal the saadc uses an internal reference so the ref voltage doesn't vary with vdd. This is an issue in battery operated designs. However, in the config register you can choose vdd as the reference if you choose.

Related