How to put the UART to sleep (low power mode)

I believe it started with SDK 2.0.0 but the board config files now define different ways to specify how hardware is to run.

&pinctrl {

    uart1_default: uart1_default {
		group1 {
			psels = <NRF_PSEL(UART_TX, 0, 26)>,
				<NRF_PSEL(UART_RTS, 0, 29)>;
		};
		group2 {
			psels = <NRF_PSEL(UART_RX, 0, 27)>,
				<NRF_PSEL(UART_CTS, 0, 28)>;
			bias-pull-up;
		};
	};

	uart1_sleep: uart1_sleep {
		group1 {
			psels = <NRF_PSEL(UART_TX, 0, 26)>,
				<NRF_PSEL(UART_RX, 0, 27)>,
				<NRF_PSEL(UART_RTS, 0, 29)>,
				<NRF_PSEL(UART_CTS, 0, 28)>;
			low-power-enable;
		};
	};
	
&uart1 {
	status = "okay";
	pinctrl-0 = <&uart1_default_alt>;
	pinctrl-1 = <&uart1_sleep_alt>;
	pinctrl-names = "default", "sleep";
};

I took this to mean that I can dynamically toggle these configurations from "uart1_default" to "uart1_sleep" from perhaps a function call. Did find the pinctrl_apply_state() function call but it's return a -2 that state id doesn't exist even though it is defined. Here's my code.

uart = device_get_binding("UART_1");
int err = pinctrl_apply_state(uart->config, PINCTRL_STATE_SLEEP); // Returns -2
Any ideas?
Parents Reply Children
  • The SDK examples enable the pinreset functionality on P0.18 by default (you can read the PSELRESET[n] register to confirm this). So, I assume the problem you're experiencing is with toggling of the IO from the 9160? 

    The bt_hci_transport_setup() function in https://github.com/nrfconnect/sdk-zephyr/blob/main/boards/arm/nrf9160dk_nrf9160/nrf52840_reset.c demonstrates one way you can assign a GPIO to control the reset line to the 52840.

    Example

    C code:

    #include <zephyr/drivers/gpio.h>
    
    #define RESET_NODE DT_NODELABEL(nrf52840_reset)
    
    
    #define RESET_GPIO_CTRL  DT_GPIO_CTLR(RESET_NODE, gpios)
    #define RESET_GPIO_PIN   DT_GPIO_PIN(RESET_NODE, gpios)
    #define RESET_GPIO_FLAGS DT_GPIO_FLAGS(RESET_NODE, gpios)
    
    void reset_nrf52840(void)
    {
    	int err;
    	const struct device *port = DEVICE_DT_GET(RESET_GPIO_CTRL);
    
    	if (!device_is_ready(port)) {
    		printk("nrf52840_reset is not ready\n");
    	}
    
    	/* Configure pin as output and initialize it to inactive state. */
    	err = gpio_pin_configure(port, RESET_GPIO_PIN,
    				 RESET_GPIO_FLAGS | GPIO_OUTPUT_INACTIVE);
    	if (err) {
    		printk("gpio_pin_configure() failed (err: %d)\n", err);
    		return;
    	}
    
    	/* Assert the reset line */
    	err = gpio_pin_set(port, RESET_GPIO_PIN, 1);
    	if (err) {
    		printk("gpio_pin_set() failed (err: %d)\n", err);
    		return;
    	}
        
        k_sleep(K_MSEC(10));
    
    	/* Release reset line */
    	err = gpio_pin_set(port, RESET_GPIO_PIN, 0);
    	if (err) {
    		printk("gpio_pin_set() failed (err: %d)\n", err);
    		return;
    	}
    
    	printk("nrf52840 is reset\n");
    
    }
    
    
    void main(void)
    {
    	reset_nrf52840();
    	...

    DTS overlay:

    &nrf52840_reset {
    	status = "okay";
    	gpios = <&gpio0 31 GPIO_ACTIVE_LOW>;
    };

  • I was able to code it out. Looks to be working. These crazy macro will be the death of me.

    void ble_reset()
    {
        if(!device_is_ready(gpio_dev))
        {
    		LOG_ERR("nrf52840_reset is not ready");
            return;
    	}
    
        // Configure pin as output and initialize it to inactive state.
    	int err = gpio_pin_configure(gpio_dev, GPIO_BLE_RESET_PIN, 0 | GPIO_OUTPUT_INACTIVE);
    	if(err)
        {
    		LOG_ERR("gpio_pin_configure() failed (err: %d)", err);
    		return;
    	}
    
        // Assert the reset line
    	err = gpio_pin_set(gpio_dev, GPIO_BLE_RESET_PIN, 1);
    	if(err)
        {
    		LOG_ERR("gpio_pin_set() failed (err: %d)", err);
    		return;
    	}
        
        k_sleep(K_MSEC(10));
    
    	// Release reset line
    	err = gpio_pin_set(gpio_dev, GPIO_BLE_RESET_PIN, 0);
    	if(err)
        {
    		LOG_ERR("gpio_pin_set() failed (err: %d)", err);
    		return;
    	}
    
    	printk("nrf52840 is reset\n");
    }

  • Excellent, thanks for the update. Regarding the macro errors, if you have the time, there was a great talk about this topic by Marti at the Zephyr developer summit where he explains the "macrobatics," as he called it. Link to the recording if you are interested: https://www.youtube.com/watch?v=w8GgP3h0M8M.  

  • I wasn't able to get past the macro errors which is why I coded it. Thanks for the video. I now understand why macros are used but I'll need to watch the video a few times. macros to this degree is very complicated. Would like to understand it better.

    Thanks got all your help! I greatly appreciate it!

  • I agree it's complicated (when it doesn't work). But I think I know why it did not work for you. I was building for the 'nrf9160dk_nrf9160' board which includes the device tree binding for 'nrf52840_reset' node: https://github.com/nrfconnect/sdk-zephyr/commit/71223ad0d0e6f152912f314ea2df3fa656995bb6 . This may not be included if you have created a custom board.

Related