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

How can I enable and disable UART devices at run time on nRF9160?

I need to enable UART1 in runtime in order to be able to read some data coming on that device.

In order to be able to use the uart functionality, I need to set CONFIG_SERIAL=y, otherwise I get compilation errors. So I wonder how can I disable all uart devices and then enable them back on runtime.

I read this thread, but when I tried to implement it for both UART0 and UART1, the application hang.


This how I try to do it:

void disable_uart()
{
    NRF_UARTE1_NS->TASKS_STOPRX=1;
    while(NRF_UARTE1_NS->EVENTS_RXTO == 0);
    NRF_UARTE1_NS->EVENTS_RXTO = 0;

    NRF_UARTE1_NS->TASKS_STOPTX = 1;
    while(NRF_UARTE1_NS->EVENTS_TXSTOPPED == 0);
    NRF_UARTE1_NS->EVENTS_TXSTOPPED = 0;

    NRF_UARTE1_NS->ENABLE = 0;
    NRF_UARTE1_NS->PSEL.TXD = 0xFFFFFFFF;
    NRF_P0_NS->OUTCLR = (1 << 1);



    NRF_UARTE0_NS->TASKS_STOPRX=1;
    while(NRF_UARTE0_NS->EVENTS_RXTO == 0);
    NRF_UARTE0_NS->EVENTS_RXTO = 0;

    NRF_UARTE0_NS->TASKS_STOPTX = 1;
    while(NRF_UARTE0_NS->EVENTS_TXSTOPPED == 0);
    NRF_UARTE0_NS->EVENTS_TXSTOPPED = 0;

    NRF_UARTE0_NS->ENABLE = 0;
    NRF_UARTE0_NS->PSEL.TXD = 0xFFFFFFFF;
    NRF_P0_NS->OUTCLR = (1 << 29);
}

void enable_uart()
{

    NRF_UARTE1_NS->ENABLE = 8;
    NRF_UARTE1_NS->TASKS_STARTRX = 1;
    NRF_UARTE1_NS->TASKS_STARTTX = 1;

    NRF_UARTE0_NS->ENABLE = 8;
    NRF_UARTE0_NS->TASKS_STARTRX = 1;
    NRF_UARTE0_NS->TASKS_STARTTX = 1;
}


So what am I missing?

Thank you very much for your assistance!

  • Thank you very much for your response.

    I also tried this solution, but I think that CONFIG_PRINTK=n, simply ignores printk in the code and CONFIG_BOOT_BANNER=n suppresses the print of the boot message of the device in the beginning, but I am not convinced that your answer actually disables and then enables the UART devices. At least in the case of UART0, using that logic, I never see anything printed out.

    But the way I want it to work is the following:

    Disable both UART0 and 1 in the beginning of the program, then enable UART0 and 1, get my data from the sensor, print them using printk and then disable them again.

  • Hello, 

    I read this thread, but when I tried to implement it for both UART0 and UART1, the application hang.

    Have you tried to debug what happens? Are you getting an error? Have you added the overlay file? What have you configured in your prj.conf?

    Kind regards,
    Øyvind

  • Using this implementation I have seen the power consumption of the device drop substantially so the UARTs are being disabled.
    This implimentation surpresses the printk() yes. This means that you won't accidentally trigger a UART0 requiring printk() that will cause a fault. If you re-enable the UART0 before you printk() then it should be fine.

    I designed this implementation as I don't need the power consuming UART-USB bridge and only need the communication between the nRF9160 and an external soruce via UART1. In my test case, the Otii Arc power analyser's UART control pins. I was then able to see the device receive and send UART messages to the anaylser when the UARTs are enabled and see no UART interrupt triggering when the UART1 was disabled.

    I use this code to disable UART0 immedately at boot to stop the serial UART wasting current and then call the code to disable/enable UART1 during runtime depending on sleep or wake states.

  • In the prj.conf the related configurations are the following:

    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_LOG=y
    CONFIG_LOG_DEFAULT_LEVEL=4
    CONFIG_SERIAL=y
    CONFIG_AT_HOST_LIBRARY=y
    CONFIG_UART_1_NRF_UARTE=y
    CONFIG_BSD_LIBRARY_TRACE_ENABLED=n


    I am assuming that switching on and off of the 2 UARTS, would result in toggling printk on and off.

    But it doesn't work out like that. After disabling UART0 once it is not possible to see anything being printed.

    UART1 seems to work though after a cycle of enabling and disabling.

    But my end goal is to achieve low power, so I also need to toggle UART0.

    The overlay I am using is this (I know that those are the defaults, but anyway):

    &uart1 {
    	status = "okay";
    	current-speed = <115200>;
    	tx-pin = <1>;
    	rx-pin = <0>;
    	rts-pin = <14>;
    	cts-pin = <15>;
    };

    This is what I am currently doing to switch them on and off:

    void disable_uart()
    {
        NRF_UARTE1_NS->TASKS_STOPRX=1;
        while(NRF_UARTE1_NS->EVENTS_RXTO == 0);
        NRF_UARTE1->EVENTS_RXTO = 0;
    
        NRF_UARTE1_NS->TASKS_STOPTX = 1;
        while(NRF_UARTE1_NS->EVENTS_TXSTOPPED == 0);
        NRF_UARTE1_NS->EVENTS_TXSTOPPED = 0;
    
        NRF_UARTE1_NS->ENABLE = 0;
        NRF_UARTE1_NS->PSEL.TXD = 0xFFFFFFFF;
        NRF_P0_NS->OUTCLR = (1 << 1);
    
        printk("One UART DOWN\n");
    
        NRF_UARTE0_NS->TASKS_STOPRX=1;
        while(NRF_UARTE0_NS->EVENTS_RXTO == 0);
        NRF_UARTE0_NS->EVENTS_RXTO = 0;
    
        NRF_UARTE0_NS->TASKS_STOPTX = 1;
        while(NRF_UARTE0_NS->EVENTS_TXSTOPPED == 0);
        NRF_UARTE0_NS->EVENTS_TXSTOPPED = 0;
    
        NRF_UARTE0_NS->ENABLE = 0;
        NRF_UARTE0_NS->PSEL.TXD = 0xFFFFFFFF;
        NRF_P0_NS->OUTCLR = (1 << 29);
    }
    
    void enable_uart()
    {
    
       NRF_UARTE1_NS->ENABLE = 8;
       NRF_UARTE1_NS->TASKS_STARTRX = 1;
       NRF_UARTE1_NS->TASKS_STARTTX = 1;
    
       NRF_UARTE0_NS->ENABLE = 8;
       NRF_UARTE0_NS->TASKS_STARTRX = 1;
       NRF_UARTE0_NS->TASKS_STARTTX = 1;
    }

Related