NRF_SAADC_EVENT_DONE appears delayed causing inconsistent ADC read timing

I have configured the ADC on my nRF52832 to trigger a read based on a PPI timer. I am using EasyDMA to capture 75 samples via double buffering. My PPI timer is configured to fire an ADC sample task every 1ms.

   nrf_ppi_channel_endpoint_setup(NRF_PPI_CHANNEL6,(uint32_t)nrf_timer_event_address_get(NRF_TIMER3,  NRF_TIMER_EVENT_COMPARE0), nrf_drv_saadc_sample_task_get());

I have scoped the signals and see that the NRF_SAADC_EVT_STARTED event is occurring every 1ms as expected. However, my NRF_SAADC_EVENT_DONE event is delayed by 3-4ms at times. This delay in getting the DONE event seems to occur every 500ms or so. When this occurs, it means I am taking ~78ms to read 75 samples which causes synchronization problems in our application.

I am looking for some guidance on where this delay may be coming from or configurations to check as I am out of ideas for next steps. I understand that you don't have access to all of my firmware code; but, I have commented out just about everything and this delay is still occurring. I am running SoftDevice S132 v7.3.0 with SDK 16.0.0. I have an active BLE connection while acquisition is occurring but I have removed all notifications just in case that was causing the hang. Other than BLE and ADC acquisition, I have debug logging enabled and call NRF_LOG_PROCESS() before calling nrf_pwr_mgmt_run() in my idle_state_handler() method. Very simple stuff at this point.

The attached image shows what I am seeing. The RED wave is the SAMPLE task, the GREEN wave is the DONE event and the BLUE wave toggles upon each call to my ADC callback upon DMA buffer full (NRF_DRV_SAADC_EVT_DONE). You can see that there is a gap in the GREEN wave form which has a width of ~4ms in this image (3ms longer than expected). You can see the widths of the good samples and the corrupted samples in the Timing Markers section on the right of the screen shot. Again, what might cause the ADC done event to be delayed  like this?

Any thoughts or suggestions would be much appreciated.

Thanks!

-Mike

Parents
  • Hello,

    How do you measure the delay for the NRF_SAADC_EVENT_DONE event? As far as I can tell, you didn't show how you did this. If you toggle the pin in an event handler, then this event handler may be delayed even though the event actually happened on time. The 3-4ms delay looks like something that can be caused by the softdevice. The softdevice always has the highest priority.

    Try toggling the pin on the NRF_SAADC_EVENT_DONE event using PPI, and see if it is still delayed.

    Best regards,

    Edvin

  • Hi Edvin,

    I am measuring the DONE event using PPI. Sorry I didn't show this code in my original post.

        NRF_GPIOTE->CONFIG[0] = ((GPIOTE_CONFIG_MODE_Task   << GPIOTE_CONFIG_MODE_Pos) |
                                 (LED_RED                   << GPIOTE_CONFIG_PSEL_Pos) |
                                 (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos));
    
        NRF_GPIOTE->CONFIG[1] = ((GPIOTE_CONFIG_MODE_Task   << GPIOTE_CONFIG_MODE_Pos) |
                                 (LED_GREEN                   << GPIOTE_CONFIG_PSEL_Pos) |
                                 (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos));
    
        nrf_ppi_fork_endpoint_setup(NRF_PPI_CHANNEL6, (uint32_t) &NRF_GPIOTE->TASKS_OUT[0]);
    
        nrf_ppi_channel_endpoint_setup(NRF_PPI_CHANNEL10,
            (uint32_t) nrf_saadc_event_address_get(NRF_SAADC_EVENT_DONE),
            (uint32_t) &NRF_GPIOTE->TASKS_OUT[1]);
    

    The blue measurement is being done inside of the ADC callback handler. The Red and Green timings are being done via PPI pin toggles.

    I should also add that when I connected the NRF_SAADC_EVENT_STARTED to a PPI channel, I saw no delays  they were always right in sync with my 1ms Timer.

    -Mike

Reply
  • Hi Edvin,

    I am measuring the DONE event using PPI. Sorry I didn't show this code in my original post.

        NRF_GPIOTE->CONFIG[0] = ((GPIOTE_CONFIG_MODE_Task   << GPIOTE_CONFIG_MODE_Pos) |
                                 (LED_RED                   << GPIOTE_CONFIG_PSEL_Pos) |
                                 (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos));
    
        NRF_GPIOTE->CONFIG[1] = ((GPIOTE_CONFIG_MODE_Task   << GPIOTE_CONFIG_MODE_Pos) |
                                 (LED_GREEN                   << GPIOTE_CONFIG_PSEL_Pos) |
                                 (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos));
    
        nrf_ppi_fork_endpoint_setup(NRF_PPI_CHANNEL6, (uint32_t) &NRF_GPIOTE->TASKS_OUT[0]);
    
        nrf_ppi_channel_endpoint_setup(NRF_PPI_CHANNEL10,
            (uint32_t) nrf_saadc_event_address_get(NRF_SAADC_EVENT_DONE),
            (uint32_t) &NRF_GPIOTE->TASKS_OUT[1]);
    

    The blue measurement is being done inside of the ADC callback handler. The Red and Green timings are being done via PPI pin toggles.

    I should also add that when I connected the NRF_SAADC_EVENT_STARTED to a PPI channel, I saw no delays  they were always right in sync with my 1ms Timer.

    -Mike

Children
  • Hello Mike,

    I wouldn't think that there would be a delay like this. Is it possible to reproduce this using an nRF52832 DK? If so, would it be possible for you to send the stripped down version of your application so that I can reproduce it? How is your timer set up? Have you enabled the clear on Clear on compare register, COMPARE0_CLEAR or does the clock roll around?

    Perhaps things will be clearer if I see more of the PPI setup and can test it for myself.

    Best regards,

    Edvin

  • Hi Edvin,

    I put all of my PPI configurations, as they related to the ADC acquisition, into the saadc_pca10040 sample application. As expected, the timing works perfectly with no delays.

    I am working on stripping our firmware down to a demo app that I can send to you; but, it might take a day or so. There is quite a bit of code that I can't send in this public area. And stripping it down could remove the cause of the issue.

    The code does run on the PCA10040 DK board via a #define in my app_config.h file and is what I have been using to measure the timing problem. It is much easier to connect the probes to the DK than to test points on our custom board. Is there a way for me to send you the code in a secure, private way?

    Thanks,

    -Mike

  • Hello Mike,

    The best would be if you could strip out any sensitive information and just upload it here. One of the reasons for this is that it is easier to figure out what is going on if there is as little as possible other things in the application. Only the parts needed to recreate the issue. 

    If it is not possible to strip out everything, then you can send the attachment in a personal message to me here on DevZone. Please only use the PM to send the attachment (and a link to this ticket), and let me know in this thicket when you have done so, as we do not have a system for "handled" and "unhandled" messages in the DM system. 

    Best regards,

    Edvin

  • Hi Edvin,

    I discovered the issue in my code base. I have setup an APP_TIMER that fires every 500msec. Inside the handler of that timer, I do some I2C communications. Any delays in that communication can cause the ADC event firing to be delayed. I don't understand how the APP_TIMERs are setup in hardware; but they apparently are managed via an interrupt that causes other interrupts (ADC events) to be delayed. I have removed the I2C communication from the timer callback and just set a flag, in essence, and call the I2C code in the main loop.

    Best,

    -Mike

Related