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

SAADC acquisition time jitter even when used with PPI

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);

  • Hi,

    I do not see how the acquisition time should be affected by using SoftDevice or not, this should be unrelated. As you write, PPI is unelated to the CPU, and also the SAADC sampling (once started it is independent and writes data to memory using DMA without CPU intervention).

    If you have not ensured that the HFXO always runs, the SoftDevice will enable it whenever needed, and disable it in other cases. When disabled, the HFINT (RC oscillator) is used instead. This should only give you a variation of worst case ±8 % though, so it also cannot explain what you see.

    Can you upload a full example project that I can run on a DK to test this on my end, both with and without SoftDevice?

    PS: I will be OoO during the holidays, and DevZone is not fully staffed so it may take some time before you get replies in this thread.

  • Hi Einar,

    I tried to reproduce it but had problems because the stripped down firmware worked as expected.

    Finally I realized, that the SAADC_CONFIG_LP_MODE was different.

    When SAADC_CONFIG_LP_MODE = 1, I see the jitter in the events and also the acquisition time is increased to ~32µS. When disabling low power mode, acquisition time is ~21.6µs and no jitter can be measured.

Related