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

UART configuration and manipulation

In order to interact with the UART, you need to first declare a device struct and then get a binding to the device:

static struct device *uart;
...
uart = device_get_binding("UART_1");

Then in order to switch the UART on and off you need to do:

uart_off()
{
    NRF_UARTE1_NS->TASKS_STOPTX = 1;
    NRF_UARTE1_NS->TASKS_STOPRX = 1;

    NRF_UARTE1_NS->ENABLE = 0;
}

uart_on()
{
    NRF_UARTE1_NS->ENABLE = 8;
    
    NRF_UARTE1_NS->TASKS_STARTRX = 1;
    NRF_UARTE1_NS->TASKS_STARTTX = 1;
}

But I wonder if there is a way to write a function that will take as input a string like "UART_1" and will perform the power on and off of the specified device.

What I have found out so far is that you can write a function like this:

void uart_power_on(NRF_UARTE_Type* dev)
{
    dev->ENABLE = 8;
    dev->TASKS_STARTRX = 1;
    dev->TASKS_STARTTX = 1;
}

And use as argument for UART1 for example NRF_UARTE1_NS.

In this way I can power on the device again. But what I would like to do is initialize the device and power it on or off in one function with the same argument.

Any ideas?

Parents
  • So to clarify, your just looking to pass a single arguement in which you can do things like turn off the UART?

    If that is the case, I would recommend looking at typedef'ing your own struct.

    Then you can pass that struct into your functions and access all the information stored in that struct. You can add bools to the struct that you can then check to see what you last set your UART to be (ON/OFF) and then preform the opposite operation on the UART (i.e if ON, switch off).

    #first define it
    typedef struct My_Struct
    {
    	struct device 	*UART;
    }MY_STRUCT;
    
    #init it in main
    MY_STRUCT MySystem;
    
    #pass it to your functions
    uart_power_on(&MySystem);

  • I don't see how that will work though.

    I mean, in order to initialize and enable UART1, I need to pass the argument "UART_1" to the device_get_binding

    and I need to pass an argument of type NRF_UARTE_Type* in order to switch on and off the UART.

    So, I assume that there has to be a way that all those different ways of addressing the same device can be somehow unified and, for example be able to get the NRF_UARTE_Type* from a function by passing it the argument "UART_1".

  • I don't think I understand, why exactly do you think you need to pass a type NRF_UARTE_Type*, you already showed that calling NRF_UARTE1_NS, which requires no function argument, works (and I know it does because I do it also for SPI, UART and PWM). So why are you trying to make something simple more complicated?

    Secondly, you do not need to pass "UART_1" to a function. You can define it as #define UART1 "UART_1" and then call UART1 in your function. This is how I do it and how you should be doing it as you should be defining your own define from the Zephyr generated list of peripheral names.

    For reference, pleae see /path/to/ncs/zephyr/samples/basic/blinky/main.c and refer to how they define the LED GPIO Port Controller and Pins. These can be defined in your code and called by any function.

  • Ok, so what I am trying to do is read data from UARTx, using a callback. In order to do that, I need a struct device *uart.

    Then I need to initialize that device, using the device_get_binding("UART_X").

    Then I need to attach a callback to that device to treat incoming data: uart_irq_callback_set(uart, callback)

    Then I need to enable the callback: uart_irq_rx_enable(uart)

    Then I need to be able to switch on and off this uart. As you have suggested in your answer, you need to do this:

    uart_on()
    {
        NRF_UARTE1_NS->ENABLE = 8;
        
        NRF_UARTE1_NS->TASKS_STARTRX = 1;
        NRF_UARTE1_NS->TASKS_STARTTX = 1;
    }

    This function will explicitly power onUART_1. What I want is to write a function that will power off any UART(0,1,2,3).

    This is done by this function:
    void uart_power_on(NRF_UARTE_Type* dev)
    {
        dev->ENABLE = 8;
        dev->TASKS_STARTRX = 1;
        dev->TASKS_STARTTX = 1;
    }

    In my understanding, passing the string argument "UART_1" to device_get_binding(), somehow matches the string to NRF_UARTE1_NS. So what I am looking for is a way to get the NRF_UARTE1_NS, by using the string "UART_1" or vice versa.

  • I mean there would be other ways of letting the function know what UART you want to control. A bool flag for example or a typedef enum that allows you to write a text UART1 as an argument but use a switch case inside the function based of the enum. That way you avoid passing the NRF_UARTE_Type*

  • This is definitely possible to use and it is my last resort, but there is definitely a matching mechanism between the string and the NRF_UARTE_Type*

Reply Children
  • Ok, so what I am trying to do is read data from UARTx, using a callback. In order to do that, I need a struct device *uart.

    This can be handled in the struct that I mentioned previously, this struct can be given all 'struct device's you need and the function can handle what one it wants.

    Then I need to initialize that device, using the device_get_binding("UART_X").

    Init your UARTs seperately, the init stage is independant of the actual manipulation of the UART. No need to have a function that inits, reads and turns them ON/OFF.

    Then I need to attach a callback to that device to treat incoming data: uart_irq_callback_set(uart, callback)

    ISRs set-ups should be done in your init function for the UART, this is another thing that only ever is one once and does not need to be in a recallable function. The custom struct I mentioned can also hold the 'struct gpio_callback' variables.

    Then I need to be able to switch on and off this uart. As you have suggested in your answer, you need to do this:

    Set-up a single method to decide what UART you are looking to control, as mentioned previously a typedef such as:

    typedef enum
    {
    	UART0,
    	UART1,
    	UART2
    }UARTS;

    Would allow you to call a function in this manner: uart_power_on(UART0).

    All together you would call a function with your struct and enum as uart_power_on(&MyStruct, UART0).

    From here, your functions should be able to decypher your input, pull all the variables and information it needs from your struct and global defines and then perform the operation required.

    If you really really want to condense the function, you could look at then calling void uart_power_on(NRF_UARTE_Type* dev) inside this function which can call the specific version of NRF_UARTE#_NS but that's a bit overkill unless you are really stuck for application memory size.

Related