SAADC oversampling + burst mode on three channel

Hi,

    Sorry, I accidentally closed my last question and I don't know how to reopen it. So I create a new one to need your support.

I want to use 200ms to get ADC value from three channel and I want to get 30 times ADC value from every channel when 200ms timer trigger.

I change my code for three channel and every channel enable burst mode + oversample is 8x. Below is my setting source code.

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, &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, &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, &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         \
    }
    
// <o> SAADC_CONFIG_OVERSAMPLE  - Sample period
 
// <0=> Disabled 
// <1=> 2x 
// <2=> 4x 
// <3=> 8x 
// <4=> 16x 
// <5=> 32x 
// <6=> 64x 
// <7=> 128x 
// <8=> 256x 

#ifndef SAADC_CONFIG_OVERSAMPLE
#define SAADC_CONFIG_OVERSAMPLE 3
#endif

Also, I create a 200ms timer to call nrf_drv_saadc_sample(), like as below.

static void data_process_handler(void * p_context)
{
    uint32_t err_code;
   
    //average_adc = true;
    nrf_drv_saadc_sample();
    
    //printf("%.4f-%.4f-%.4f\r\n",real_v_current_sense,real_v_adc_temp,real_v_em_temp);
    printf("%d-%d-%d\r\n",current_sense_vol,adc_temp_vol,em_temp_vol);
}

below is my ADC callback function and calibration function in main()

void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
{
    uint32_t err_code;
  
    if (p_event->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->data.done.p_buffer, 3);             //Set buffer so the SAADC can write to it again. 
            APP_ERROR_CHECK(err_code);
        }
        
        adc_result = p_event->data.done.p_buffer[0];
        adc_temp_result = p_event->data.done.p_buffer[1];
        em_temp_result = p_event->data.done.p_buffer[2];
        
        //printf("Hello : %d-%d-%d\r\n",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->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;
        }
    }
}

I will print my three channel ADC value every 200ms. 

printf("%d-%d-%d\r\n",current_sense_vol,adc_temp_vol,em_temp_vol);

This works is very good and correct.

But I have a issue to need your support.

As described above, My channel 0 is AIN0 / channel 1 is AIN2 / channel 2 is AIN3

I expected that the arrangement of the data I printed should be 0->1->2

But It is 1->2->0. Why?? Maybe I can use it, but i am confused

Thank you.

John.

Parents
  • Hello John,

    I think you may either move the call to nrf_drv_saadc_sample() after the printf (for printing the current value of variables) and afterward, 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. To avoid the potential racing you can try this. 

    Though it depends on what you want to achieve. If triggering occurs before printf, there may be a race condition since SAADC buffer may or may not be filled with new samples before pritnf is done printing the variables.  

    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: https://infocenter.nordicsemi.com/topic/errata_nRF52832_Rev3/ERR/nRF52832/Rev3/latest/anomaly_832_86.html?cp=4_2_1_0_1_23

    You can look at this thread also: https://devzone.nordicsemi.com/f/nordic-q-a/20291/offset-in-saadc-samples-with-easy-dma-and-ble/79053#79053 

    Hope it helps.

    Best Regards, 

    Kazi Afroza Sultana

  • Hi Kazi,

         Good news. After i checked this link from you : https://devzone.nordicsemi.com/f/nordic-q-a/20291/offset-in-saadc-samples-with-easy-dma-and-ble/79053#79053 and I used PPI function. I fixed my issue. But I need more time to test it.

    I pasted my code and please help me to double check it.(Have any problem in my code?)

    I add some PPI init code in below function with my timer init

    static void timer_init(void)
    {
        uint32_t time_ms = 1; //Time(in miliseconds) between consecutive compare events
        uint32_t err_code;
        uint32_t time_ticks;
      
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        err_code = nrf_drv_timer_init(&TIMER_PRIXIMITY, &timer_cfg, timer_proximity_event_handler);
        APP_ERROR_CHECK(err_code);
        
        time_ticks = nrf_drv_timer_ms_to_ticks(&TIMER_PRIXIMITY, time_ms);
        nrf_drv_timer_extended_compare(
             &TIMER_PRIXIMITY, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
        
        nrf_drv_timer_enable(&TIMER_PRIXIMITY);
        
        uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&TIMER_PRIXIMITY, NRF_TIMER_CC_CHANNEL0);
        uint32_t saadc_sample_event_addr = nrf_drv_saadc_sample_task_get();
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
        /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, saadc_sample_event_addr);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel0);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(m_ppi_channel0);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel0, nrf_saadc_event_address_get(NRF_SAADC_EVENT_END), nrf_saadc_task_address_get(NRF_SAADC_TASK_START));
        APP_ERROR_CHECK(err_code);
    }

    And I haven't changed anything else

    Thank you.

Reply
  • Hi Kazi,

         Good news. After i checked this link from you : https://devzone.nordicsemi.com/f/nordic-q-a/20291/offset-in-saadc-samples-with-easy-dma-and-ble/79053#79053 and I used PPI function. I fixed my issue. But I need more time to test it.

    I pasted my code and please help me to double check it.(Have any problem in my code?)

    I add some PPI init code in below function with my timer init

    static void timer_init(void)
    {
        uint32_t time_ms = 1; //Time(in miliseconds) between consecutive compare events
        uint32_t err_code;
        uint32_t time_ticks;
      
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        err_code = nrf_drv_timer_init(&TIMER_PRIXIMITY, &timer_cfg, timer_proximity_event_handler);
        APP_ERROR_CHECK(err_code);
        
        time_ticks = nrf_drv_timer_ms_to_ticks(&TIMER_PRIXIMITY, time_ms);
        nrf_drv_timer_extended_compare(
             &TIMER_PRIXIMITY, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
        
        nrf_drv_timer_enable(&TIMER_PRIXIMITY);
        
        uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&TIMER_PRIXIMITY, NRF_TIMER_CC_CHANNEL0);
        uint32_t saadc_sample_event_addr = nrf_drv_saadc_sample_task_get();
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
        /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, saadc_sample_event_addr);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel0);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(m_ppi_channel0);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel0, nrf_saadc_event_address_get(NRF_SAADC_EVENT_END), nrf_saadc_task_address_get(NRF_SAADC_TASK_START));
        APP_ERROR_CHECK(err_code);
    }

    And I haven't changed anything else

    Thank you.

Children
No Data
Related