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 

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

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

  • Hey Jared again,

    so I used the nrfx use example for the suggestion you mentioned above. 

    Ma code now

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr.h>
    
    #include <nrfx_gpiote.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 		1000000UL	//200uS sampling desired	
    
    #define INPUT_PIN	DT_GPIO_PIN(DT_ALIAS(sw0), gpios)
    #define OUTPUT_PIN	DT_GPIO_PIN(DT_ALIAS(led0), gpios)
    
    static void button_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
    	LOG_INF("GPIO input event callback");
    }
    
    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);
    
    	/* Connect GPIOTE_0 IRQ to nrfx_gpiote_irq_handler */
    	//IRQ_CONNECT initialize an interrupt handler, handler handls interrupts
    	IRQ_CONNECT(
    		DT_IRQN(DT_NODELABEL(gpiote)),
    		    DT_IRQ(DT_NODELABEL(gpiote), priority),
    		    nrfx_isr, nrfx_gpiote_irq_handler, 0);
    
    	timer_init();
    	saadc_init();
    
    	/* Initialize GPIOTE (the interrupt priority passed as the parameter
    	 * here is ignored, see nrfx_glue.h).
    	 */
    	err = nrfx_gpiote_init(0);
    
    	if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_gpiote_init error: %08x", err);
    		return;
    	}
    
    	if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_gpiote_in_init error: %08x", err);
    		return;
    	}
    
    	nrfx_gpiote_out_config_t const out_config = {
    		.action = NRF_GPIOTE_POLARITY_TOGGLE,
    		.init_state = 1,
    		.task_pin = true,
    	};
    
    	err = nrfx_gpiote_out_init(OUTPUT_PIN, &out_config);
    
    	if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_gpiote_out_init error: %08x", err);
    		return;
    	}
    
    	nrfx_gpiote_in_event_enable(INPUT_PIN, true);
    	nrfx_gpiote_out_task_enable(OUTPUT_PIN);
    
    	LOG_INF("nrfx_gpiote initialized");
    
        /* Allocate a (D)PPI channel. */
    #if defined(DPPI_PRESENT)
    	uint8_t channel;
    	uint8_t channel_GPIOTE;
    	err = nrfx_dppi_channel_alloc(&channel);
    	err = nrfx_dppi_channel_alloc(&channel_GPIOTE);
    #else
    	nrf_ppi_channel_t channel;
    	err = nrfx_ppi_channel_alloc(&channel);
    #endif
    
    	if (err != NRFX_SUCCESS) {
    		LOG_ERR("(D)PPI channel allocation error: %08x", err);
    		return;
    	}
    
    
    	/* Configure endpoints of the channel so that the input pin event is
    	 * connected with the output pin OUT task. This means that each time
    	 * the button is pressed, the LED pin will be toggled.
    	 */
    	nrfx_gppi_channel_endpoints_setup(channel_GPIOTE,
    		nrfx_timer_event_address_get(&timer1, NRF_TIMER_EVENT_COMPARE0),
    			nrfx_gpiote_out_task_addr_get(OUTPUT_PIN));
    
    	/* 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));
    
    		/* Enable (D)PPI channel. */
    #if defined(DPPI_PRESENT)
    	err = nrfx_dppi_channel_enable(channel);
    	err = nrfx_dppi_channel_enable(channel_GPIOTE);
    #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");
    	}
    }
    

    the difficulty now

    	/* Configure endpoints of the channel so that the input pin event is
    	 * connected with the output pin OUT task. This means that each time
    	 * the button is pressed, the LED pin will be toggled.
    	 */
    	nrfx_gppi_channel_endpoints_setup(channel_GPIOTE,
    		nrfx_timer_event_address_get(&timer1, NRF_TIMER_EVENT_COMPARE0),
    			nrfx_gpiote_out_task_addr_get(OUTPUT_PIN));
    
    	/* 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));

    depends on which nrfx_gppi_channel_endpoints_setup() is setup before. So timer1 COMPARE triggers the LED or the SAADC but unfoftunately not both.

    Is this the right way or is it even possible to use timer1 COMPARE0 event for both tasks?

    Thank you in advance,

    Christoph

  • Hi Cristoph,

    ChrtistophAT said:
    so I used the nrfx use example for the suggestion you mentioned above. 

    That's a great start. 

    In the documentation it is stated:

    Use PPI and DPPI drivers directly. This layer is provided only to help create generic code that can be built for SoCs equipped with either of these peripherals. When using this layer, take into account that there are significant differences between the PPI and DPPI interfaces that affect the behavior of this layer.

    One difference is that PPI allows associating of one task or event with more than one channel, whereas DPPI does not allow this. In DPPI, the second association overwrites the first one. Consequently, this helper layer cannot be used in applications that need to connect a task or event to multiple channels.

    Another difference is that in DPPI one channel can be associated with multiple tasks and multiple events, while in PPI this is not possible (with the exception of the association of a second task as a fork). Because of this difference, it is important to clear the previous endpoints of the channel that is to be reused with some different ones. Otherwise, the behavior of this helper layer will be different, depending on the actual interface used: in DPPI the channel configuration will be extended with the new endpoints, and in PPI the new endpoints will replace the previous ones.

    Thus, using two different channels i.e. "channel_GPIOTE" and "channel" with  the same event "NRF_TIMER_EVENT_COMPARE0" is not supported with DPPI. Instead, you should use one channel and FORK to associate an additional task to the same channel by using nrfx_gppi_fork_endpoint_setup()

    regards

    Jared 

  • Hey Jared

    finished building up extern measurement trough myRIO FPGA LabView and everything works like expected Slight smile 200uS 

    Awesome !! So lets start datatransfer via BLE.

    Thanks for great help again,

    Christoph

Related