Timer/SAADC/(D)PPI differences between nRF52840 & nRF5340

Hi team !

I'm facing issue when porting my code from nRF52840DK to nRF5340DK

I implemented SAADC acquisition, using Timer/SAADC/(D)PPI stack on both boards, handling the few differences I found (i.e: nrfx_ppi_channel... vs nrfx_dppi_channel... functions, includes, etc).
So I got my code running on both boards, but I still see a huge difference I can't tell where it comes:

As I log some timing values at runtime, I can see how long my firmware takes to do a full loop (ADC acquisition, writing buffer in flash/sending buffer through BLE, depending on the situation).
- With the nRF52840, I have a 100ms loop, as expected. During this time, I take 100 ADC samples from 1 channel, get it in my main() from ADC queue, and handle it.
- With the nRF5340, the same code take 400ms to do a loop, everything else is OK.

The only way I found to fix this delta is to divide by 4 the compare value I set when calling nrfx_timer_compare(), from 1000 (1ms @ 1MHz), to 250 (don't really know what this value means in this situation...).

My question is: why do I have to change this compare value and is it the best way to achieve my goal ?

Thanks in advance for your support.

Guillaume

const nrfx_timer_t m_sample_timer = NRFX_TIMER_INSTANCE(1);
const uint32_t saadc_sampling_rate = 1; // milliseconds (ms)

void timer_init(void)
{
    // SAADC timer config
    nrfx_timer_config_t timer_config_sample = {
            .frequency = NRF_TIMER_FREQ_1MHz,
            .mode = NRF_TIMER_MODE_TIMER,
            .bit_width = NRF_TIMER_BIT_WIDTH_32,
            .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY
        };
    // Hot fix for code compatibility 5340DK vs 52840DK
    #ifdef DPPI_PRESENT
        int compare_value = 250;
    #else
        int compare_value = 1000;
    #endif
    
        err_code = nrfx_timer_init(&m_sample_timer, &timer_config_sample, timer_handler);
        if(err_code != NRFX_SUCCESS) {
            printk("Unable to init sampling timer (error %d)", err_code);
        }
        nrfx_timer_compare(&m_sample_timer,
                                    NRF_TIMER_CC_CHANNEL0,
                                    nrfx_timer_us_to_ticks(&m_sample_timer, saadc_sampling_rate * compare_value),
                                    false);
        nrfx_timer_compare(&m_sample_timer,
                                    NRF_TIMER_CC_CHANNEL1,
                                    nrfx_timer_us_to_ticks(&m_sample_timer, saadc_sampling_rate * compare_value * 2),
                                    false);
        nrfx_timer_compare(&m_sample_timer,
                                    NRF_TIMER_CC_CHANNEL2,
                                    nrfx_timer_us_to_ticks(&m_sample_timer, saadc_sampling_rate * compare_value * 3),
                                    false);
        nrfx_timer_extended_compare(&m_sample_timer,
                                    NRF_TIMER_CC_CHANNEL3,
                                    nrfx_timer_us_to_ticks(&m_sample_timer, saadc_sampling_rate * compare_value * 4),
                                    NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK,
                                    false);
    
    nrfx_timer_resume(&m_sample_timer);
}

Config:

- Windows_NT x64 v10.0.19042
- VSCode v1.65.2
- nRF Connect for VS Code v2022.3.104

Parents
  • Hi,

    The only difference I can think of would be that one of the devices have oversampling enabled in some config, while the other does not. If oversampling is set to 4X without enabling BURST, you would need to sample 4 times for each result to be generated. However, with SCAN mode (multiple channels enabled), without BURST enabled, this would generate the wrong results.

    Can you post your config and all code for using SAADC?

    Best regards,
    Jørgen

  • And here is the function to configure ppi.

    void ppi_init(void)
    {
        nrfx_err_t err;
        nrf_timer_event_t evt_compare[4] = {
            NRF_TIMER_EVENT_COMPARE0,
            NRF_TIMER_EVENT_COMPARE1,
            NRF_TIMER_EVENT_COMPARE2,
            NRF_TIMER_EVENT_COMPARE3
        };
    
    #if defined(DPPI_PRESENT)
    
    	uint8_t m_timer_saadc_ppi_channel[4];
    
        for (int i = 0; i < 4; i++) {
        	err = nrfx_dppi_channel_alloc(&m_timer_saadc_ppi_channel[i]);
            if (err != NRFX_SUCCESS) {
                printk("SAADC (D)PPI channel allocation error: %08x\n", err);
                return;
            }
        }
    #else
    	uint8_t m_timer_saadc_ppi_channel[4];
    
        for (int i = 0; i < 4; i++) {
        	err = nrfx_ppi_channel_alloc(&m_timer_saadc_ppi_channel[i]);
            if (err != NRFX_SUCCESS) {
                printk("SAADC (D)PPI channel allocation error: %08x\n", err);
                return;
            }
        }
    #endif
    
        for (int i = 0; i < 4; i++) {
            nrfx_gppi_channel_endpoints_setup(m_timer_saadc_ppi_channel[i],
                nrfx_timer_event_address_get(&m_sample_timer, evt_compare[i]),
                nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_SAMPLE));
        }
        
    	/* Enable (D)PPI channel. */
    #if defined(DPPI_PRESENT)
        for (int i = 0; i < 4; i++) {
        	err = nrfx_dppi_channel_enable(m_timer_saadc_ppi_channel[i]);
            if (err != NRFX_SUCCESS) {
                printk("Failed to enable SAADC (D)PPI channel, error: %08x", err);
                return;
            }
        }
    #else
        for (int i = 0; i < 4; i++) {
        	err = nrfx_ppi_channel_enable(m_timer_saadc_ppi_channel[i]);
            if (err != NRFX_SUCCESS) {
                printk("Failed to enable SAADC (D)PPI channel, error: %08x", err);
                return;
            }
        }
    #endif
    }

    Then, I finally use this in my program's main loop.

    void main(void)
    {
        [...]
        while(1) {
            time_start_sampling = k_uptime_get();
    	    k_msgq_get(getADCQueue(), &adc_buffer, K_FOREVER);
    	    time_end_sampling = k_uptime_get();
        	memcpy(buffer, adc_buffer, sizeof(adc_buffer));
        [...]
        }
    }

Reply
  • And here is the function to configure ppi.

    void ppi_init(void)
    {
        nrfx_err_t err;
        nrf_timer_event_t evt_compare[4] = {
            NRF_TIMER_EVENT_COMPARE0,
            NRF_TIMER_EVENT_COMPARE1,
            NRF_TIMER_EVENT_COMPARE2,
            NRF_TIMER_EVENT_COMPARE3
        };
    
    #if defined(DPPI_PRESENT)
    
    	uint8_t m_timer_saadc_ppi_channel[4];
    
        for (int i = 0; i < 4; i++) {
        	err = nrfx_dppi_channel_alloc(&m_timer_saadc_ppi_channel[i]);
            if (err != NRFX_SUCCESS) {
                printk("SAADC (D)PPI channel allocation error: %08x\n", err);
                return;
            }
        }
    #else
    	uint8_t m_timer_saadc_ppi_channel[4];
    
        for (int i = 0; i < 4; i++) {
        	err = nrfx_ppi_channel_alloc(&m_timer_saadc_ppi_channel[i]);
            if (err != NRFX_SUCCESS) {
                printk("SAADC (D)PPI channel allocation error: %08x\n", err);
                return;
            }
        }
    #endif
    
        for (int i = 0; i < 4; i++) {
            nrfx_gppi_channel_endpoints_setup(m_timer_saadc_ppi_channel[i],
                nrfx_timer_event_address_get(&m_sample_timer, evt_compare[i]),
                nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_SAMPLE));
        }
        
    	/* Enable (D)PPI channel. */
    #if defined(DPPI_PRESENT)
        for (int i = 0; i < 4; i++) {
        	err = nrfx_dppi_channel_enable(m_timer_saadc_ppi_channel[i]);
            if (err != NRFX_SUCCESS) {
                printk("Failed to enable SAADC (D)PPI channel, error: %08x", err);
                return;
            }
        }
    #else
        for (int i = 0; i < 4; i++) {
        	err = nrfx_ppi_channel_enable(m_timer_saadc_ppi_channel[i]);
            if (err != NRFX_SUCCESS) {
                printk("Failed to enable SAADC (D)PPI channel, error: %08x", err);
                return;
            }
        }
    #endif
    }

    Then, I finally use this in my program's main loop.

    void main(void)
    {
        [...]
        while(1) {
            time_start_sampling = k_uptime_get();
    	    k_msgq_get(getADCQueue(), &adc_buffer, K_FOREVER);
    	    time_end_sampling = k_uptime_get();
        	memcpy(buffer, adc_buffer, sizeof(adc_buffer));
        [...]
        }
    }

Children
  • I can't see any obvious issues that should be causing this in the code.

    Can you read out and post the SAADC, TIMER1 and (D)PPI registers using a debugger after the initialization part of the code is done, on both devices, to see if there is any differences in the actual configuration?

    Do you have a minimal sample, with the code you have posted, that we can use to reproduce/debug this issue?

Related