timer tasked DPPI saadc read , how to evaluate sample rate ?

Hello,

I changed saadc.zip for nRF5340DK and my main.c is like following:

/*
 * Copyright (c) 2019 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr.h>

#include <helpers/nrfx_gppi.h>

#if defined(DPPI_PRESENT)
#include <nrfx_dppi.h>
#else
#include <nrfx_ppi.h>
#endif

//#include <nrfx_ppi.h>
#include <nrfx_saadc.h>
#include <nrfx_timer.h>

#include <logging/log.h>
LOG_MODULE_REGISTER(nrfx_sample, LOG_LEVEL_INF);

#define SAADC_CHANNEL_NUM 	0
#define SAMPLES_IN_BUFFER 	1
#define SAMPLE_RATE 		200UL	//200uS sampling desired	

int16_t saadc_buf1[SAMPLES_IN_BUFFER];
int16_t saadc_buf2[SAMPLES_IN_BUFFER];

nrfx_timer_t timer1 = NRFX_TIMER_INSTANCE(1);		//timer instance

int64_t prevTime, elapsedTime = 0;
int64_t prevTicks, elapsedTicks = 0;


void saadc_evt_handler(nrfx_saadc_evt_t const * p_event)
{
	printk("saadc_evt_handler\n");
	printk("p_event->type = %d\n", p_event->type);


	nrfx_err_t err = NRFX_SUCCESS;
	static uint8_t counter = 0;


	if(p_event->type == NRFX_SAADC_EVT_DONE)
	{		
		elapsedTime = k_uptime_get() - prevTime;
		prevTime = k_uptime_get();
		printk("elapsedTime %lld\n", elapsedTime);

		elapsedTicks = k_uptime_ticks() - prevTicks;
		prevTicks = k_uptime_ticks();
		printk("elapsedTicks %lld\n", elapsedTicks);
		//CONFIG_SYS_CLOCK_TICKS_PER_SEC 32768 32.768kHz

		printk("SAADC sampled: \n");
		for(uint8_t i = 0; i < p_event->data.done.size; i++)
		{
			printk("%hi\n", p_event->data.done.p_buffer[i]);

		}
	}
	else if(p_event->type == NRFX_SAADC_EVT_CALIBRATEDONE)
	{
		printk("SAADC calibrated.\n");
	}
	else if(p_event->type == NRFX_SAADC_EVT_BUF_REQ)
	{
		printk("SAADC buffer requested\n");
		counter++;

		if(counter%2)
		{
			err = nrfx_saadc_buffer_set(saadc_buf1, SAMPLES_IN_BUFFER);
			if(err != NRFX_SUCCESS)
			{
				LOG_ERR("Error! Could not set buffer2: %d\n", err);
			}
		}
		else
		{
			err = nrfx_saadc_buffer_set(saadc_buf2, SAMPLES_IN_BUFFER);
			if(err != NRFX_SUCCESS)
			{
				LOG_ERR("Error! Could not set buffer1: %d\n", err);
			}
		}
		
	}
	else if(p_event->type == NRFX_SAADC_EVT_FINISHED)
	{
		printk("SAADC finished sampling\n\n");
	}
}

void timer1_evt_handler(nrf_timer_event_t event_type, void * p_context)	//called when timer is triggered
{
	// Nothing to do here, the timer's IRQ is not enabled
	printk("timer1_evt_handler\n");

}

void timer_init(void)
{
	nrfx_err_t err = NRFX_SUCCESS;

	nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
	
	timer_cfg.frequency          = NRF_TIMER_FREQ_16MHz;
    timer_cfg.mode               = NRF_TIMER_MODE_TIMER;
    timer_cfg.bit_width          = NRF_TIMER_BIT_WIDTH_32;		
    timer_cfg.interrupt_priority = 0;//NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY;

	err = nrfx_timer_init(&timer1, &timer_cfg, timer1_evt_handler);

	uint32_t time_ticks;
	time_ticks = nrfx_timer_us_to_ticks(&timer1, SAMPLE_RATE);
	printk("time_ticks = %u\n", time_ticks);

	if(err != NRFX_SUCCESS)
	{
		LOG_ERR("Error! Could not initialize TIMER1: %d\n", err);
	}
	nrfx_timer_extended_compare(&timer1, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);	

}

void saadc_init(void)
{
	nrfx_err_t err = NRFX_SUCCESS;
	nrfx_saadc_channel_t saadc_channel = NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN0, SAADC_CHANNEL_NUM);
	nrfx_saadc_adv_config_t saadc_adv_cfg = NRFX_SAADC_DEFAULT_ADV_CONFIG;
	saadc_adv_cfg.start_on_end = true;
	
	err = nrfx_saadc_init(IRQ_PRIO_LOWEST);
	if(err != NRFX_SUCCESS)
	{
		LOG_ERR("Error! Could not initialize SAADC: %d\n", err);
	}

	err = nrfx_saadc_offset_calibrate(NULL);
	if(err != NRFX_SUCCESS)
	{
		LOG_ERR("Error! Could not calibrate offset: %d\n", err);
	}

	err = nrfx_saadc_channel_config(&saadc_channel);
	if(err != NRFX_SUCCESS)
	{
		LOG_ERR("Error! Could not configure SAADC channels: %d\n", err);
	}	

	err = nrfx_saadc_advanced_mode_set((1 << SAADC_CHANNEL_NUM), NRF_SAADC_RESOLUTION_10BIT, &saadc_adv_cfg, saadc_evt_handler);
	if(err != NRFX_SUCCESS)
	{
		LOG_ERR("Error! Could not set advanced SAADC mode: %d\n", err);
	}

	err = nrfx_saadc_buffer_set(saadc_buf1, SAMPLES_IN_BUFFER);
	if(err != NRFX_SUCCESS)
	{
		LOG_ERR("Error! Could not set buffer1: %d\n", err);
	}

	err = nrfx_saadc_buffer_set(saadc_buf2, SAMPLES_IN_BUFFER);
	if(err != NRFX_SUCCESS)
	{
		LOG_ERR("Error! Could not set buffer2: %d\n", err);
	}

	err = nrfx_saadc_mode_trigger();
	if(err != NRFX_SUCCESS)
	{
		LOG_ERR("Error! Could trigger mode: %d\n", err);
	}	
}

void main(void)
{
	printk("nrfx_saadc sample on %s\n", CONFIG_BOARD);

	nrfx_err_t err;

	/* Connect SAADC IRQ to nrfx_saadc_irq_handler */
	IRQ_CONNECT(SAADC_IRQn, IRQ_PRIO_LOWEST, nrfx_isr, nrfx_saadc_irq_handler, 0);

	timer_init();
	saadc_init();

		/* Allocate a (D)PPI channel. */
#if defined(DPPI_PRESENT)
	uint8_t channel;
	err = nrfx_dppi_channel_alloc(&channel);
#else
	nrf_ppi_channel_t channel;
	err = nrfx_ppi_channel_alloc(&channel);
#endif

	// /* Allocate a PPI channel. */
	// nrf_ppi_channel_t channel;
	// err = nrfx_ppi_channel_alloc(&channel);

	if (err != NRFX_SUCCESS) {
		LOG_ERR("(D)PPI channel allocation error: %08x", err);
		return;
	}

	/* Configure endpoints of the channel so that the TIMER1 CAPTURE0
	 * event is connected with the SAADC SAMPLE task. This means that each time
	 * TIMER1 reaches it's set compare value, the SAADC will sample all 
	 * enabled channel once.
	 */
	nrfx_gppi_channel_endpoints_setup(channel,
		nrfx_timer_event_address_get(&timer1, NRF_TIMER_EVENT_COMPARE0),
			nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_SAMPLE));


	// err = nrfx_ppi_channel_enable(channel);

	// if (err != NRFX_SUCCESS) {
	// 	LOG_ERR("Failed to enable PPI channel, error: %08x", err);
	// 	return;
	// }
	// printk("PPI configured\n");

		/* Enable (D)PPI channel. */
#if defined(DPPI_PRESENT)
	err = nrfx_dppi_channel_enable(channel);
#else
	err = nrfx_ppi_channel_enable(channel);
#endif
	if (err != NRFX_SUCCESS) {
		LOG_ERR("Failed to enable (D)PPI channel, error: %08x", err);
		return;
	}

	LOG_INF("(D)PPI configured, leaving main()");

	nrfx_timer_enable(&timer1);
	printk("TIMER1 started\n");

	while(1)
	{
		k_msleep(3000);
		printk("while sleep\n");
	}
}

At the end of my developement I would like to sample ADC at 200us and the buffer should have 1600 values and when full, transfer via BLE or perhaps evaluate right on the nRF5340 chip. Right now I dont know in detail what has to be done for evaluation purpose with the sampled buffer.

This DPPI featurte sound like powerfull magic! 

There are a few problems or simple my lack of understanding:

how can I evaluate elapsed time between two ADC samples when this is happening without CPU involvement like described in

The distributed programmable peripheral interconnect (DPPI) enables peripherals to interact autonomously with each other by using tasks and events, without any intervention from the CPU DPPI

I mean how to get at the place / line where adc read task is happening with debugger or I dont know ? 

&

I tried sitting at the 

if(p_event->type == NRFX_SAADC_EVT_DONE)
	{		
		elapsedTime = k_uptime_get() - prevTime;
		prevTime = k_uptime_get();
		printk("elapsedTime %lld\n", elapsedTime);

		elapsedTicks = k_uptime_ticks() - prevTicks;
		prevTicks = k_uptime_ticks();
		printk("elapsedTicks %lld\n", elapsedTicks);
		//CONFIG_SYS_CLOCK_TICKS_PER_SEC 32768 32.768kHz

		printk("SAADC sampled: \n");
		for(uint8_t i = 0; i < p_event->data.done.size; i++)
		{
			printk("%hi\n", p_event->data.done.p_buffer[i]);

		}
	}

and printk the time in ms or the ticks between every NRFX_SAADC_EVT_DONE , however at SAMPLE_RATE 200us or 1 000 000 us the measured time isnt accurate like desired Disappointed.

What I m doing wrong ?

Not that important but ther is some example code from tutorial nrf52 EXTERN, I think the code is very similar, only 

nrfx_timer_extended_compare(&timer0, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

enable_int parameter is set to true. And for sure the 

nrfx_gppi_channel_endpoints_setup 

isnt done because only blink LED.

When I set up enable_int to true, than I got the error

Thanks in advance,

Christoph

Parents
  • Hi there,

    Which NCS version are you using?

    and printk the time in ms or the ticks between every NRFX_SAADC_EVT_DONE , however at SAMPLE_RATE 200us or 1 000 000 us the measured time isnt accurate like desired Disappointed.

    Not that important but ther is some example code from tutorial nrf52 EXTERN, I think the code is very similar, only 

    Fullscreen
    1
    nrfx_timer_extended_compare(&timer0, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    nrfx_timer_extended_compare(&timer0, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

    enable_int parameter is set to true. And for sure the 

    What do you mean? Doesn't the program enter the event handler? What do you get at the elapsed time?

    Is my understanding correct in that you want to measure the elapsed time after a SAADC sample event has ended and until the next one starts?

    regards

    Jared 

  • ncs v1.9.1

    I mean I want to verify the timestamp between two ADC samples. So time_ADC(n+1) - timeADC(n) = 200uS or whatever defined in SAMPLE_RATE.

    When p_event->type == NRFX_SAADC_EVT_DONE

    if(p_event->type == NRFX_SAADC_EVT_DONE)
    	{		
    		elapsedTime = k_uptime_get() - prevTime;
    		prevTime = k_uptime_get();
    		printk("elapsedTime %lld\n", elapsedTime);
    
    		elapsedTicks = k_uptime_ticks() - prevTicks;
    		prevTicks = k_uptime_ticks();
    		printk("elapsedTicks %lld\n", elapsedTicks);
    		//CONFIG_SYS_CLOCK_TICKS_PER_SEC 32768 32.768kHz
    
    		printk("SAADC sampled: \n");
    		for(uint8_t i = 0; i < p_event->data.done.size; i++)
    		{
    			printk("%hi\n", p_event->data.done.p_buffer[i]);
    
    		}
    	}

    the buffer is full and it prints out. Okay , but is it possible to see where the buffer is filled with ADC read's, or is this some process in the nrfx_dppi library I can not evaluate the easy way I think.

    Doesn't the program enter the event handler?

    Yes the programm is working like expected, but the timestemp issue described above is untransparent.

    What do you get at the elapsed time?

    not that accurate Disappointed.

    Just to get clear, the event in the event handler is not that important for me. I mean, yes it should not be that much delay after fullfilled when further evaluation takes place. Furthermore interest is in the way the buffer gets fullfiled in considerations of timestep (discretisation).

    Thank you for your help,

    Christoph

  • Christoph,

    I see, you want to verify that the sampling interval is actually 200 µs. From the log output I see that you get elapsed time = 2988 ms which is far from 200 µs. I'm not sure exactly why you're getting that high numbers. I tried pasting your main.c into the saadc.zip that you shared and tried to reproduce your results but got far less values on the elapsed time:

    I expect the elapsed time using this method to be a bit bigger than 200 µs due to the added overhead, but still not as big as 14 ms. At the moment I'm not sure why it returns that high numbers. 

    However here is a better suggestion:

     You asked if it was possible to use the DPPI feature to verify the sampling rate. What you can do is to fork the Timer COMPARE event that you use to drive the SAADC to toggle a GPIO by using the GPIOTE peripheral. This means that each time a COMPARE event is generated, it will toggle a GPIO synchronized with starting the SAADC. The interval between each time the GPIO is toggled, is therefore equal to the sampling interval, which means that you can measure the GPIO toggling interval externally to verify the sampling interval.

    Hope this made sense. 

    regards

    Jared 

  • Hey Jared,

    I see that you get elapsed time = 2988 ms which is far from 200 µs. I'm not sure exactly why you're getting that high numbers.

    this was my fault! I changed the #define s to 

    Though when I change to the #define 200UL buffer 1 sample I get the same 

    Uff so its not that simple to get accurate sampling when using ADC from nrf5340 or am I using the wrong code example?

    You mentioned

    You asked if it was possible to use the DPPI feature to verify the sampling rate.

    no no , I would like to use DPPI feature for SAADC , so in the background SAADC its always sampling at 200us and when the buffer is full I can use it for evaluation. 

    You said overhead , most important for my further application is the propertie in always same sampling and if there is delay in broadcasting the full buffer this would not be that critical.

    Any suggestions ?

    Thank you in advance,

    Christoph

    Christoph

Reply
  • Hey Jared,

    I see that you get elapsed time = 2988 ms which is far from 200 µs. I'm not sure exactly why you're getting that high numbers.

    this was my fault! I changed the #define s to 

    Though when I change to the #define 200UL buffer 1 sample I get the same 

    Uff so its not that simple to get accurate sampling when using ADC from nrf5340 or am I using the wrong code example?

    You mentioned

    You asked if it was possible to use the DPPI feature to verify the sampling rate.

    no no , I would like to use DPPI feature for SAADC , so in the background SAADC its always sampling at 200us and when the buffer is full I can use it for evaluation. 

    You said overhead , most important for my further application is the propertie in always same sampling and if there is delay in broadcasting the full buffer this would not be that critical.

    Any suggestions ?

    Thank you in advance,

    Christoph

    Christoph

Children
No Data
Related