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

GPIO config propagation delay

I have a button matrix (2 rows, multiple columns) connected to an nRF52840. After driving the two row pins appropriately, the first column pin I read (regardless of actual pin #) gives me a phantom hit. Adding a 1µs delay between the config and the read solves the problem. I'd like to understand what, specifically, is causing this.

Config:

void buttons_init(void) {
    nrf_gpio_cfg(BUTTON_UP_ROW_PIN,
                 NRF_GPIO_PIN_DIR_OUTPUT,
                 NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL,
                 NRF_GPIO_PIN_S0D1,
                 NRF_GPIO_PIN_NOSENSE);
    nrf_gpio_cfg(BUTTON_DOWN_ROW_PIN,
                 NRF_GPIO_PIN_DIR_OUTPUT,
                 NRF_GPIO_PIN_INPUT_DISCONNECT,
                 NRF_GPIO_PIN_NOPULL,
                 NRF_GPIO_PIN_S0D1,
                 NRF_GPIO_PIN_NOSENSE);
}

Reading:

    //Read upper row.  Set the upper row low, and the lower row floating.
    nrf_gpio_pin_clear(BUTTON_UP_ROW_PIN);
    nrf_gpio_pin_set(BUTTON_DOWN_ROW_PIN);
    nrfx_coredep_delay_us(1);   // :-(
    // Up buttons
    for (uint8_t i = 0; i < BUTTON_SETS; i++) {
        if (!nrf_gpio_pin_read(buttons_pins[i])) {                             // If button is pushed
            ...
        }
    }

(And swap pin states to read other row)

  • Hi,

     

    As a pure firmware point of view: the peripherals run on the 16 MHz peripheral clock tree, while the CPU runs on 64 MHz. This will then need wait-states to ensure writes/reads. This is done in hardware when setting registers and reading events (for most peripherals, but there are some behavioral issues, as errata #173), but in this case, you are awaiting a physical change, while reading a RAM location (NRF_Px->IN register).

    To ensure a wait state on the 16 MHz PCLK (peripheral clock), you can read a event, for instance the (void)NRF_TIMER1->EVENTS_COMPARE[0] register. Doesn't matter if you do this for any other peripheral, the wait state of 1 PCLK cycle will be introduced.

     

    That being said, I don't think adding a small delay of 1 x 16M cycle will help here, because the ROW pins must be set physically high, and you have routing on your board (which act as small capacitors), which will impact the rise/fall time of the GPIO signal. You could try, but I'd recommend having that delay of 1 us, or even higher, to ensure that the signal has crossed the VDD*0.7 threshold to ensure that you read a proper logical '1' on the input side.

     

    Kind regards,

    Håkon

Related