This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to shorten adc time consuming?

Thanks in advanced. I'm using nrf52832 with nRF5_SDK_17.0.2. I try to measure adc time consuming as below:

......
static void event_handler(nrfx_saadc_evt_t const * p_event)
{
    ret_code_t err_code;
	
    switch (p_event->type)
    {
        case NRFX_SAADC_EVT_BUF_REQ:
			Click_start = app_timer_cnt_get();
		
            // Set up the next available buffer
            err_code = nrfx_saadc_buffer_set(&BoMo_samples[next_free_buf_index()][0], ADC_CHANNELS_IN_USE);
            APP_ERROR_CHECK(err_code);
            break;
			
        case NRFX_SAADC_EVT_DONE:
			Click_stop = app_timer_cnt_get();
			NRF_LOG_INFO("Time cost is " NRF_LOG_FLOAT_MARKER "ms.\r\n", NRF_LOG_FLOAT(1000*app_timer_cnt_diff_compute(Click_stop, Click_start)/32768.0));
......
 

I find when timer sample rate is 500ms, then adc time consuming is 249.ms, and when rate is 5ms, then adc time consuming is 2.47ms. It seems that adc always consumes half time of timer sample rate. I want to fix adc time consuming, is there any necessity of such 1/2 scale? Would any expert help me? Thanks again.

Parents
  • Hi,

    The ADC sampling itself does not take anything close to this amount of time, and the tame it takes to sample is independent of the sampling rate. Can you show more of your code to provide context, and explain with reference to that what takes time?

  • Thanks for reply. If you need more code details, please reply me:

    ......
    #define NRFX_SAADC_DEFAULT_CHANNEL_SE(_pin_p, _index)       \
    {                                                           \
        .channel_config =                                       \
        {                                                       \
            .resistor_p = NRF_SAADC_RESISTOR_DISABLED,          \
            .resistor_n = NRF_SAADC_RESISTOR_DISABLED,          \
            .gain       = NRF_SAADC_GAIN1_4,                    \
            .reference  = NRF_SAADC_REFERENCE_VDD4,         \
            .acq_time   = NRF_SAADC_ACQTIME_10US,               \
            .mode       = NRF_SAADC_MODE_SINGLE_ENDED,          \
            .burst      = NRF_SAADC_BURST_DISABLED,             \
        },                                                      \
        .pin_p          = (nrf_saadc_input_t)_pin_p,            \
        .pin_n          = NRF_SAADC_INPUT_DISABLED,             \
        .channel_index  = _index,                               \
    }
    
    #define NRFX_SAADC_DEFAULT_ADV_CONFIG                                           \
    {                                                                               \
        .oversampling      = NRF_SAADC_OVERSAMPLE_DISABLED,                         \
        .burst             = NRF_SAADC_BURST_ENABLED,                              \
        .internal_timer_cc = 0,                                                     \
        .start_on_end      = false,                                                 \
    }
    static const uint32_t saadc_sampling_rate = 500;	//sample rate update then adc time consuming update ~1/2
    static nrf_saadc_value_t BoMo_samples[ADC_CHANNELS_IN_USE];
    static uint32_t Click_start, Click_stop;
    
    static void event_handler(nrfx_saadc_evt_t const * p_event)
    {
        ret_code_t err_code;
    	
        switch (p_event->type)
        {
            case NRFX_SAADC_EVT_BUF_REQ:
    			Click_start = app_timer_cnt_get();
    		
                // Set up the next available buffer
                err_code = nrfx_saadc_buffer_set(BoMo_samples, ADC_CHANNELS_IN_USE);
                APP_ERROR_CHECK(err_code);
                break;
    			
            case NRFX_SAADC_EVT_DONE:
    		
    			Click_stop = app_timer_cnt_get();
    			NRF_LOG_INFO("Time cost is " NRF_LOG_FLOAT_MARKER "ms.\r\n", NRF_LOG_FLOAT(1000*app_timer_cnt_diff_compute(Click_stop, Click_start)/32768.0));
    ......
    }
    
    static void BoMo_monitor_init(void)
    {
        sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
        ret_code_t err_code;	
    
        nrfx_saadc_adv_config_t saadc_adv_config = NRFX_SAADC_DEFAULT_ADV_CONFIG;
        saadc_adv_config.internal_timer_cc = 0;
        saadc_adv_config.start_on_end = true;
    
        err_code = nrfx_saadc_init(NRFX_SAADC_CONFIG_IRQ_PRIORITY);
        APP_ERROR_CHECK(err_code);
     
        static nrfx_saadc_channel_t channel_configs[ADC_CHANNELS_IN_USE];
    	
    	uint8_t channel_mask = 0;
    
        for(uint8_t i = 0; i < ADC_CHANNELS_IN_USE; i++)
    	{
            nrf_saadc_input_t pin = ANALOG_INPUT_MAP[i];
            nrfx_saadc_channel_t config = NRFX_SAADC_DEFAULT_CHANNEL_SE(pin, i);
            memcpy(&channel_configs[i], &config, sizeof(config));
            channel_mask |= 1 << i;
    	}
    
        err_code = nrfx_saadc_channels_config(channel_configs, ADC_CHANNELS_IN_USE);	
        APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_saadc_advanced_mode_set(channel_mask,
                                                NRF_SAADC_RESOLUTION_14BIT,
                                                &saadc_adv_config,
                                                event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_saadc_buffer_set(BoMo_samples, ADC_CHANNELS_IN_USE);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_saadc_mode_trigger();
        APP_ERROR_CHECK(err_code);
    
    	return;
    }
    
    static void ppi_init(void)
    {
        // Trigger task sample from timer
        nrfx_err_t err_code = nrfx_ppi_channel_alloc(&m_timer_saadc_ppi_channel);
        APP_ERROR_CHECK(err_code);
        err_code = nrfx_ppi_channel_assign(m_timer_saadc_ppi_channel, 
                                           nrfx_timer_event_address_get(&m_sample_timer, NRF_TIMER_EVENT_COMPARE0),
                                           nrf_saadc_task_address_get(NRF_SAADC_TASK_SAMPLE));
        APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_ppi_channel_enable(m_timer_saadc_ppi_channel);
        APP_ERROR_CHECK(err_code);
    }
    
    static void timer_handler(nrf_timer_event_t event_type, void * p_context)
    {
    	UNUSED_PARAMETER(p_context);
    }
    
    static void BoMo_timer_init(void)
    {
        nrfx_err_t err_code;
    
        nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG;
        timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
    	
        err_code = nrfx_timer_init(&m_sample_timer, &timer_config, timer_handler);
        APP_ERROR_CHECK(err_code);
    	
        nrfx_timer_extended_compare(&m_sample_timer,
                                    NRF_TIMER_CC_CHANNEL0,
                                    nrfx_timer_ms_to_ticks(&m_sample_timer, saadc_sampling_rate),
                                    NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                    false);
    
        nrfx_timer_resume(&m_sample_timer);
    }
    
    int main(void)
    {
    ......
    
    		BoMo_monitor_init();
    		ppi_init();
    		BoMo_timer_init();
    ......
    }

    I add time count between adc request and done. The purpose is to save power, only enable a switch during adc process.

Reply
  • Thanks for reply. If you need more code details, please reply me:

    ......
    #define NRFX_SAADC_DEFAULT_CHANNEL_SE(_pin_p, _index)       \
    {                                                           \
        .channel_config =                                       \
        {                                                       \
            .resistor_p = NRF_SAADC_RESISTOR_DISABLED,          \
            .resistor_n = NRF_SAADC_RESISTOR_DISABLED,          \
            .gain       = NRF_SAADC_GAIN1_4,                    \
            .reference  = NRF_SAADC_REFERENCE_VDD4,         \
            .acq_time   = NRF_SAADC_ACQTIME_10US,               \
            .mode       = NRF_SAADC_MODE_SINGLE_ENDED,          \
            .burst      = NRF_SAADC_BURST_DISABLED,             \
        },                                                      \
        .pin_p          = (nrf_saadc_input_t)_pin_p,            \
        .pin_n          = NRF_SAADC_INPUT_DISABLED,             \
        .channel_index  = _index,                               \
    }
    
    #define NRFX_SAADC_DEFAULT_ADV_CONFIG                                           \
    {                                                                               \
        .oversampling      = NRF_SAADC_OVERSAMPLE_DISABLED,                         \
        .burst             = NRF_SAADC_BURST_ENABLED,                              \
        .internal_timer_cc = 0,                                                     \
        .start_on_end      = false,                                                 \
    }
    static const uint32_t saadc_sampling_rate = 500;	//sample rate update then adc time consuming update ~1/2
    static nrf_saadc_value_t BoMo_samples[ADC_CHANNELS_IN_USE];
    static uint32_t Click_start, Click_stop;
    
    static void event_handler(nrfx_saadc_evt_t const * p_event)
    {
        ret_code_t err_code;
    	
        switch (p_event->type)
        {
            case NRFX_SAADC_EVT_BUF_REQ:
    			Click_start = app_timer_cnt_get();
    		
                // Set up the next available buffer
                err_code = nrfx_saadc_buffer_set(BoMo_samples, ADC_CHANNELS_IN_USE);
                APP_ERROR_CHECK(err_code);
                break;
    			
            case NRFX_SAADC_EVT_DONE:
    		
    			Click_stop = app_timer_cnt_get();
    			NRF_LOG_INFO("Time cost is " NRF_LOG_FLOAT_MARKER "ms.\r\n", NRF_LOG_FLOAT(1000*app_timer_cnt_diff_compute(Click_stop, Click_start)/32768.0));
    ......
    }
    
    static void BoMo_monitor_init(void)
    {
        sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
        ret_code_t err_code;	
    
        nrfx_saadc_adv_config_t saadc_adv_config = NRFX_SAADC_DEFAULT_ADV_CONFIG;
        saadc_adv_config.internal_timer_cc = 0;
        saadc_adv_config.start_on_end = true;
    
        err_code = nrfx_saadc_init(NRFX_SAADC_CONFIG_IRQ_PRIORITY);
        APP_ERROR_CHECK(err_code);
     
        static nrfx_saadc_channel_t channel_configs[ADC_CHANNELS_IN_USE];
    	
    	uint8_t channel_mask = 0;
    
        for(uint8_t i = 0; i < ADC_CHANNELS_IN_USE; i++)
    	{
            nrf_saadc_input_t pin = ANALOG_INPUT_MAP[i];
            nrfx_saadc_channel_t config = NRFX_SAADC_DEFAULT_CHANNEL_SE(pin, i);
            memcpy(&channel_configs[i], &config, sizeof(config));
            channel_mask |= 1 << i;
    	}
    
        err_code = nrfx_saadc_channels_config(channel_configs, ADC_CHANNELS_IN_USE);	
        APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_saadc_advanced_mode_set(channel_mask,
                                                NRF_SAADC_RESOLUTION_14BIT,
                                                &saadc_adv_config,
                                                event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_saadc_buffer_set(BoMo_samples, ADC_CHANNELS_IN_USE);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_saadc_mode_trigger();
        APP_ERROR_CHECK(err_code);
    
    	return;
    }
    
    static void ppi_init(void)
    {
        // Trigger task sample from timer
        nrfx_err_t err_code = nrfx_ppi_channel_alloc(&m_timer_saadc_ppi_channel);
        APP_ERROR_CHECK(err_code);
        err_code = nrfx_ppi_channel_assign(m_timer_saadc_ppi_channel, 
                                           nrfx_timer_event_address_get(&m_sample_timer, NRF_TIMER_EVENT_COMPARE0),
                                           nrf_saadc_task_address_get(NRF_SAADC_TASK_SAMPLE));
        APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_ppi_channel_enable(m_timer_saadc_ppi_channel);
        APP_ERROR_CHECK(err_code);
    }
    
    static void timer_handler(nrf_timer_event_t event_type, void * p_context)
    {
    	UNUSED_PARAMETER(p_context);
    }
    
    static void BoMo_timer_init(void)
    {
        nrfx_err_t err_code;
    
        nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG;
        timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
    	
        err_code = nrfx_timer_init(&m_sample_timer, &timer_config, timer_handler);
        APP_ERROR_CHECK(err_code);
    	
        nrfx_timer_extended_compare(&m_sample_timer,
                                    NRF_TIMER_CC_CHANNEL0,
                                    nrfx_timer_ms_to_ticks(&m_sample_timer, saadc_sampling_rate),
                                    NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                    false);
    
        nrfx_timer_resume(&m_sample_timer);
    }
    
    int main(void)
    {
    ......
    
    		BoMo_monitor_init();
    		ppi_init();
    		BoMo_timer_init();
    ......
    }

    I add time count between adc request and done. The purpose is to save power, only enable a switch during adc process.

Children
  • Hi,

    Sampling itself consumes time in order of micro seconds (exact time depends on acquisition time and number of channels sampled), regardless of what you are seeing it is not related to sampling itself.

    Regarding your code, I see you trigger sampling via PPI, using a timer that triggers the SAMPLE task every time the timer has counted to 500 ms.

    faithself said:
    I add time count between adc request and done.

    It is not clear to me where you do this. Can you specify exactly in your code where you start and stop counting the time? As you sample with a timer triggering sampling via PPI you do not have any indication that sampling has started before it completes with this code.

    There must be some misunderstanding here, but I am not sure where. Please share more of your code and point to exactly where in your code you "measure" the time (starting point and end point). Perhaps that will make is clearer.

    Also, a few side notes, as you write that "The purpose is to save power":

    1. Using a constantly running TIMER is not power efficient. So you should use another method to sample if you want to do it in a power efficient way. If you do not need a very accurate sampling rate, then you could simply trigger sampling via SW from an app_timer. This way it would also be much easier for you to handle any tasks you need to do before sampling and after sampling in SW.
    2. If you want to sample via a TIMER triggering SAMPLE like you do now, even though it is not power efficient, then you could get the starting point of the sampling by using PPI fork connected to GPIOTE to generate an interrupt. However, this would happen when sampling starts, so you would not have time to do any thing before sampling starts (not even enable a switch). So this probably does not solve what you want to do.
  • Thanks for reply. The time counting is located at codes:

    ......
    static uint32_t Click_start, Click_stop;

    static void event_handler(nrfx_saadc_evt_t const * p_event)
    {
    ret_code_t err_code;

    switch (p_event->type)
    {
    case NRFX_SAADC_EVT_BUF_REQ:
    Click_start = app_timer_cnt_get();

    // Set up the next available buffer
    err_code = nrfx_saadc_buffer_set(BoMo_samples, ADC_CHANNELS_IN_USE);
    APP_ERROR_CHECK(err_code);
    break;

    case NRFX_SAADC_EVT_DONE:

    Click_stop = app_timer_cnt_get();
    NRF_LOG_INFO("Time cost is " NRF_LOG_FLOAT_MARKER "ms.\r\n", NRF_LOG_FLOAT(1000*app_timer_cnt_diff_compute(Click_stop, Click_start)/32768.0));
    ......
    }

    I measure time cost between signal NRFX_SAADC_EVT_BUF_REQ and NRFX_SAADC_EVT_DONE, which I take as one adc's time consuming.

    I need time to understand your other suggestions, thanks again.

  • I see. NRFX_SAADC_EVT_BUF_REQ is not related to when you start sampling, which in your code, happens by triggering the SAMPLE task via PPI using a timer.

    As stated, you need to do this in a different way. If you want to turn on something in SW before sampling and disabling it afterwards, it makes sense to use an app_timer for this. In that case you can keep most of this, but remove the code related to the timer. Instead, make a repeated app_timer with a frequency of your desired sampling frequency. In the timeout handler do the task you need to do before sampling, and either sample right away (for instance by just triggering the SAMPLE task from SW instead of PPI), or in case a delay is needed, start a single shot app_timer to use a low power delay until it is time to sample.

  • Thanks. I will follow your advice, it's easy to implement what I want. Just forget the timer that gives me a terrible weekend.

Related