I need a constant acquisition time for my SAADC. In my experiements I see jitter in the acquisition time, so I started debugging with PPI to ensure no Interrupts are making issues.
My setup is as following with PPI and EGU:
- The EGU is used to create a start event
- The EGU event triggers a GPIOTE task via PPI to clear a pin.
- The same PPI channel is forked to start the SAADC sample task.
- The NRF_SAADC_EVENT_DONE event is used via another PPI channel to the set the same pin again.
SAADC is set up to sample a single ADC with 20uS acquisition time.
The sampling is triggered when I call
nrf_egu_task_trigger(NRF_EGU0, NRF_EGU_TASK_TRIGGER0);
When running the code standalone, everything looks fine on a scope. The pin is cleared for ~21.5uS and then set again.
When running the code in an application with BLE enabled, I see some strange behavior.
1. The pin is cleared most of the time for about 32uS. Why does the acquisition take longer when BLE is enabled vs the expected ~21.5 as seen above? The code is exactly the same.
2. Sometimes (about once a second or so) I see a jitter on the pin and it is cleared for a longer time e.g. 40uS, 80uS or about 128uS.
I thought, the PPI and the SAADC sample task and EVENT_DONE are completely unaware of the CPU and was expecting the same behavior as without ble.
What could be the reason for the jitter and how to avoid it? Is there any peripheral disturbing the SAADC?
Below you can see the code to initialize the PPI channels.
if (!nrfx_gpiote_is_init()) {
APP_ERROR_CHECK(nrfx_gpiote_init());
}
// set gpiote to set the pin low on an event
nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_TASK_LOW;
APP_ERROR_CHECK(nrf_drv_gpiote_out_init(p_config->output_pin, &out_config));
nrf_ppi_channel_t ppi_channel_sample_start;
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_sample_start);
APP_ERROR_CHECK(err_code);
// it seems the function returns in newer versions an uint32_t
// https://github.com/NordicSemiconductor/nrfx/blob/master/hal/nrf_egu.h
uint32_t egu_evt_addr =
(uint32_t)nrf_egu_event_address_get(NRF_EGU0, NRF_EGU_EVENT_TRIGGERED0);
uint32_t gpiote_clear_task_addr =
nrfx_gpiote_clr_task_addr_get(p_config->output_pin);
err_code = nrf_drv_ppi_channel_assign(ppi_channel_sample_start, egu_evt_addr,
gpiote_clear_task_addr);
APP_ERROR_CHECK(err_code);
uint32_t saadc_task_addr = nrf_drv_saadc_sample_task_get();
// set ppi_channel_fork to trigger ssadc sample task at the same time as the gpiote task
err_code = nrf_drv_ppi_channel_fork_assign(ppi_channel_sample_start,
saadc_task_addr);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(ppi_channel_sample_start);
APP_ERROR_CHECK(err_code);
// // use a second ppi channel to set the pin again
nrf_ppi_channel_t ppi_channel_set_out_pin;
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_set_out_pin);
APP_ERROR_CHECK(err_code);
uint32_t saadc_done_evt_addr =
nrf_saadc_event_address_get(NRF_SAADC_EVENT_DONE);
uint32_t gpiote_set_task_addr =
nrfx_gpiote_set_task_addr_get(p_config->output_pin);
err_code = nrf_drv_ppi_channel_assign(
ppi_channel_set_out_pin, saadc_done_evt_addr, gpiote_set_task_addr);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(ppi_channel_set_out_pin);
APP_ERROR_CHECK(err_code);
// finally enable the tasks on output_pin
nrfx_gpiote_out_task_enable(p_config->output_pin);