How To Read SPI MISO as a GPIO?

Using nRF5340-DK, nRF Connect for VS Code 2026.1, ncs v3.1.1

I'm interfacing over a SPI bus to a custom ASIC that uses MISO as a sort of RTS/CTS kind of idea. While CS is active the ASIC raises the MISO line asynchronously with SCLK to indicate it has received the command. The ASIC lowers the MISO line asynchronously when it has the result ready to be read. Then the microcontroller finishes the SPI transaction and de-asserts CS.

So, my firmware needs to do this:

1. Assert CS
2. Send several bytes that form the command
3. Wait for asynchronous MISO high to low transition
4. Send dummy bytes to clock in the response
5. De-assert CS

I'm using spi4 as defined in the default device tree. CS is a GPIO controlled by my firmware (as set up in the spi_config struct).

The SPI bus is working to read/write individual registers in the typical way using this Zephyr function: spi_transceive(spec->bus, &spec->config, tx_bufs, rx_bufs);

How can I access MISO as a GPIO to accomplish step 3?

Thanks,
Dan

Parents
  • Hello,

    If you have tried setting up the pin as a GPIO before, it should be pretty straight forward. What you need to do is to suspend the SPI instance that you are using, then enable it as an input pin. After you have received the interrupt, disable it as an input pin, and re-enable the SPI instance. 

    Make sure that you have this in your prj.conf to be able to suspend peripherals:

    CONFIG_PM_DEVICE=y

    And then you can try something like this:

    #include <zephyr/device.h>
    #include <zephyr/pm/device.h>
    
    /* Get the device binding for SPI0 */
    const struct device *spi0_dev = DEVICE_DT_GET(DT_NODELABEL(spi0));
    
    void suspend_spi0(void) {
        if (device_is_ready(spi0_dev)) {
            /* Put the peripheral into suspended state */
            int err = pm_device_action_run(spi0_dev, PM_DEVICE_ACTION_SUSPEND);
            if (err) {
                // Handle error
            }
        }
    }

    Then use a similar method to enable your input pin.

    To enable the SPI again, use:

    int err = pm_device_action_run(spi0_dev, PM_DEVICE_ACTION_RESUME);

    Best regards,

    Edvin

Reply
  • Hello,

    If you have tried setting up the pin as a GPIO before, it should be pretty straight forward. What you need to do is to suspend the SPI instance that you are using, then enable it as an input pin. After you have received the interrupt, disable it as an input pin, and re-enable the SPI instance. 

    Make sure that you have this in your prj.conf to be able to suspend peripherals:

    CONFIG_PM_DEVICE=y

    And then you can try something like this:

    #include <zephyr/device.h>
    #include <zephyr/pm/device.h>
    
    /* Get the device binding for SPI0 */
    const struct device *spi0_dev = DEVICE_DT_GET(DT_NODELABEL(spi0));
    
    void suspend_spi0(void) {
        if (device_is_ready(spi0_dev)) {
            /* Put the peripheral into suspended state */
            int err = pm_device_action_run(spi0_dev, PM_DEVICE_ACTION_SUSPEND);
            if (err) {
                // Handle error
            }
        }
    }

    Then use a similar method to enable your input pin.

    To enable the SPI again, use:

    int err = pm_device_action_run(spi0_dev, PM_DEVICE_ACTION_RESUME);

    Best regards,

    Edvin

Children
No Data
Related