GPIO0_2 (P0.02) Pin Behavior Issue on nRF54L15 - Button Triggering Events Without Interaction

Hello Nordic Team!

I'm experiencing unusual issues with GPIO pins on an nRF54L15 custom board. Specifically, P0.02 and P1.03 are not behaving as expected.

Button Issues (P0.02)

I have three buttons configured in my application:
- Button K1 on GPIO2_9
- Button K2 on GPIO2_10
- Button K3 on GPIO0_2

All GPIO pins are configured with `GPIO_ACTIVE_LOW | GPIO_PULL_UP`, meaning they should read as high (1) when not pressed and low (0) when pressed.

The problem with P0.02:
1. On startup, debug logs correctly show K3 as high (not pressed): `ButtonK3 initial state: 1`
2. Shortly after initialization, the button triggers a long press event without physical interaction: `K3 long press start (MultiButton)`
3. Continuous debug logs show the pin consistently reads as state 1, yet the button's pressed state persists

Here is the code:

static const struct gpio_dt_spec ButtonK1 = { .port = GPIO2_DEV, .pin = 9, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };
static const struct gpio_dt_spec ButtonK2 = { .port = GPIO2_DEV, .pin = 10, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };
static const struct gpio_dt_spec ButtonK3 = { .port = GPIO0_DEV, .pin = 2, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };
static const struct gpio_dt_spec ButtonK4 = { .port = GPIO0_DEV, .pin = 3, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };
static const struct gpio_dt_spec ButtonK5 = { .port = GPIO0_DEV, .pin = 4, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };


Additional testing:
- I attempted to bind an interrupt event to P0.02 but failed, while P0.03 and P0.04 worked successfully
- Using a hardware testing tool, I found that P0.02 appears to be connected to GND when the board is powered on, but disconnects when power is removed
- This suggests some internal configuration is affecting the pin

LED Issue (P1.03)

I also can't properly control P1.03 for LED output, while P1.02 works fine. I have already set `CONFIG_NFCT_PINS_AS_GPIOS=y` in my configuration.

Configuration Details

SDK version: nRF Connect SDK v3.0.0
Build arguments: `-DFILE_SUFFIX="internal"`

My overlay file contains:

chosen {
zephyr,console = &uart30;
zephyr,shell-uart = &uart30;
zephyr,uart-mcumgr = &uart30;
zephyr,bt-mon-uart = &uart30;
zephyr,bt-c2h-uart = &uart30;
};
&uart20 {
status = "disabled";
};

&uart30 {
status = "okay";
current-speed = <115200>;
/delete-property/ hw-flow-control;
};

UART is functioning properly and I can see the debug output.

## Questions

1. Is P0.02 a special pin on nRF54L15 that might have default functions affecting its GPIO behavior?
2. Even though I've disabled hardware flow control for UART, could other internal functions be affecting this pin?
3. Are there specific configurations needed to use P0.02 and P1.03 reliably as GPIO pins?
4. Could there be a conflict with another peripheral that's claiming these pins?

Thank you for your assistance!

Best regards,
Xiongwei.wang

  • Hi, Hieu!


    I found the same issue on the NRF54L15 DK as well. Here is a complete project. No compilation options have been added.

    Meanwhile, I also tested the code below, but got the same result.

    &uart00 {
    	status = "disabled";
    	/delete-property/ hw-flow-control;
    };

    Best regards,
    Xiongwei.Wang

    BoradBug.zip

  • Hi Hieu,

    I hope you're doing well. I wanted to follow up on my previous message regarding the issue I'm experiencing.

    I have tested the code on the NRF54L15 DK and found that:

    I: ButtonK1 initial state: 0
    I: ButtonK2 initial state: 0
    I: ButtonK3 initial state: 1
    I: ButtonK4 initial state: 1
    I: ButtonK5 initial state: 0

    And  the code is

    #define GPIO0_DEV DEVICE_DT_GET(DT_NODELABEL(gpio0))
    #define GPIO1_DEV DEVICE_DT_GET(DT_NODELABEL(gpio1))
    #define GPIO2_DEV DEVICE_DT_GET(DT_NODELABEL(gpio2))
    
    static const struct gpio_dt_spec ButtonK1	= { .port = GPIO2_DEV, .pin =  9, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };
    static const struct gpio_dt_spec ButtonK2	= { .port = GPIO2_DEV, .pin = 10, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };
    static const struct gpio_dt_spec ButtonK3	= { .port = GPIO0_DEV, .pin =  2, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };
    static const struct gpio_dt_spec ButtonK4	= { .port = GPIO0_DEV, .pin =  3, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };
    static const struct gpio_dt_spec ButtonK5	= { .port = GPIO0_DEV, .pin =  4, .dt_flags = GPIO_ACTIVE_LOW | GPIO_PULL_UP };

    I suspect this might be related to UART00, but I've already tried all the methods I'm familiar with without success.

    Do you have any suggestions for resolving this issue? I'm currently stuck and would appreciate your guidance.

    Best regards,
    Xiongwei Wang

    BoradBug.zip

  • Hi Xiongwei,

    I built the project you attached with the nrf54l15dk/nrf54l15/cpuapp target and found nothing is assigned to P0.02, whether a peripheral or a button.

    I see that nothing in the DeviceTree is setting the buttons at all.

    Is it possible that you misunderstood that the static const struct gpio_dt_spec ButtonKx lines will configure your button at that pin and port?

    Best regards,

    Hieu

  • Hi Hieu,

    I apologize for only providing the simplest code. On my side, there are other functions to initialize the button pins. The simplified code was just meant to show you that the ButtonK3 state is different from the others. I don't know what is influencing it or how to disable it.

    You can notice in the BoardBug.zip that I used exactly the same functions, but the pin levels are different.

    Regarding the code, I referenced dk_buttons_and_leds.c. I realized that normal GPIO configuration in the devicetree leads to a struct and two functions:
    - struct gpio_dt_spec
    - gpio_pin_interrupt_configure_dt and gpio_pin_configure_dt

    So I discarded the devicetree approach and used pure code to complete the configuration. It's valid - I can control the LED and accept interrupts or read the pin level.

    Best regards,
    Xiongwei Wang

  • Hello, Hieu,

    I have solved this problem. I have disabled the RTS/CTS flow control in the overlay file successfully. Here is the code:

    &uart30 {
    status = "okay";
    current-speed = <115200>;
    /delete-property/ hw-flow-control;
    };
    &uart30_default {
    group1 {
    psels = <NRF_PSEL(UART_TX, 0, 0)>;
    };

    group2 {
    psels = <NRF_PSEL(UART_RX, 0, 1)>;
    };
    };

    &uart30_sleep {
    group1 {
    psels = <NRF_PSEL(UART_TX, 0, 0)>, <NRF_PSEL(UART_RX, 0, 1)>;
    low-power-enable;
    };
    };

    Best regards,
    Xiongwei Wang

Related