Using the DPPI on the nRF5340 to enable the ADC and GPIO toggling based on a hardware timer

Hi,

I need to enable the ADC read and GPIO pin toggling to happen simultaneously at high precision, without using the MCU resources, approximately 15 us interval. After searching through this forum, I realized the only way to achieve this precision is to use DPPI in the nrfx drivers directly, instead of using the Zephyr drivers.

I successfully enabled the timer1 that triggers the ADC read configured in the DPPI, and another set of code to use the same timer that toggles the GPIO pin also configured in the DPPI but I cannot set them together. Here are snippets of my code for configuring DPPI:

In the API reference, DPPI does not allow one task or event to associate with more than one channel. In my case, ideally, I would like to toggle the GPIO pin based on the timer1 and also triggers the ADC read every time the GPIO toggles, at the rising edge and falling edge.

Can you suggest a method to seamlessly enable the ADC read and GPIO pin toggling with the timer1 configured in DPPI? Maybe there is a way to set a GPIO pin to the PWM based on the timer1 while triggering the ADC read in DPPI?

Thanks!

Parents
  • Hi,

    When you alloc a dppi channel, then you can use this channel to connect severval publishers and subcribers, e.g. in this case you want to set the allocated channel to the TIMER->PUBLISH_COMPARE[] register:
    https://infocenter.nordicsemi.com/topic/ps_nrf5340/timer.html#register.PUBLISH_COMPARE

    And then for each peripheral that you want to do something based on this event, then you need to set the subscribe, e.g. in your case set the came dppi channel to SAADC->SUBSCRIBE_START and GPIOTE->SUBSCRIBE_OUT[]:
    https://infocenter.nordicsemi.com/topic/ps_nrf5340/saadc.html#register.SUBSCRIBE_START 
    https://infocenter.nordicsemi.com/topic/ps_nrf5340/gpiote.html#register.SUBSCRIBE_OUT 

    Best regards,
    Kenneth

  • Hello Kenneth,

    Thanks for the info. Do you have any SDK examples available for subscribing to those DPPI channels? It seems like the nrfx drivers do not offer many examples in the SDK...

    Ted

  • I can find various code that show this to some degree, for instance ppi_init() from esb.c

Reply
  • I can find various code that show this to some degree, for instance ppi_init() from esb.c

Children
  • So here is what I did but I still cannot get the ADC read working... The GPIO pin toggling only works. Am I missing something here?

  • Try something like this:

  • Kenneth, the SAADC still doesn't work with your code but I managed to make it work!

    The SAADC driver worked with the following code, but this helper layer didn't work to assign a single event to trigger multiple tasks:

    So, instead of setting:
    NRF_SAADC->SUBSCRIBE_START = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | dppi_channel_0;

    I modified it to:
    NRF_SAADC->SUBSCRIBE_SAMPLE = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | dppi_channel_0;

    Then the GPIO pin toggling worked simultaneously with the SAADC read!

    Here is the portion of the code that allowed me to do that:

    Can you clarify why the original helper layer didn't work but this publish/subscribe method worked? I was able to find another approach here, and it ties the publish and subscribe sets like this:

    I wonder which approach works best with setting up the DPPI module because I intend to use the DPPI more widely now and then. Can you explain why this approach failed to read the ADC channel but only the GPIO pin toggling worked:

    Thank you for leading to the answer I was looking for!

    Ted

  • I must admit I was not paying attention to whether you were using START or SAMPLE, my main focus was how to setup publish to several subscribers. But you are right, you should use SAMPLE to actually SAMPLE the analog input, while START simply prepare the ADC for the SAMPLE task. In general you may find the hardware description useful:
    https://infocenter.nordicsemi.com/topic/ps_nrf5340/saadc.html 

    In terms of which api to use when setting up the publish and subscribe, I was looking at how you can write to the registers directly, but you can also setup this with a more convenient api like you have found also (they do the same, one is just a wrapper around the other).

    Glad to hear you have made it work!

    Kenneth