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

nRF52832 SAADC sampling

Hi,

I have been able to use SAADC to measure temperature, but my code does not behave in the way I expect it to! In the config file I have the following settings set:

#define SAADC_CONFIG_RESOLUTION      NRF_SAADC_RESOLUTION_10BIT
#define SAADC_CONFIG_OVERSAMPLE      NRF_SAADC_OVERSAMPLE_DISABLED
#define SAADC_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW

here is my code:

#define SAMPLES_IN_BUFFER 5

static nrf_saadc_value_t       m_buffer_pool[2][SAMPLES_IN_BUFFER];
static int temp_rotor;

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        int avg_sample = 0;
        float steinhart;
        float sampleAVG;
        int i;
        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);

        for (i = 0; i < SAMPLES_IN_BUFFER; i++)	
        {
              avg_sample += p_event->data.done.p_buffer[i]; // take N samples in a row
        }
        avg_sample /= i; // average all the samples out
        printf("Avg_sample: %d\r\n", avg_sample);
			
        sampleAVG = 810 / avg_sample - 1;		//VDD = 2.85V
        sampleAVG = SERIESRESISTOR / sampleAVG;
        
        steinhart = 0;
        steinhart = sampleAVG / THERMISTORNOMINAL;   // (R/Ro)
        steinhart = log(steinhart);                  // ln(R/Ro)
        steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
        steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
        steinhart = 1.0 / steinhart;                 // Invert
        steinhart -= 273.15;                         // convert to C
        temp_rotor = (int)steinhart;             //convert float to int
    }
}

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);
	
    channel_config.gain = NRF_SAADC_GAIN1_6;

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

void saadc_sampling_trigger(void)
{
    ret_code_t err_code;
	//Event handler is called immediately after conversion is finished.
	err_code = nrf_drv_saadc_sample(); // Check error
	APP_ERROR_CHECK(err_code);
}

int main(void)
{
	uart_config();
	printf("SAADC Started...\r\n");
	saadc_init();
	while (true)
    {
		saadc_sampling_trigger();
		printf("Room Temperature: %d\r\n", temp_rotor);
		nrf_delay_ms(1000);       //waiting a second
	}

}

When I run the code, I get the following text on Termite terminal(each line is printed every 1 second): Termite

I expected to see something like this instead:

Avg_sample: 409

Room Temperature: 24

Avg_sample: 400

Room Temperature: 25

Avg_sample: 393

Room Temperature: 26

Avg_sample: 377

Room Temperature: 28

What am I doing wrong? why is the Avg_sample(ADC value) updated so slowly?

How can I implement a code in a way that every time I make a call to nrf_drv_saadc_sample() I get 5 samples of ADC value so I could average them and convert the averaged value to temperature?

If I want to use just one buffer for this code, how should I change it?

Parents
  • Hi

    Every time you call nrf_drv_saadc_sample(), the SAADC will sample once and it will transfer one value to RAM. You will only get SAADC event every fifth time you sample because your buffer size is set to 5. If you set the buffer size to 1, you will get a callback after every SAADC sample from nrf_drv_saadc driver.

    If you enable oversample, the SAADC will output an averaged value to RAM every "oversample" time. If you also enable BURST mode, the SAADC will sample "oversample" number of times as fast as it can when you call nrf_drv_saadc_sample() once, and then it will output on averaged value to RAM.

    If you like to average numbers in your code, I suspect you can do that by decreasing the buffer size to 1 to receive event for every sample, and then do the averaging in the saadc handler.

    Update 21.6.2016
    With oversampling enabled, noise is averaged, and as a result you will see less noise and more stable measurement. There is however a limit to how much accuracy you can get with oversampling. High oversampling will close to cancel out any white noise, while any noise that is not white will not be cancelled with oversampling. General rule is that if there is purely white noise present, quadrupling oversampling will reduce the noise level by 50%, while setting oversampling to 16x will leave 25% of the white noise. There is a limit though how much noise can be reduced. Highest ENOB can be achieved with 14-bit sampling resolution and high oversampling value, e.g. 128X or 256X. Around 11.3 ENOB is the highest obtainable for the SAADC on nRF52832 with 14-bit resolution and high oversampling, could be higher or lower for a single IC. With 12-bit resolution and 4x oversampling, you should get around 10.5 ENOB as stated here

    Oversampling has drawbacks. One is that it takes longer time, therefore it decreases the maximum sampling rate. Another is that it consumes more current.

    That is correct, oversampling should not be combined with scan mode. That does not mean that you can not sample on multiple pins with oversampling enabled. It is possible to configure the SAADC to sample on one pin, then reconfigure it for another pin with oversampling and sample on that pin.

    • With oversampling 8x and buffer size of 1, the SAADC will collect 8 samples, take the averaged value and output that averaged value to the RAM buffer. The application will get a notification as the buffer is full with only one averaged sample.
    • With oversampling disabled and buffer size of 8, SAADC will output 8 values to the RAM buffer, then it will notify the application that the buffer is full with 8 values, but the 8 values are not averaged.
  • Well yes, on the nrf51 i used to do the pin switching, but that gave me some weird outliers. Probably because i'm sampling on a few kHz.

Reply Children
No Data
Related