This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Create a bi-directional pin using PPI

I'm working on a driver for a sensor which uses a proprietary one-wire interface. To get data out of the device, we do the following:
1) switch the pin to output
2) 1 us low
3) 1 us high
4) Switch the pin to input
5) wait 8 us for the signal to settle
6) read the pin value
.. and this loops for the number of bits we need to read.

I have been working on a design using PPI. The issue I'm running into is that the pin needs to switch between input and output. Originally I had planned to use a 3-state buffer external to the chip and use the PPI+Timer CC to control that. However, we have ben told that we can overcome this by using 2 pins: one configured as input and one as output. This is the exact answer we received from Nordic (Håkon):

"Not with a single GPIO. You can achieve this functionality by using two GPIOs that are both connected to the DIRECT LINK pin. You can then turn on or off the PPI channel associated with a GPIO via the PPI task (nrf_ppi_task_t).

The input pin must be connected to the disable task of it's own PPI channel as well as the enable task of the output pins PPI channel (forked PPI event). "


I've been going thorugh the documentation and tried some examples and have a hard time figuring out how this would work. The docs state:

“When Event mode is selected in CONFIG.MODE, the pin specified by CONFIG.PSEL will be configured as
an input, overriding the DIR setting in GPIO. Similarly, when Task mode is selected in CONFIG.MODE, the
pin specified by CONFIG.PSEL will be configured as an output overriding the DIR setting and OUT value
in GPIO.”


That seemed encouraging, and for a while I was under the impression the PPI can use the PPI Group Tasks (enable/Disable, NRF_PPI->CHG, NRF_PPI->TASKS_CHG[0].DIS) to switch between input (default GPIO config) and output (GPIOTE config).

However, I have not been successful and am wondering if this is possible at all. Am I missing something?


Thanks,
Dirk

Parents
  • Hey Dirk,

    I believe I've made a mistake.

    You cannot disable a GPIOTE pin via PPI once it's configured as an output, you can only disconnect it from the PPI system. It will drive the input pin to whatever voltage of its last state.  

    This means that you will need to reconfigure the output pins direction via CPU. The good news is that you will only need one pin instead of two. 

    You should use a TIMER to control the output pin. Create a one-shot TIMER with COMPARE0 event connected to the output pins GPIOTE toggle task (initial GPIO state high), COMPARE1 event connected to the output pins GPIOTE toggle task, and COMPARE2 event to fire a CPU interrupt.

    COMPARE0 can be set to whatever time you want, it starts the sequence of events by pulling the output pin low. COMPARE1 needs to be set 1µs after COMPARE0 and COMPARE2 needs to be set 1µs after COMPARE1.

    Cheers,

    Håkon.

Reply
  • Hey Dirk,

    I believe I've made a mistake.

    You cannot disable a GPIOTE pin via PPI once it's configured as an output, you can only disconnect it from the PPI system. It will drive the input pin to whatever voltage of its last state.  

    This means that you will need to reconfigure the output pins direction via CPU. The good news is that you will only need one pin instead of two. 

    You should use a TIMER to control the output pin. Create a one-shot TIMER with COMPARE0 event connected to the output pins GPIOTE toggle task (initial GPIO state high), COMPARE1 event connected to the output pins GPIOTE toggle task, and COMPARE2 event to fire a CPU interrupt.

    COMPARE0 can be set to whatever time you want, it starts the sequence of events by pulling the output pin low. COMPARE1 needs to be set 1µs after COMPARE0 and COMPARE2 needs to be set 1µs after COMPARE1.

    Cheers,

    Håkon.

Children
  • No problem! Thanks for the fast response. 

    The second reason for using just the PPI, which I should have mentioned, is to be able to guarantee the PIR waveform timing. The issue with using the CPU for any aspect of the read-out process is that the Softdevice might interfere and we end up not making the timing specs for the PIR sensor (some parts of the waveform need to be timed within  < 2us). With the Softdevice doing its own thing, this is almost guaranteed to be an issue.

    I've got the waveform generation covered like you mention with timers and CC-events/GPIOTE tasks. The plan was to clock the data into the SPI peripheral (slave mode). If I'm going to use IRQs, that's no longer necessary. I just need to be able to generate IRQs timely (without Softdevice shenanigans).

    If you don't mind, could you look at some ideas to get around the issue (which don't involve changing the HW) to make sure I am not missing potentially better options?

    1) Make sure the Softdevice is not used or even disabled while we're sampling from the sensor. I noticed this thread which suggests this is possible: https://devzone.nordicsemi.com/f/nordic-q-a/24426/disabling-s132-softdevice-when-running-freertos. However, this option will require some major changes in the current application-level code which is relying on the Softdevice to always be enabled.

    2) A little ugly, but...change the vector table so we have a hook into this and can re-direct the SD -IRQ (level 0) handler and forward this from our  super-short "change-pin-direction" handler.

    3) Even uglier: Use the PPI/MWU + some other peripheral with EasyDMA to generate a NMI which we can then use as our IRQ handler to change the pin direction.

    4) Blasphemy...but: In theory I could edit the Softdevice binary to change the IRQ (level 0) to a lower level such that my application. I am guessing that this is a no-go (Nordic user agreement violation?), but wanted to mention it nonetheless in case someone has done it before.

    Now ideally there would have been a task in the GPIOTE peripheral to set direction on a pin. This would at least for my case really be a useful feature for the next nRF52 SoC. Just say'in!

    Thanks,

    Dirk

Related