<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>SAADC scan mode of 3 channels --&amp;gt; buffer order swap</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/48783/saadc-scan-mode-of-3-channels----buffer-order-swap</link><description>Hi, 
 I already read all the forum posts about this buffer order swap problem of the SAADC. Especially this one: https://devzone.nordicsemi.com/f/nordic-q-a/20291/offset-in-saadc-samples-with-easy-dma-and-ble/79053#79053 
 I tried to implement the PPI</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Fri, 13 Sep 2019 15:22:55 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/48783/saadc-scan-mode-of-3-channels----buffer-order-swap" /><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/209678?ContentTypeID=1</link><pubDate>Fri, 13 Sep 2019 15:22:55 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:4798c7c0-61b9-4995-a0bd-772039361f12</guid><dc:creator>J&amp;#248;rgen Holmefjord</dc:creator><description>&lt;p&gt;Why do you trigger the START task in main after calibration? This should be done by&amp;nbsp;nrf_drv_saadc_buffer_convert() in the CALIBRATEDONE event in the handler, so there should be no need to trigger this manually. You should also be able to restart the PPI/sampling event from the callback, after setting up the new buffers.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/205449?ContentTypeID=1</link><pubDate>Thu, 22 Aug 2019 07:18:20 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:305fa50c-5ceb-4315-9a68-17d0aecd76bf</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;Hi Jorgen,&lt;/p&gt;
&lt;p&gt;Sorry for the late answer. I have now implemented your suggestion and here is my new code:&lt;/p&gt;
&lt;p&gt;PPI:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    uint32_t rtc_compare_event_addr = nrf_drv_rtc_event_address_get(&amp;amp;rtc, NRF_RTC_EVENT_COMPARE_0);//nrf_drv_timer_compare_event_address_get(&amp;amp;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(&amp;amp;m_ppi_channel_1);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel_1,
                                          rtc_compare_event_addr,
                                          saadc_sample_task_addr);
																					
    APP_ERROR_CHECK(err_code);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;SAADC:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;#define SAMPLES_IN_BUFFER 10
#define ADC_CHANNEL_COUNT 3

void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel_1);

    APP_ERROR_CHECK(err_code);
	
	nrf_drv_rtc_counter_clear(&amp;amp;rtc);
	//reactivate compare irq! 
	nrf_drv_rtc_cc_set(&amp;amp;rtc,0,COMPARE_COUNTERTIME * 8,true);
}

void saadc_sampling_event_disable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_disable(m_ppi_channel_1);

    APP_ERROR_CHECK(err_code);
}


void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
	int value = 0;
	int i;
	ret_code_t err_code;

    if (p_event-&amp;gt;type == NRF_DRV_SAADC_EVT_DONE)
    {
		nrf_gpio_pin_toggle(LED);
		
		if((m_adc_evt_counter % SAADC_CALIBRATION_INTERVAL) == 0)       //Evaluate if offset calibration should be performed. Configure the SAADC_CALIBRATION_INTERVAL constant to change the calibration frequency
        {
            nrf_drv_saadc_abort();                                      // Abort all ongoing conversions. Calibration cannot be run if SAADC is busy
            m_saadc_calibrate = true;                                   // Set flag to trigger calibration in main context when SAADC is stopped
        }
    
        NRF_LOG_INFO(&amp;quot;ADC event number: %d&amp;quot;, (int)m_adc_evt_counter);
			
		for (i = 0; i &amp;lt; ADC_CHANNEL_COUNT; i++)
		{
			//NRF_LOG_INFO(&amp;quot;%d&amp;quot;, p_event-&amp;gt;data.done.p_buffer[i]);
			switch(i%4)
			{

				case 0: thermistor_1_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;
				case 1: thermistor_2_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;	
				case 2: battery_voltage_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;	
			}
		}
						
		if(m_saadc_calibrate == false)
        {
            err_code = nrf_drv_saadc_buffer_convert(p_event-&amp;gt;data.done.p_buffer, ADC_CHANNEL_COUNT); //Set buffer so the SAADC can write to it again. This is either &amp;quot;buffer 1&amp;quot; or &amp;quot;buffer 2&amp;quot;
			APP_ERROR_CHECK(err_code);
			
			measDone = 1;
        }
		
		m_adc_evt_counter++;
		
		nrf_gpio_pin_clear(THERMISTOR_VREF);
    }
	
	else if (p_event-&amp;gt;type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
    {
		nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
		while(NRF_SAADC-&amp;gt;EVENTS_STOPPED == 0);
		NRF_SAADC-&amp;gt;EVENTS_STOPPED = 0;
		
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], ADC_CHANNEL_COUNT);             //Set buffer so the SAADC can write to it again. 
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], ADC_CHANNEL_COUNT);             //Need to setup both buffers, as they were both removed with the call to nrf_drv_saadc_abort before calibration.
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_INFO(&amp;quot;SAADC calibration complete !&amp;quot;);                                              //Print on UART    

		battery_voltage_sum = 0;
		voltage_sum = 0;
		thermistor_1_sum = 0;
		thermistor_2_sum = 0;			
    }
}

void saadc_init(void)
{
    ret_code_t err_code;
    
    //Configure SAADC
    nrf_drv_saadc_config_t  config = NRF_DRV_SAADC_DEFAULT_CONFIG;
    config.resolution = NRF_SAADC_RESOLUTION_14BIT;  
    config.oversample = SAADC_OVERSAMPLE_OVERSAMPLE_Over256x;
    //config.low_power_mode = true; 
    
    //Initialize SAADC
    err_code = nrf_drv_saadc_init(&amp;amp;config, saadc_callback);                       
    APP_ERROR_CHECK(err_code);
    
    //Configure SAADC channel 0
    nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
    channel_config.gain = NRF_SAADC_GAIN1_4;
    channel_config.acq_time = SAADC_CH_CONFIG_TACQ_3us; //needed for maximum source resistance of 800kOhm (Datasheet) --&amp;gt; 40us. With additional C --&amp;gt; 3us
    channel_config.burst = NRF_SAADC_BURST_ENABLED;
                                        
    //Initialize SAADC channel 0
    err_code = nrf_drv_saadc_channel_init(2, &amp;amp;channel_config);
    APP_ERROR_CHECK(err_code);
    
    //Configure SAADC channel 1
    channel_config.pin_p = NRF_SAADC_INPUT_AIN0;
    channel_config.reference = NRF_SAADC_REFERENCE_VDD4;
    channel_config.gain = NRF_SAADC_GAIN1_4;
    channel_config.acq_time = SAADC_CH_CONFIG_TACQ_40us;
    channel_config.burst = NRF_SAADC_BURST_ENABLED;
    
    //Initialize SAADC channel 1
    err_code = nrf_drv_saadc_channel_init(0, &amp;amp;channel_config);
    APP_ERROR_CHECK(err_code);
    
    //Configure SAADC channel 2
    channel_config.pin_p = NRF_SAADC_INPUT_AIN1;
    channel_config.acq_time = SAADC_CH_CONFIG_TACQ_40us;
    
    //Initialize SAADC channel 2
    err_code = nrf_drv_saadc_channel_init(1, &amp;amp;channel_config);
    APP_ERROR_CHECK(err_code);
    
    //Set SAADC buffer 1. The SAADC will start to write to this buffer
    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], ADC_CHANNEL_COUNT);
    APP_ERROR_CHECK(err_code);
    
    //Set SAADC buffer 2. The SAADC will write to this buffer when buffer 1 is full. This will give the applicaiton time to process data in buffer 1.
    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], ADC_CHANNEL_COUNT);
    APP_ERROR_CHECK(err_code);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;RTC:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
    if (int_type == NRF_DRV_RTC_INT_COMPARE0)
    {
		nrf_gpio_pin_set(THERMISTOR_VREF);
        //nrf_gpio_pin_toggle(LED);
		nrf_drv_rtc_counter_clear(&amp;amp;rtc);
		//reactivate compare irq! 
		nrf_drv_rtc_cc_set(&amp;amp;rtc,0,COMPARE_COUNTERTIME * 8,true);
    }
		
    else if (int_type == NRF_DRV_RTC_INT_TICK)
    {
        rtcCounter++;
    }	
}


static void lfclk_config(void)
{
    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_clock_lfclk_request(NULL);
}


static void rtc_config(void)
{
	uint32_t err_code;

	//Initialize RTC instance
	nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
	config.prescaler = 4095; // fRTC [kHz] = 32.768 / (PRESCALER + 1 ) --&amp;gt; 8Hz (minimum because prescsaler is 12bit)
	err_code = nrf_drv_rtc_init(&amp;amp;rtc, &amp;amp;config, rtc_handler);
	APP_ERROR_CHECK(err_code);

	//Enable tick event &amp;amp; interrupt
	nrf_drv_rtc_tick_enable(&amp;amp;rtc,true);

	//Set compare channel 0 to trigger interrupt after COMPARE_COUNTERTIME seconds
	err_code = nrf_drv_rtc_cc_set(&amp;amp;rtc,0,COMPARE_COUNTERTIME * 8,true); //1Hz
	APP_ERROR_CHECK(err_code);

	//Power on RTC instance
	nrf_drv_rtc_enable(&amp;amp;rtc);
}

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Main:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;int main(void)
{
	/* Configure board. */
    bsp_board_init(BSP_INIT_LEDS);
	bsp_board_leds_on();
	bsp_board_init(BSP_INIT_BUTTONS);

    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();
	
	NRF_POWER-&amp;gt;DCDCEN = 1;	//Enabling the DCDC converter for lower current consumption
	
	lfclk_config();
	rtc_config();
	
	nrf_gpio_cfg_output(THERMISTOR_VREF);
	nrf_gpio_pin_set(THERMISTOR_VREF);
		
    saadc_init();
	saadc_sampling_event_init();
    saadc_sampling_event_enable();
		
	while(1)
    {
        if(m_saadc_calibrate == true)
		{
			// Disable the PPI triggering of the sample task
			saadc_sampling_event_disable();

			while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS); //Trigger calibration task
			while(!NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE);
			NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE = 0;
			
			NRF_SAADC-&amp;gt;EVENTS_STARTED = 0;
			NRF_SAADC-&amp;gt;TASKS_START = 1;
			while(!NRF_SAADC-&amp;gt;EVENTS_STARTED);
			NRF_SAADC-&amp;gt;EVENTS_STARTED = 0;
			
			// Enable the PPI triggering of the sample task
			saadc_sampling_event_enable();

			m_saadc_calibrate = false;
		}
		
        if(measDone == 1)
        {
            //LOG VALUES
        }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Indeed it works much better now! But still, in the first measurement after a calibration, there is a false value in the first buffer index. Here is the RTT output (error is marked yellow):&lt;/p&gt;
&lt;p&gt;&lt;img alt=" " src="https://devzone.nordicsemi.com/resized-image/__size/320x240/__key/communityserver-discussions-components-files/4/SAADC_5F00_Calibration_5F00_Error.PNG" /&gt;&lt;/p&gt;
&lt;p&gt;I am still not able to solve this problem...&lt;/p&gt;
&lt;p&gt;Thank you and best regards,&lt;br /&gt;Manuel&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/201682?ContentTypeID=1</link><pubDate>Wed, 31 Jul 2019 16:55:04 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:d3925366-4d0c-4ce9-ad1c-a255e535e2cf</guid><dc:creator>J&amp;#248;rgen Holmefjord</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I checked over your code and found an issue with how you trigger the tasks.&lt;/p&gt;
&lt;p&gt;You need to write &amp;#39;1&amp;#39; to the tasks in order to trigger the task. In your code you do this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;NRF_SAADC-&amp;gt;TASKS_START;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;While you should do this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;NRF_SAADC-&amp;gt;TASKS_START = 1;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;I see that this is what Håkon posted below as well.&lt;/p&gt;
&lt;p&gt;Effectively, the workaround is in implemented, and you will get stuck waiting for events that will never arrive.&lt;/p&gt;
&lt;p&gt;Best regards,&lt;br /&gt;Jørgen&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/195935?ContentTypeID=1</link><pubDate>Tue, 02 Jul 2019 10:39:42 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:a93067a1-a245-4cbb-8a76-cff689605d3c</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;Thanks haakonsh. But this is intended. I&amp;#39;m using oversampling on three channels. Therfore I will have three values (each is an average of 256 samples) in the buffer after DONE event.&lt;/p&gt;
&lt;p&gt;I also found this:&amp;nbsp;&lt;a href="https://devzone.nordicsemi.com/f/nordic-q-a/48462/questions-on-saadc-calibration-gain-best-use"&gt;https://devzone.nordicsemi.com/f/nordic-q-a/48462/questions-on-saadc-calibration-gain-best-use&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Same code as I have except that I have three channels and I&amp;#39;m using higher oversampling. But it is still not working.&lt;/p&gt;
&lt;p&gt;My console output:&lt;br /&gt;&lt;img src="https://devzone.nordicsemi.com/resized-image/__size/320x240/__key/communityserver-discussions-components-files/4/pastedimage1562064379999v1.png" alt=" " /&gt;&lt;/p&gt;
&lt;p&gt;Event number 6 is the calibration measurement which is always the same three values? Is this normal? And after this, the values start jumping.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/195928?ContentTypeID=1</link><pubDate>Tue, 02 Jul 2019 10:25:01 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:d09b5770-12d4-456c-bbd1-cc04c0e0b0a8</guid><dc:creator>haakonsh</dc:creator><description>&lt;p&gt;Well I see one potential issue in your code:&lt;/p&gt;
&lt;p&gt;you call&amp;nbsp;nrf_drv_saadc_buffer_convert(m_buffer_pool[0], ADC_CHANNEL_COUNT), where you probably want to use&amp;nbsp;SAMPLES_IN_BUFFER instead of&amp;nbsp;&lt;span&gt;ADC_CHANNEL_COUNT as the size of your buffers.&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/195796?ContentTypeID=1</link><pubDate>Tue, 02 Jul 2019 06:22:24 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:df73a2c3-3460-4caf-9175-34da235685a4</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;Unfortunately it starts to be very urgent. Any other ideas or suggestions?&lt;/p&gt;
&lt;p&gt;Thank you!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/195416?ContentTypeID=1</link><pubDate>Fri, 28 Jun 2019 15:08:00 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:3f9717e2-fb55-484b-9ad4-896c96877c69</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;&lt;span&gt;Could you please point out the difference to my code? I also prepare the next buffer as soon as the calibration interrupt has occured. In the exampe, the RTC frequency is even faster so I can&amp;#39;t understand, why this isn&amp;#39;t happening there?&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/195411?ContentTypeID=1</link><pubDate>Fri, 28 Jun 2019 14:48:28 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:ced1bffa-e7ee-4240-895c-92368abfba06</guid><dc:creator>haakonsh</dc:creator><description>&lt;p&gt;That example does not prepare the next buffer until the calibration is complete.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194901?ContentTypeID=1</link><pubDate>Wed, 26 Jun 2019 13:38:15 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:47c12c47-b979-4fee-8736-853534cde072</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;That means you were not able to get it working with RTC, SCAN and OVERSAMPLING in combination with CALIBRATION?&lt;/p&gt;
&lt;p&gt;Revert to what exactly? I was not able to manage this in one of the approaches.&lt;/p&gt;
&lt;p&gt;In my opinion i implemented it exactly like described here:&lt;br /&gt;&lt;a href="https://github.com/NordicPlayground/nRF52-ADC-examples/blob/master/saadc_low_power/main.c#L286"&gt;https://github.com/NordicPlayground/nRF52-ADC-examples/blob/master/saadc_low_power/main.c#L286&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Regards,&lt;br /&gt;Manuel&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194828?ContentTypeID=1</link><pubDate>Wed, 26 Jun 2019 09:37:20 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:0fbd6dd0-55aa-4d04-9afd-431bd5bfe818</guid><dc:creator>haakonsh</dc:creator><description>&lt;p&gt;I think we should revert to&amp;nbsp;&lt;a href="https://devzone.nordicsemi.com/support-private/support/231167#permalink=471722"&gt;https://devzone.nordicsemi.com/support-private/support/231167#permalink=471722&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;if(m_saadc_calibrate == true)
{
    // Disable any source that triggers the sample task.
    
	NRF_LOG_INFO(&amp;quot;SAADC calibration starting...&amp;quot;);    //Print on UART
	while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS); //Trigger calibration task
	while(!NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE);
	m_saadc_calibrate = false;
	
	// Enable the source/s for that triggers the sample task.
}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I believe the problem is that the sample task is getting triggered during the calibration procedure.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;The saadc driver does not have any awareness of HW triggering of the sample task and it will therefore not be able to handle this scenario.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194798?ContentTypeID=1</link><pubDate>Wed, 26 Jun 2019 08:49:55 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:ddf65890-8549-4a46-a802-95b865bb52d0</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;&lt;a href="https://devzone.nordicsemi.com/cfs-file/__key/communityserver-discussions-components-files/4/Firmware_5F00_Nordic_5F00_Devzone.7z"&gt;devzone.nordicsemi.com/.../Firmware_5F00_Nordic_5F00_Devzone.7z&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you. Here I send you a compilable version of my code. Its for my custom board but it should be easy to change it to the default devkits.&lt;/p&gt;
&lt;p&gt;Regards,&lt;br /&gt;Manuel&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194792?ContentTypeID=1</link><pubDate>Wed, 26 Jun 2019 08:33:23 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:2b374c2a-ef78-4af0-9fe5-a9f7747727fe</guid><dc:creator>haakonsh</dc:creator><description>&lt;p&gt;I&amp;#39;d like to try to reproduce it on my end, but I need a compilable code. I&amp;#39;m missing the definitions of about 20 variables and definitions.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194702?ContentTypeID=1</link><pubDate>Tue, 25 Jun 2019 14:48:21 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:b35ec93f-4f4b-4644-a55a-df20a85985f4</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;Still hanging on while(!NRF_SAADC-&amp;gt;EVENTS_STOPPED)&lt;/p&gt;
&lt;p&gt;Here is my current codeif this helps for further debugging&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);
	
    uint32_t rtc_compare_event_addr = nrf_drv_rtc_event_address_get(&amp;amp;rtc, NRF_RTC_EVENT_COMPARE_0);//nrf_drv_timer_compare_event_address_get(&amp;amp;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(&amp;amp;m_ppi_channel_1);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel_1,
                                          rtc_compare_event_addr,
                                          saadc_sample_task_addr);
																					
    APP_ERROR_CHECK(err_code);
}


void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel_1);

    APP_ERROR_CHECK(err_code);
}

void saadc_sampling_event_disable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_disable(m_ppi_channel_1);

    APP_ERROR_CHECK(err_code);
}


void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
	int value = 0;
	int i;
	ret_code_t err_code;
	
    if (p_event-&amp;gt;type == NRF_DRV_SAADC_EVT_DONE)
    {
		nrf_gpio_pin_toggle(LED);
		
		if((m_adc_evt_counter % SAADC_CALIBRATION_INTERVAL) == 0)       //Evaluate if offset calibration should be performed. Configure the SAADC_CALIBRATION_INTERVAL constant to change the calibration frequency
        {
            nrf_drv_saadc_abort();                                      // Abort all ongoing conversions. Calibration cannot be run if SAADC is busy
            m_saadc_calibrate = true;                                   // Set flag to trigger calibration in main context when SAADC is stopped
        }
				
        NRF_LOG_INFO(&amp;quot;ADC event number: %d&amp;quot;, (int)m_adc_evt_counter);
				
		for (i = 0; i &amp;lt; ADC_CHANNEL_COUNT; i++)
		{
			NRF_LOG_INFO(&amp;quot;%d&amp;quot;, p_event-&amp;gt;data.done.p_buffer[i]);
			switch(i%4)
			{
				case 0: thermistor_1_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;
				case 1: thermistor_2_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;	
				case 2: voltage_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;	
			}
		}
		
		if(m_saadc_calibrate == false)
        {
            err_code = nrf_drv_saadc_buffer_convert(p_event-&amp;gt;data.done.p_buffer, ADC_CHANNEL_COUNT); //Set buffer so the SAADC can write to it again. This is either &amp;quot;buffer 1&amp;quot; or &amp;quot;buffer 2&amp;quot;
	        APP_ERROR_CHECK(err_code);
					
					measDone = 1;
        }
				
		m_adc_evt_counter++;
		
		nrf_gpio_pin_clear(THERMISTOR_VREF);
    }
    
    else if (p_event-&amp;gt;type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
    {
				//nrfx_saadc_abort();
			
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], ADC_CHANNEL_COUNT);             //Set buffer so the SAADC can write to it again. 
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], ADC_CHANNEL_COUNT);             //Need to setup both buffers, as they were both removed with the call to nrf_drv_saadc_abort before calibration.
        APP_ERROR_CHECK(err_code);
        
        NRF_LOG_INFO(&amp;quot;SAADC calibration complete !&amp;quot;);                                              //Print on UART        
    }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;void saadc_init(void)
{
    ret_code_t err_code;

	//Configure SAADC
	nrf_drv_saadc_config_t  config = NRF_DRV_SAADC_DEFAULT_CONFIG;
	config.resolution = NRF_SAADC_RESOLUTION_14BIT;  
    config.oversample = SAADC_OVERSAMPLE_OVERSAMPLE_Over256x;
	//config.low_power_mode = true; 

	//Initialize SAADC
    err_code = nrf_drv_saadc_init(&amp;amp;config, saadc_callback);                       
    APP_ERROR_CHECK(err_code);
	
    //Configure SAADC channel 1
    nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
    channel_config.reference = NRF_SAADC_REFERENCE_VDD4;
    channel_config.gain = NRF_SAADC_GAIN1_4;
    channel_config.acq_time = SAADC_CH_CONFIG_TACQ_40us;
    channel_config.burst = NRF_SAADC_BURST_ENABLED;
    
    //Initialize SAADC channel 1
    err_code = nrf_drv_saadc_channel_init(0, &amp;amp;channel_config);
    APP_ERROR_CHECK(err_code);
    
    //Configure SAADC channel 2
    channel_config.pin_p = NRF_SAADC_INPUT_AIN1;
    channel_config.acq_time = SAADC_CH_CONFIG_TACQ_40us;
    
    //Initialize SAADC channel 2
    err_code = nrf_drv_saadc_channel_init(1, &amp;amp;channel_config);
    APP_ERROR_CHECK(err_code);
    
    //Configure SAADC channel 3
    channel_config.pin_p = NRF_SAADC_INPUT_AIN2;
    channel_config.reference = NRF_SAADC_REFERENCE_INTERNAL;
    channel_config.gain = NRF_SAADC_GAIN4;
    channel_config.acq_time = SAADC_CH_CONFIG_TACQ_40us;
    
    //Initialize SAADC channel 3
    err_code = nrf_drv_saadc_channel_init(2, &amp;amp;channel_config);
    APP_ERROR_CHECK(err_code);
    
    //Set SAADC buffer 1. The SAADC will start to write to this buffer
    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], ADC_CHANNEL_COUNT);
    APP_ERROR_CHECK(err_code);
    
    //Set SAADC buffer 2. The SAADC will write to this buffer when buffer 1 is full. This will give the applicaiton time to process data in buffer 1.
    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], ADC_CHANNEL_COUNT);
    APP_ERROR_CHECK(err_code);
}


static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
	static int i = 2;
    if (int_type == NRF_DRV_RTC_INT_COMPARE0)
    {
		nrf_gpio_pin_set(THERMISTOR_VREF);
		nrf_drv_rtc_counter_clear(&amp;amp;rtc);
		//reactivate compare irq! 
	    nrf_drv_rtc_cc_set(&amp;amp;rtc,0,COMPARE_COUNTERTIME * 8,true);
    }
		
    else if (int_type == NRF_DRV_RTC_INT_TICK)
    {
        rtcCounter++;
    }
		
}


static void lfclk_config(void)
{
    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_clock_lfclk_request(NULL);
}


static void rtc_config(void)
{
	uint32_t err_code;

	//Initialize RTC instance
	nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
	config.prescaler = 4095; // fRTC [kHz] = 32.768 / (PRESCALER + 1 ) --&amp;gt; 8Hz (minimum because prescsaler is 12bit)
	err_code = nrf_drv_rtc_init(&amp;amp;rtc, &amp;amp;config, rtc_handler);
	APP_ERROR_CHECK(err_code);

	//Enable tick event &amp;amp; interrupt
	nrf_drv_rtc_tick_enable(&amp;amp;rtc,true);

	//Set compare channel 0 to trigger interrupt after COMPARE_COUNTERTIME seconds
	err_code = nrf_drv_rtc_cc_set(&amp;amp;rtc,0,COMPARE_COUNTERTIME * 8,true); //1Hz
	APP_ERROR_CHECK(err_code);

	//Power on RTC instance
	nrf_drv_rtc_enable(&amp;amp;rtc);
}

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;int main(void)
{
    /* Configure board. */
    bsp_board_init(BSP_INIT_LEDS);
    bsp_board_leds_on();
    bsp_board_init(BSP_INIT_BUTTONS);
    
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    
    NRF_POWER-&amp;gt;DCDCEN = 1;	//Enabling the DCDC converter for lower current consumption
    
    NRF_LOG_INFO(&amp;quot;Zirbel Datalogger successfuly started...&amp;quot;);
    
    lfclk_config();
    rtc_config();
    
    nrf_gpio_cfg_output(THERMISTOR_VREF);
    nrf_gpio_pin_set(THERMISTOR_VREF);
    
    saadc_init();
    saadc_sampling_event_init();
    saadc_sampling_event_enable();
    
    while(1)
    {	
        if(m_saadc_calibrate == true)
        {
            // Disable the PPI triggering of the sample task
            saadc_sampling_event_disable();
            
            NRF_SAADC-&amp;gt;EVENTS_STOPPED = 0;
            NRF_SAADC-&amp;gt;TASKS_STOP;
            while(!NRF_SAADC-&amp;gt;EVENTS_STOPPED);
            NRF_SAADC-&amp;gt;EVENTS_STOPPED = 0;
            
            NRF_LOG_INFO(&amp;quot;SAADC calibration starting...&amp;quot;);    //Print on UART
            while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS); //Trigger calibration task
            while(!NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE);
            NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE = 0;
            
            NRF_SAADC-&amp;gt;EVENTS_STOPPED = 0;
            NRF_SAADC-&amp;gt;TASKS_STOP;
            while(!NRF_SAADC-&amp;gt;EVENTS_STOPPED);
            NRF_SAADC-&amp;gt;EVENTS_STOPPED = 0;
            
            NRF_SAADC-&amp;gt;EVENTS_STARTED = 0;
            NRF_SAADC-&amp;gt;TASKS_START;
            while(!NRF_SAADC-&amp;gt;EVENTS_STARTED);
            NRF_SAADC-&amp;gt;EVENTS_STARTED = 0;
            
            // Enable the PPI triggering of the sample task
            saadc_sampling_event_enable();
            
            m_saadc_calibrate = false;
        }

        if(measDone == 1)
        {
            ...
        }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Thank you for your help,&amp;nbsp;&lt;span&gt;I appreciate that very much!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Manuel&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194680?ContentTypeID=1</link><pubDate>Tue, 25 Jun 2019 13:34:24 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:0076dee3-5be8-463f-adb4-3e4da3e0fd21</guid><dc:creator>haakonsh</dc:creator><description>&lt;p&gt;Try this:&lt;br /&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;if(m_saadc_calibrate == true)
{
    // Disable the PPI triggering of the sample task
    
    NRF_SAADC-&amp;gt;EVENTS_STOPPED = 0;
	NRF_SAADC-&amp;gt;TASKS_STOP;
	while(!NRF_SAADC-&amp;gt;EVENTS_STOPPED);
	NRF_SAADC-&amp;gt;EVENTS_STOPPED = 0;

	NRF_LOG_INFO(&amp;quot;SAADC calibration starting...&amp;quot;);    //Print on UART
	while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS); //Trigger calibration task
	while(!NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE);
	NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE = 0;
	
	NRF_SAADC-&amp;gt;EVENTS_STOPPED = 0;
	NRF_SAADC-&amp;gt;TASKS_STOP;
	while(!NRF_SAADC-&amp;gt;EVENTS_STOPPED);
	NRF_SAADC-&amp;gt;EVENTS_STOPPED = 0;
	
	NRF_SAADC-&amp;gt;EVENTS_STARTED = 0;
	NRF_SAADC-&amp;gt;TASKS_START;
	while(!NRF_SAADC-&amp;gt;EVENTS_STARTED);
	NRF_SAADC-&amp;gt;EVENTS_STARTED = 0;
	
	// Enable the PPI triggering of the sample task
	
	m_saadc_calibrate = false;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The PPI system will operate even though you&amp;#39;ve halted the CPU with the debugger, and the SAADC will also operate when the CPU is halted.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194665?ContentTypeID=1</link><pubDate>Tue, 25 Jun 2019 13:02:31 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:b5dbfefc-cc4d-4438-ad29-d87fd3516128</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;Thank you, but this is also not working together with my code. It stops and hangs on:&lt;/p&gt;
&lt;p&gt;while(!NRF_SAADC-&amp;gt;EVENTS_STARTED);&lt;/p&gt;
&lt;p&gt;PPI is still active for the SAMPLE task.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m really confused now about this START, STARTED, END, DONE- things...&lt;br /&gt;I&amp;#39;m not able to comprehend this procedure of events and tasks while debugging.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194646?ContentTypeID=1</link><pubDate>Tue, 25 Jun 2019 12:27:10 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:8c48c64b-9fa7-473f-82c6-42ee519c5194</guid><dc:creator>haakonsh</dc:creator><description>&lt;p&gt;Then you&amp;#39;ve triggered the start task before the calibration task, use:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;if(m_saadc_calibrate == true)
{
	NRF_LOG_INFO(&amp;quot;SAADC calibration starting...&amp;quot;);    //Print on UART
	while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS); //Trigger calibration task
	while(!NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE);
	NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE = 0;
	
	NRF_SAADC-&amp;gt;EVENTS_STARTED = 0;
	NRF_SAADC-&amp;gt;TASKS_START;
	while(!NRF_SAADC-&amp;gt;EVENTS_STARTED);
	NRF_SAADC-&amp;gt;EVENTS_STARTED = 0;
	
	m_saadc_calibrate = false;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;in order to re-trigger the start task, as this will reload the PTR and MAXCNT registers.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194643?ContentTypeID=1</link><pubDate>Tue, 25 Jun 2019 12:23:10 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:c2542a92-1c19-4beb-86e1-f8a76afef755</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;It&amp;#39;s 0x0003&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194625?ContentTypeID=1</link><pubDate>Tue, 25 Jun 2019 11:35:15 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:919afb54-9759-41a7-9b58-4f587bd23d03</guid><dc:creator>haakonsh</dc:creator><description>&lt;p&gt;What&amp;#39;s the state of the&amp;nbsp;&lt;a title="  RESULT.AMOUNT  " href="https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/saadc.html?cp=3_1_0_36_10_42#register.RESULT.AMOUNT"&gt;RESULT.AMOUNT&lt;/a&gt;&amp;nbsp;register after the first calibration has completed?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194592?ContentTypeID=1</link><pubDate>Tue, 25 Jun 2019 10:18:16 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:86f2fc45-a0a8-4e7a-8f99-a8947c4f22e6</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;OK, I added this to my main:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;if(m_saadc_calibrate == true)
{
	NRF_LOG_INFO(&amp;quot;SAADC calibration starting...&amp;quot;);    //Print on UART
	while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS); //Trigger calibration task
	while(!NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE);
	m_saadc_calibrate = false;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The problem is still there. After the first calibration, the samples in the buffer are somehow swapped.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;It seems to be the same error like in the beginning of the thread. Anyone can show me some tested samplecode?&amp;nbsp;&lt;span&gt;I really can not go any further..&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Thanks,&lt;br /&gt;Manuel&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194587?ContentTypeID=1</link><pubDate>Tue, 25 Jun 2019 10:04:09 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:14c426c2-508c-464e-b4d2-39673c227e4b</guid><dc:creator>haakonsh</dc:creator><description>&lt;p&gt;You&amp;#39;re getting calibration data in your samples.&lt;br /&gt;&lt;br /&gt;After you&amp;#39;ve triggered the calibrate offset task with the call to&amp;nbsp;nrf_drv_saadc_calibrate_offset() you need to wait until it&amp;#39;s complete:&lt;br /&gt;&lt;br /&gt;While(!NRF_SAADC-&amp;gt;EVENTS_CALIBRATEDONE);&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194546?ContentTypeID=1</link><pubDate>Tue, 25 Jun 2019 08:29:10 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:91046d64-f0d5-487c-87d0-dce9eeae2eb7</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;Thank you haakonsh.&lt;/p&gt;
&lt;p&gt;Unfotunately I was not able to implement this without swaps in the buffer. I switched now to your suggested approach. SCAN mode of multiple channels with oversampling (256x). Burst mode is activated on every channel.&lt;/p&gt;
&lt;p&gt;I need a high accuracy of the thermistor measurements. Therefore I wanted to add a periodical offset calibration. Because a change in temperature will be very likely in my application.&lt;/p&gt;
&lt;p&gt;Therefore I added the following to my code:&lt;/p&gt;
&lt;p&gt;SAADC interrupt routine:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
	int value = 0;
	int i;
	ret_code_t err_code;

    if (p_event-&amp;gt;type == NRF_DRV_SAADC_EVT_DONE)
    {
		nrf_gpio_pin_toggle(LED);
		
		if((m_adc_evt_counter % SAADC_CALIBRATION_INTERVAL) == 0)       //Evaluate if offset calibration should be performed. Configure the SAADC_CALIBRATION_INTERVAL constant to change the calibration frequency
        {
            nrf_drv_saadc_abort();                                      // Abort all ongoing conversions. Calibration cannot be run if SAADC is busy
            m_saadc_calibrate = true;                                   // Set flag to trigger calibration in main context when SAADC is stopped
        }
        
        NRF_LOG_INFO(&amp;quot;ADC event number: %d&amp;quot;, (int)m_adc_evt_counter);
				
		for (i = 0; i &amp;lt; ADC_CHANNEL_COUNT; i++)
		{
			NRF_LOG_INFO(&amp;quot;%d&amp;quot;, p_event-&amp;gt;data.done.p_buffer[i]);
			switch(i%4)
			{
				case 0: battery_voltage_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;
				case 1: thermistor_1_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;
				case 2: thermistor_2_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;	
				case 3: voltage_sum = p_event-&amp;gt;data.done.p_buffer[i];
								break;	
			}
		}
		
		if(m_saadc_calibrate == false)
        {
            err_code = nrf_drv_saadc_buffer_convert(p_event-&amp;gt;data.done.p_buffer, ADC_CHANNEL_COUNT); //Set buffer so the SAADC can write to it again. This is either &amp;quot;buffer 1&amp;quot; or &amp;quot;buffer 2&amp;quot;
			APP_ERROR_CHECK(err_code);
			
			measDone = 1;
        }
				
		m_adc_evt_counter++;
		
		nrf_gpio_pin_clear(THERMISTOR_VREF);
    }
		
	else if (p_event-&amp;gt;type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
    {
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], ADC_CHANNEL_COUNT);             //Set buffer so the SAADC can write to it again. 
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], ADC_CHANNEL_COUNT);             //Need to setup both buffers, as they were both removed with the call to nrf_drv_saadc_abort before calibration.
        APP_ERROR_CHECK(err_code);
        
        NRF_LOG_INFO(&amp;quot;SAADC calibration complete !&amp;quot;);                                              //Print on UART        
    }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;main:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;while(1)
{	
	if(m_saadc_calibrate == true)
	{
		NRF_LOG_INFO(&amp;quot;SAADC calibration starting...&amp;quot;);    //Print on UART
		while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS); //Trigger calibration task
		m_saadc_calibrate = false;
	}

	if(measDone == 1)
	{
	    ...
	}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I think I did everythink like described in this link:&lt;br /&gt;&lt;a href="https://github.com/NordicPlayground/nRF52-ADC-examples/tree/master/saadc_low_power"&gt;https://github.com/NordicPlayground/nRF52-ADC-examples/tree/master/saadc_low_power&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But as soon as I perform the first calibration, the buffer data is rubbish. I can&amp;#39;t even recognize a pattern of buffer swap or something like this.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Could you please help me with this behaviour?&lt;/p&gt;
&lt;p&gt;Thank you and best regards,&lt;br /&gt;Manuel&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194309?ContentTypeID=1</link><pubDate>Mon, 24 Jun 2019 11:23:44 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:2dd045cc-624d-445e-9d81-7717a1841177</guid><dc:creator>haakonsh</dc:creator><description>[quote user="Manuel55"]Thank you for your answer. But I do not fully understand it. How can I catch this STARTED event for calling nrf_drv_saadc_buffer_convert() then. Is there some samplecode for that?[/quote]
&lt;p&gt;&amp;nbsp;No, I&amp;#39;m afraid there&amp;#39;s no sample code that does that for you. You will need to modify the saadc driver&amp;#39;s interrupt handler to handle this scenario.&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
[quote user="Manuel55"]I have a hard time by understanding this PPI stuff like[/quote]
&lt;p&gt;The PPI uses the registers of the HW peripherals to connect their tasks and events.&lt;br /&gt;It monitors a given event register, and in the event that it changes state from 0x00 to 0x01(indicating that the event has happened) it will write a 0x01 to a given task register, thereby triggering the given task.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;f.ex, the nRF52832&amp;#39;a SAADC&amp;nbsp;&lt;span&gt;EVENTS_END register has an address offset of&amp;nbsp;0x104, with an address base of&amp;nbsp;0x40007000 for the SAADC peripheral the&amp;nbsp;EVENTS_END register has the address of 0x40007104, who&amp;#39;s&lt;/span&gt;&amp;nbsp;is what nrf_saadc_event_address_get(NRF_SAADC_EVENT_END) will return.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;Likewise&amp;nbsp;nrf_saadc_task_address_get(NRF_SAADC_TASK_START) will return 0x40007000, as the address offset of the&amp;nbsp;&lt;span&gt;TASKS_START register is 0x000.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;This coupling between an event register and a task register is then assigned to a PPI channel.&amp;nbsp;&lt;br /&gt;An event or task register can be connected to any number of PPI channels.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
[quote user="Manuel55"]Well, MAXCNT is to set the maximum sample count for the buffer before firing the&amp;nbsp;NRF_DRV_SAADC_EVT_DONE event, right?[/quote]
&lt;p&gt;The MAXCNT sets the number of samples that the SAADC will sample before it will fire the&amp;nbsp;&lt;span&gt;EVENTS_END, at which point all the samples have been transferred from the SAADC into RAM.&lt;br /&gt;&lt;br /&gt;MAXCNT along with PTR &lt;strong&gt;must&lt;/strong&gt; be configured before triggering the next START task, otherwise, they will not be used. This is the core of your issue, that the MAXCNT and PTR register are not updated&amp;nbsp;before the START task is&amp;nbsp;triggered, or the start task is triggered after the SAADC has begun its next sampling cycle.&amp;nbsp;&lt;br /&gt;In both cases, you&amp;#39;ll overwrite your previous buffers, and in the second case, you will suddenly change the buffer mid-sample-cycle, thereby creating out of order samples.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
[quote user="Manuel55"]What I want to implement is 1 measurement per second. 10 measurements per channel are made at 1kHz. After the DONE event, I switch off the PPI channel so no more samples will be made. After 1 second, I switch on the PPI channel again for 10 measurements. Summarized I want to have one measurement per seccond but the measurements are a average out of 10 samples which were sampled in a high frequency.[/quote]
&lt;p&gt;I interpret this as one set of measurements per second, 10 samples per channel per set, at 1kHz sample rate, with averaging of the sets of 10 samples.&lt;br /&gt;&lt;br /&gt;You don&amp;#39;t need to disable the PPI channel, but that might work as intended. I would rather stop and clear the TIMER on the SAADC&amp;#39;s end event, and then trigger the start event in order to start your sampling sequence.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Other thoughts:&lt;br /&gt;If you only enable one SAADC channel at a time you can use oversampling to average over the samples automatically at 1kHz. That way you will not have to do any averaging in SW.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;You can do oversampling on multiple channels, but then you must enable BURST mode on all channels. From &lt;a title="Oversampling" href="https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/saadc.html?cp=3_1_0_36_4_2#saadc_operationmodes_oversample"&gt;Oversampling&lt;/a&gt;:&lt;br /&gt;&amp;quot;&lt;span&gt;H[n].CONFIG.BURST can be enabled to avoid setting SAMPLE task 2&lt;/span&gt;&lt;sup&gt;OVERSAMPLE&lt;/sup&gt;&lt;span&gt;&amp;nbsp;times. With BURST = 1 the ADC will sample the input 2&lt;/span&gt;&lt;sup&gt;OVERSAMPLE&lt;/sup&gt;&lt;span&gt;&amp;nbsp;times as fast as it can (actual timing: &amp;lt;(t&lt;/span&gt;&lt;sub&gt;ACQ&lt;/sub&gt;&lt;span&gt;+t&lt;/span&gt;&lt;sub&gt;CONV&lt;/sub&gt;&lt;span&gt;)×2&lt;/span&gt;&lt;sup&gt;OVERSAMPLE&lt;/sup&gt;&lt;span&gt;). Thus, for the user it will just appear like the conversion took a bit longer time, but other than that, it is similar to one-shot mode. Scan mode can be combined with BURST=1, if burst is enabled on all channels.&amp;quot;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194076?ContentTypeID=1</link><pubDate>Fri, 21 Jun 2019 11:20:44 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:bcef1da7-4007-4c49-8c9f-c77c16f07028</guid><dc:creator>Manuel55</dc:creator><description>&lt;p&gt;Thank you for your answer. But I do not fully understand it. How can I catch this STARTED event for calling nrf_drv_saadc_buffer_convert() then. Is there some samplecode for that?&lt;/p&gt;
&lt;p&gt;I have a hard time by understanding this PPI stuff like&lt;br /&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;err_code = nrf_drv_ppi_channel_assign(m_ppi_channel_2, nrf_saadc_event_address_get(NRF_SAADC_EVENT_END), nrf_saadc_task_address_get(NRF_SAADC_TASK_START));&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Well, MAXCNT is to set the maximum sample count for the buffer before firing the&amp;nbsp;NRF_DRV_SAADC_EVT_DONE event, right?&lt;/p&gt;
&lt;p&gt;What I want to implement is 1 measurement per second. 10 measurements per channel are made at 1kHz. After the DONE event, I switch off the PPI channel so no more samples will be made. After 1 second, I switch on the PPI channel again for 10 measurements. Summarized I want to have one measurement per seccond but the measurements are a average out of 10 samples which were sampled in a high frequency.&lt;/p&gt;
&lt;p&gt;Is it clearer now?&lt;/p&gt;
&lt;p&gt;Thank you and best regards,&lt;br /&gt;Manuel&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;#edit:&lt;/p&gt;
&lt;p&gt;When I activate the STARTED interrupt with&amp;nbsp;nrf_saadc_int_enable(NRF_SAADC_INT_STARTED), I end up in a NRF_ERROR_INVALID_STATE error while calling&amp;nbsp;APP_ERROR_CHECK(err_code) after enabling my PPI channel 1 which is responsible for triggering the sample task.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC scan mode of 3 channels --&gt; buffer order swap</title><link>https://devzone.nordicsemi.com/thread/194041?ContentTypeID=1</link><pubDate>Fri, 21 Jun 2019 09:13:45 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:95384e96-3144-43ee-a772-f3f7b28ac278</guid><dc:creator>haakonsh</dc:creator><description>&lt;p&gt;You need to&amp;nbsp;update the buffer pointer and maxcount registers immediately after a STARTED event. Right now it&amp;#39;s done after the END event.&amp;nbsp;&lt;br /&gt;By updating the buffer registers after the START task has been triggered you will overwrite the previous buffer as new buffers will not be used until the next START task.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;See the SAADC&amp;#39;s&amp;nbsp;&lt;a title="EasyDMA" href="https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/saadc.html?cp=3_1_0_36_5#saadc_easydma"&gt;EasyDMA&lt;/a&gt;&amp;nbsp;chapter.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;quot;&lt;span&gt;I&amp;#39;m using a compare event of the RTC to trigger the sample task in scan mode. Another compare event is used to&amp;nbsp;enable the ppi channel again after disabling it after 10 samples per channel. The reason for that is that I want to sample at a high frequency but only 10 samples per second.&amp;quot;&lt;br /&gt;&lt;/span&gt;Can you try to rephrase your description a bit, I did not quite catch why you&amp;#39;re disabling the PPI to control the sampling, usually this is done with the MAXCNT register.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>