This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

SAADC - Real sample rate is a bit higher than the configured sample rate

Hello,

in my project I have a custom board with a nRF52832 chip, which reads 4 channels with a sample rate of 1kHz (1ms). The SAADC readings get transmitted to a nRF52840DK via NUS every 40ms. Overall, this setup works fine and I receive the right SAADC readings. 

But I noticed something weird. I configured a sample rate of 1kHz, so I should get 1000 values for each channel every second. But my real sample rate is about 1.020 kHz, so I get about 1020 values for each channel every second.

This is how my SAADC is configured:

#define SAADC_SAMPLES_IN_BUFFER         4
#define SAADC_SAMPLE_RATE               1

void saadc_sampling_event_init(void)
{
    ret_code_t err_code;
    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);
    
    nrf_drv_timer_config_t timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_config.frequency = NRF_TIMER_FREQ_31250Hz;                                         
    err_code = nrf_drv_timer_init(&m_timer, &timer_config, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer,SAADC_SAMPLE_RATE);
    nrf_drv_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer, NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_event_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(&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);
}

void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
    APP_ERROR_CHECK(err_code);
}

void saadc_init(void)
{
    ret_code_t err_code;
	
    nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
    saadc_config.resolution = NRF_SAADC_RESOLUTION_10BIT;
    
    nrf_saadc_channel_config_t channel_0_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);     
    channel_0_config.gain = NRF_SAADC_GAIN1_4;
    channel_0_config.reference = NRF_SAADC_REFERENCE_VDD4;
	
    nrf_saadc_channel_config_t channel_1_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5);
    channel_1_config.gain = NRF_SAADC_GAIN1_4;
    channel_1_config.reference = NRF_SAADC_REFERENCE_VDD4;

    nrf_saadc_channel_config_t channel_2_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);   
    channel_2_config.gain = NRF_SAADC_GAIN1_4;
    channel_2_config.reference = NRF_SAADC_REFERENCE_VDD4;

    nrf_saadc_channel_config_t channel_3_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
    channel_3_config.gain = NRF_SAADC_GAIN1_4;
    channel_3_config.reference = NRF_SAADC_REFERENCE_VDD4;	                           
	
    err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(1, &channel_1_config);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(2, &channel_2_config);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(3, &channel_3_config);
    APP_ERROR_CHECK(err_code);	

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0],SAADC_SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);   
    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1],SAADC_SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);

}

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        ret_code_t err_code;
        // set buffers
        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
        ...
    }
}
 

So here are my questions:

1. Why is the real sample rate is a bit higher than the configured sample rate?

2. Do you have any suggestions how to solve this issue?

Setup: nRF5_SDK_17.0.0_9d13099, Softdevice s132 on custom nRF52832 chip

Thank you very much in advance.

  • Relevant code:

    timer_config.frequency = NRF_TIMER_FREQ_31250Hz; 

    That frequency has no available integer divider in order to achieve exactly 1 kHz.

    Just use NRF_TIMER_FREQ_125kHz or higher.

  • Hello Turbo J,

    thank you very much for your fast reply.

    It looks like you fixed my problem.

    I wish you a great day. :)

  • Hello, 

    I was able to fix the problem for my nrf52832 on my development board. It works just fine there.

    But on my custom board with the nrf52832 chip it does not work. Maybe it has something to do with the timer source. On the custom board, the SoftDevice uses NRF_CLOCK_LF_SRC_RC instead of NRF_CLOCK_LF_SRC_XTAL.

    Here are my questions:

    1. Is this a problem of the timer source?

    2. Which timer does the SAADC use by default?

    Thank you so much in advance.

  • Can you try to start the HFCLK here by nrf_drv_clock_hfclk_request(NULL). The internal HFCLK is not accurate (typical 1-2% tolerance).

    Kenneth

  • Hello Kenneth,

    thank you very much for your response.

    I added this request into my saadc_sampling_event_init(void) function:

    void saadc_sampling_event_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
        
        nrf_drv_timer_config_t timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
        timer_config.frequency = NRF_TIMER_FREQ_125kHz;                                                             
        err_code = nrf_drv_timer_init(&m_timer, &timer_config, timer_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_clock_hfclk_request(NULL);
    
        /* setup m_timer for compare event */
        uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer,SAADC_SAMPLE_RATE);
        nrf_drv_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
        nrf_drv_timer_enable(&m_timer);
        
        ...
        
    }

    It looks like, this fixed my problem. Thank you for that. It seems that the HFCLK consumes about 150µA.

    Do you recommend to call nrf_drv_clock_hfclk_request(NULL) in the saadc_sampling_event_init(void) function or somewhere else?

    Thank you in advance.

    Michael

Related