<?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 oversampling + burst mode on three channel</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/81488/saadc-oversampling-burst-mode-on-three-channel</link><description>Hi, 
 I have two questions as below. Thank you. 
 1. Oversampling + burst mode only can use on one channel, can&amp;#39;t support two or more channel. Is it right? 
 2. If Q1&amp;#39;s answer is yes. How can I average 30 numbers of ADC value on three channel? (for loop</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Tue, 09 Nov 2021 15:26:08 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/81488/saadc-oversampling-burst-mode-on-three-channel" /><item><title>RE: SAADC oversampling + burst mode on three channel</title><link>https://devzone.nordicsemi.com/thread/338240?ContentTypeID=1</link><pubDate>Tue, 09 Nov 2021 15:26:08 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:21d1a61f-d216-4b2d-81ed-6007e7bde515</guid><dc:creator>Kazi Afroza Sultana</dc:creator><description>&lt;p&gt;Hello John,&lt;/p&gt;
&lt;p&gt;I think you may either move the call to&amp;nbsp;nrf_drv_saadc_sample() after the printf (for printing the current value of variables) and afterwards can start a new sample; or may wait for the SAADC event even handler to be called before printing to get and print new values.&amp;nbsp;To avoid the potential racing you can try this.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Though it depends what you want to achieve. If triggering occurs before &lt;strong&gt;printf&lt;/strong&gt;, there may be a race condition since SAADC buffer may or may not be filled with new samples before &lt;strong&gt;pritnf&lt;/strong&gt; is done printing the variables.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;It is recommended to start triggering after offset calibration. If you do offset calibration before starting trigger, the wrong order in the buffer may be caused by this errata: &lt;a title="https://infocenter.nordicsemi.com/topic/errata_nrf52832_rev3/err/nrf52832/rev3/latest/anomaly_832_86.html?cp=4_2_1_0_1_23" href="https://infocenter.nordicsemi.com/topic/errata_nRF52832_Rev3/ERR/nRF52832/Rev3/latest/anomaly_832_86.html?cp=4_2_1_0_1_23" rel="noopener noreferrer" target="_blank"&gt;https://infocenter.nordicsemi.com/topic/errata_nRF52832_Rev3/ERR/nRF52832/Rev3/latest/anomaly_832_86.html?cp=4_2_1_0_1_23&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can look at this thread also:&amp;nbsp;&lt;a href="https://devzone.nordicsemi.com/f/nordic-q-a/20291/offset-in-saadc-samples-with-easy-dma-and-ble/79053#79053"&gt;https://devzone.nordicsemi.com/f/nordic-q-a/20291/offset-in-saadc-samples-with-easy-dma-and-ble/79053#79053&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Hope it helps.&lt;/p&gt;
&lt;p&gt;Best Regards,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Kazi Afroza Sultana&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC oversampling + burst mode on three channel</title><link>https://devzone.nordicsemi.com/thread/338038?ContentTypeID=1</link><pubDate>Tue, 09 Nov 2021 03:04:58 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:fb034a2b-d01d-4da7-ac42-52359b1d6876</guid><dc:creator>JohnCC</dc:creator><description>&lt;p&gt;Hi Kazi,&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;Thank you for your support.&lt;/p&gt;
&lt;p&gt;I want to use 200ms to get ADC value from three channel and I want to&amp;nbsp;get 30 times ADC value from every channel when 200ms timer trigger.&lt;/p&gt;
&lt;p&gt;I change my code for three channel and every channel enable burst mode + oversample is 8x. Below is my setting source code.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;static void adc_configure(void)
{
    ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);
    APP_ERROR_CHECK(err_code);

    nrf_saadc_channel_config_t config_current_sense =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
    err_code = nrf_drv_saadc_channel_init(0, &amp;amp;config_current_sense);
    APP_ERROR_CHECK(err_code);
    
    nrf_saadc_channel_config_t config_adc_temp =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
    err_code = nrf_drv_saadc_channel_init(1, &amp;amp;config_adc_temp);
    APP_ERROR_CHECK(err_code);
    
    nrf_saadc_channel_config_t config_em_temp =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);
    err_code = nrf_drv_saadc_channel_init(2, &amp;amp;config_em_temp);
    APP_ERROR_CHECK(err_code);
    
    err_code = nrf_drv_saadc_buffer_convert(adc_buf_adc[0], 3);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(adc_buf_adc[1], 3);
    APP_ERROR_CHECK(err_code);
}

#define NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PIN_P) \
    {                                                  \
        .resistor_p = NRF_SAADC_RESISTOR_DISABLED,     \
        .resistor_n = NRF_SAADC_RESISTOR_DISABLED,     \
        .gain       = NRF_SAADC_GAIN1_6,               \
        .reference  = NRF_SAADC_REFERENCE_INTERNAL,    \
        .acq_time   = NRF_SAADC_ACQTIME_10US,          \
        .mode       = NRF_SAADC_MODE_SINGLE_ENDED,     \
        .burst      = NRF_SAADC_BURST_ENABLED,         \
        .pin_p      = (nrf_saadc_input_t)(PIN_P),      \
        .pin_n      = NRF_SAADC_INPUT_DISABLED         \
    }
    
// &amp;lt;o&amp;gt; SAADC_CONFIG_OVERSAMPLE  - Sample period
 
// &amp;lt;0=&amp;gt; Disabled 
// &amp;lt;1=&amp;gt; 2x 
// &amp;lt;2=&amp;gt; 4x 
// &amp;lt;3=&amp;gt; 8x 
// &amp;lt;4=&amp;gt; 16x 
// &amp;lt;5=&amp;gt; 32x 
// &amp;lt;6=&amp;gt; 64x 
// &amp;lt;7=&amp;gt; 128x 
// &amp;lt;8=&amp;gt; 256x 

#ifndef SAADC_CONFIG_OVERSAMPLE
#define SAADC_CONFIG_OVERSAMPLE 3
#endif
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Also, I create a 200ms timer to call&amp;nbsp;nrf_drv_saadc_sample(), like as below.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;static void data_process_handler(void * p_context)
{
    uint32_t err_code;
   
    //average_adc = true;
    nrf_drv_saadc_sample();
    
    //printf(&amp;quot;%.4f-%.4f-%.4f\r\n&amp;quot;,real_v_current_sense,real_v_adc_temp,real_v_em_temp);
    printf(&amp;quot;%d-%d-%d\r\n&amp;quot;,current_sense_vol,adc_temp_vol,em_temp_vol);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;below is my ADC callback function and calibration function in main()&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
{
    uint32_t err_code;
  
    if (p_event-&amp;gt;type == NRF_DRV_SAADC_EVT_DONE)
    {
        nrf_saadc_value_t adc_result,adc_temp_result,em_temp_result;
        uint32_t          err_code;
        
        if((m_adc_evt_counter % 50000) == 0)               //Evaluate if offset calibration should be performed. Configure the SAADC_CALIBRATION_INTERVAL constant to change the calibration frequency
        {
            m_saadc_calibrate = true;                                           // Set flag to trigger calibration in main context when SAADC is stopped
        }
        
        if(m_saadc_calibrate == false)
        {
            err_code = nrf_drv_saadc_buffer_convert(p_event-&amp;gt;data.done.p_buffer, 3);             //Set buffer so the SAADC can write to it again. 
            APP_ERROR_CHECK(err_code);
        }
        
        adc_result = p_event-&amp;gt;data.done.p_buffer[0];
        adc_temp_result = p_event-&amp;gt;data.done.p_buffer[1];
        em_temp_result = p_event-&amp;gt;data.done.p_buffer[2];
        
        //printf(&amp;quot;Hello : %d-%d-%d\r\n&amp;quot;,adc_result,adc_temp_result,em_temp_result);
        
        current_sense_vol = adc_result;
        adc_temp_vol = adc_temp_result;
        em_temp_vol = em_temp_result;
        
        m_adc_evt_counter++;
    }
    else if (p_event-&amp;gt;type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
    {
        nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
        while(!nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED));
        nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED);
       
        //Set buffer so the SAADC can write to it again.
        err_code = nrf_drv_saadc_buffer_convert(adc_buf_adc[0], 3);
        APP_ERROR_CHECK(err_code);
        //Need to setup both buffers, as they were both removed with the call to nrf_drv_saadc_abort before calibration.
        err_code = nrf_drv_saadc_buffer_convert(adc_buf_adc[1], 3);
        APP_ERROR_CHECK(err_code);
    }
}

int main(void)
{

    for (;;)
    {
        if (m_saadc_calibrate == true) 
        {
            nrf_drv_saadc_abort();
            while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS); //Trigger calibration task
            m_saadc_calibrate = false;
        }
    }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I will print my three channel ADC value every 200ms.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;printf(&amp;quot;%d-%d-%d\r\n&amp;quot;,current_sense_vol,adc_temp_vol,em_temp_vol);&lt;/p&gt;
&lt;p&gt;This works is very good and&amp;nbsp;correct.&lt;/p&gt;
&lt;p&gt;But I have a issue to need your support.&lt;/p&gt;
&lt;p&gt;As described above, My channel 0 is AIN0 / channel 1 is AIN2 / channel 2 is AIN3&lt;/p&gt;
&lt;p&gt;I expected that the arrangement of the data I printed should be 0-&amp;gt;1-&amp;gt;2&lt;/p&gt;
&lt;p&gt;But It is 1-&amp;gt;2-&amp;gt;0. Why?? Maybe I can use it, but i am confused&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Thank you.&lt;/p&gt;
&lt;p&gt;John.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: SAADC oversampling + burst mode on three channel</title><link>https://devzone.nordicsemi.com/thread/337973?ContentTypeID=1</link><pubDate>Mon, 08 Nov 2021 15:17:33 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:e59e79e6-b06f-4e76-babb-21e7363f4bd7</guid><dc:creator>Kazi Afroza Sultana</dc:creator><description>&lt;p&gt;Hi,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Thanks for the queries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.&amp;nbsp;&amp;nbsp;Oversampling + burst mode only can use on one channel, can&amp;#39;t support two or more channel. Is it right?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is actually not right.&lt;/p&gt;
&lt;p&gt;It can support two or more channel if Burst is enable for those channel. Scan mode can be combined with burst if BURST = 1 for all channel. This is because if you do not use BURST, it will sample on every channel and later will perform the averaging. In Scan + Overlapping (without burst) , you will only get the average of all the channels. On the the other hand, BURST makes sure to finish sampling on single channel before moving to the next one.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I would like to recommend you to enable BURST for the two channels, and set oversampling to the appropriate value and to trigger sample once. This will make perform (number of) measurements before averaging them and placing them in the buffer. Furthermore, I would like to ask how often you intend to perform the sampling, and if it needs to fulfill some real-time constraint or high accuracy interval, I would suggest you not to trigger the samplings using CPU (like the way you call the nrf_drv_saadc_sample() ), instead you can make use of the PP peripheral to connect an EVENT to the TASKS_SAMPLE task. In this way that sampling is triggered whenever the event occurs, without requiring the CPU intervention. S&lt;span&gt;ince the CPU may be occupied or blocked by a higher priority interrupt or similar.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;There are some explanation from previous devzone thread which you can look at as reference : &lt;a href="https://devzone.nordicsemi.com/f/nordic-q-a/26659/saacd-scan-oversample/104878#104878"&gt;&amp;nbsp;scan oversample - Nordic Q&amp;amp;A - Nordic DevZone - Nordic DevZone (nordicsemi.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;You also can look at this project contains code examples that shows how to use the nrfx SAADC driver with API v2 :&amp;nbsp;&lt;/span&gt;&lt;a href="https://github.com/NordicPlayground/nRF52-ADC-examples/tree/master/nrfx_saadc_simple_low_power_app_timer_multichannel_oversample"&gt;https://github.com/NordicPlayground/nRF52-ADC-examples/tree/master/nrfx_saadc_simple_low_power_app_timer_multichannel_oversample&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;You can send your code after making these changes.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Hope it helps. Feel free to ask further queries.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Best Regards,&lt;/p&gt;
&lt;p&gt;Kazi Afroza Sultana&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>