nrf54 wakeup using uart pins as gpio.

Using nrf connect 3.1.1

using nrf54L15 evaluation board.

Hi,

I have an application that is using the shell capabilities of the zephyr.  uart and shell is connected to stranded virital com to usb c,

#define UART_TX_GPIO_SPEC       <NRF_PSEL(UART_TX,   1, 4)>
#define UART_RX_GPIO_SPEC       <NRF_PSEL(UART_RX,   1, 5)>
I have succeeded in putting device into sleep mode using a shell command, and i observe minimal current drawn.
Next i wish to wake nrf54 and re- enable uart when receiving an interrupt on rx line P1.05.
I configured the rx pin to be interrupted, put this will not fired.
what am I missing?
Thanks
Dan
// UART
#define UART_TX_GPIO_SPEC       <NRF_PSEL(UART_TX,   1, 4)>
#define UART_RX_GPIO_SPEC       <NRF_PSEL(UART_RX,   1, 5)>
#define UART_RX_GPIO_SPEC_PIN   <&gpio1 5  (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>



&gpio1 {
	sense-edge-mask = <0x00002120>; /* P1.05, P1.08, P1.13 */
};

   
    pad_input:pad_input {
        compatible = "gpio-keys";
		debounce-interval-ms = <150>;                      /* Debouncing time */
        
		uart_rx_pin: uart_rx_pin {
			gpios = UART_RX_GPIO_SPEC_PIN;
			label = "uart rx pin";
			zephyr,code = <INPUT_KEY_1>;
		};
    };
    
    
///
/// UART
///
&uart20 {
	current-speed = <115200>;
	pinctrl-0 = <&uart20_default>;
	pinctrl-1 = <&uart20_sleep>;
	pinctrl-names = "default", "sleep";
};


&pinctrl {
	/omit-if-no-ref/ uart20_default: uart20_default {
		group1 {
			psels = UART_TX_GPIO_SPEC;
		};

		group2 {
			psels = UART_RX_GPIO_SPEC;
			bias-pull-up;
		};
	};

	/omit-if-no-ref/ uart20_sleep: uart20_sleep {
		group1 {
			psels = UART_TX_GPIO_SPEC,
				    UART_RX_GPIO_SPEC;
			low-power-enable;
		};
	};

};
    
    
    
    
#include <zephyr/kernel.h>
#include <zephyr/types.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/logging/log.h>
#include <zephyr/device.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/led.h>
#include <zephyr/settings/settings.h>
#include <zephyr/shell/shell.h>
#include <zephyr/sys/reboot.h>
const struct device *uart = DEVICE_DT_GET(DT_NODELABEL(uart20));

static struct gpio_callback gpio_cb;

static void gpio_isr(const struct device *port,
                     struct gpio_callback *cb,
                     uint32_t pins)
{
    LOG_INF("ISR fired ");
    int x = pm_device_runtime_usage(uart);
    if(x == 0)
    {
        pm_device_runtime_get(uart);
    }
}

void uart_rx_pin_setup(void)
{
    const struct gpio_dt_spec uart_rx_pin = GPIO_DT_SPEC_GET(DT_NODELABEL(uart_rx_pin), gpios); 
   
    gpio_pin_configure_dt(&uart_rx_pin, GPIO_INPUT);

    gpio_pin_interrupt_configure(uart_rx_pin.port,
                                       uart_rx_pin.pin,
                                       GPIO_INT_EDGE_BOTH);

    gpio_init_callback(&uart_rx_pin,
                       gpio_isr,
                       BIT(uart_rx_pin.pin));

    gpio_add_callback(uart_rx_pin.port, &gpio_cb);

}

void uart_sleep(void)
{
    pm_device_runtime_put(uart);
    uart_rx_pin_setup();
}


int main(void)
{

    // Enable runtime power management
    pm_device_runtime_enable(uart);
    pm_device_runtime_get(uart);


    while(1)
    {

        k_sleep(K_SECONDS(10));
    }
 
	return 0;
}

static int shell_disable(const struct shell *shell, size_t argc, char **argv)
{
     uart_sleep(); // disable uart
    return 0;
}


SHELL_STATIC_SUBCMD_SET_CREATE(sleep_cmds,
    SHELL_CMD(shell_disable, NULL, "Disable shell ", shell_disable),
    SHELL_SUBCMD_SET_END
);

SHELL_CMD_REGISTER(uart, &sleep_cmds, "Sleep commands", NULL);
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000

CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y
#CONFIG_NRFX_UARTE20=y
#CONFIG_PINCTRL=y
#CONFIG_PINCTRL_NRF=y
#CONFIG_PINCTRL_DYNAMIC=y

# Shell
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_UART_CONSOLE=y

# Logging
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=2
CONFIG_LOG_MODE_MINIMAL=n
#CONFIG_LOG_BACKEND_UART=n
CONFIG_LOG_RUNTIME_FILTERING=y              # adds ability to change log levels at runtime
#CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_LOG_CMDS=y                           # shell commands
CONFIG_LOG_PRINTK=y

# Bluetooth
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="BLE_Advertiser"
CONFIG_BT_DEVICE_APPEARANCE=0
CONFIG_BT_PRIVACY=n
CONFIG_BT_HCI=y


#float support
CONFIG_CBPRINTF_FP_SUPPORT=y                # enables float support in printf functions

# external flash
CONFIG_FLASH=y
CONFIG_SPI_NOR_SFDP_RUNTIME=y               # enable SFDP support for SPI NOR flash
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
CONFIG_FLASH_PAGE_LAYOUT=y                  # enable flash page layout API    
CONFIG_FLASH_SHELL=y
CONFIG_FLASH_MAP=y

# NVS Filesystem
CONFIG_NVS=y
CONFIG_NVS_LOG_LEVEL_DBG=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y

# Input sub system
CONFIG_INPUT=y
CONFIG_INPUT_EVENT_DUMP=y
CONFIG_INPUT_GPIO_KEYS=n
CONFIG_GPIO=y
CONFIG_LED=y
CONFIG_LED_GPIO=y
#CONFIG_NRFX_GPIOTE_NUM_OF_EVT_HANDLERS MAX is 12
CONFIG_NRFX_GPIOTE_NUM_OF_EVT_HANDLERS=12 
#CONFIG_NRFX_GPIOTE_LOG=y



# NFC
CONFIG_NFC_T4T_NRFXLIB=y
CONFIG_NFC_NDEF=y
CONFIG_NFC_NDEF_MSG=y
CONFIG_NFC_NDEF_RECORD=y
CONFIG_NFC_NDEF_LE_OOB_REC=y
CONFIG_NFC_NDEF_PARSER=y


# HEAP
#CONFIG_SYS_HEAP_RUNTIME_STATS=y

# CONFIG_PM_PARTITION_SIZE_NVS_STORAGE=0x00

# MAIN TASK MODULE
CONFIG_APP_MAIN_TASK_ENABLED=y
CONFIG_APP_MAIN_TASK_SHORT_QUEUE_LEN=10
CONFIG_APP_MAIN_TASK_MAX_SHORT_MESSAGE_LEN=4
CONFIG_APP_MAIN_TASK_LONG_QUEUE_LEN=4
CONFIG_APP_MAIN_TASK_MAX_LONG_MESSAGE_LEN=128
CONFIG_APP_MAIN_TASK_MAX_NUM_OF_EVENTS=15 

Parents
  • Hi,

     

    This topic comes into play when using PM runtime API:

     button with "gpio-keys" not fired when CONFIG_PM_DEVICE_RUNTIME=y 

     

    SHELL will also be a consumer of your uart, so it will keep it on. Try instead of using serial backend for shell, to use RTT instead.

    This function call will create issues:

        gpio_init_callback(&uart_rx_pin,
                           gpio_isr,
                           BIT(uart_rx_pin.pin));
    

     Should point to "gpio_cb", not "uart_rx_pin".

     

    If you choose to go with PM runtime API, you should enable the "uart_rx_pin.port" via pm_device_runtime_get() when disabling the uart.

    If you choose to use PM without runtime, you should suspend the uart, then setup your gpio callback.

     

    Kind regards,

    Håkon

  • I confirmed this works as I needed.

    I suspend uart, then configure rx pin as interrupt and it work.

    after interrupt fires, i disable it and re enable uart.

    thanks.

    static int configure_uart_rx_wakeup(void)
    {
        if (!device_is_ready(uart_rx_pin.port)) {
            return -ENODEV;
        }

        int ret = gpio_pin_configure_dt(&uart_rx_pin,
                                        GPIO_INPUT | GPIO_PULL_UP);
        if (ret) {
            return ret;
        }

        ret = gpio_pin_interrupt_configure(uart_rx_pin.port,
                                           uart_rx_pin.pin,
                                           GPIO_INT_EDGE_BOTH);
        if (ret) {
            return ret;
        }

        k_work_init_delayable(&work, work_thread);

        gpio_init_callback(&gpio_cb,
                           gpio_isr,
                           BIT(uart_rx_pin.pin));

        ret = gpio_add_callback(uart_rx_pin.port, &gpio_cb);
        if (ret) {
            return ret;
        }

        return 0;
    }
  • Hi!

     

    narfster said:

    I confirmed this works as I needed.

    I suspend uart, then configure rx pin as interrupt and it work.

    after interrupt fires, i disable it and re enable uart.

    thanks.

    That is great to hear, and thank you so much for sharing your proposed code. Hope you have a wonderful day!

     

    Kind regards,

    Håkon

Reply Children
No Data
Related