This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

nRF9160 DK - UART big picture

Dear Nordic-Support Team,

Introduction

I have read through some sources (tickets and documentation) but I am still struggling to see the big picture of UART configuration in context of the nRF9160 DK. I noticed that even the terminology changes across different sources.

For example: in the tickets https://devzone.nordicsemi.com/f/nordic-q-a/47652/nrf9160-dk-uart-configuration and https://devzone.nordicsemi.com/f/nordic-q-a/68810/how-to-configue-an-external-uart-from-nrf9160-dk UART0 and UART1 are mentioned as primary and secondary UARTs which are forwarded through the virtual comports VCOM0 and VCOM2 respectively. However, Nordic's documentation (https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrf91_dk%2FUG%2Fnrf91_DK%2Fboard_controller.html&anchor=board_controller and https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrf91_dk%2FUG%2Fnrf91_DK%2Fhw_switches_uart_if.html) states, that UART1 and UART2 are forwarded though the virtual comports VCOM0 and VCOM2.

Thus, it would be great if you could help me to understand the big picture about how the different UARTs are set up per default and how they can be configured.

Device tree files

Because of the different terminology in the sources I have read, I had a look at the device tree files of the nRF9160, the nRF52840, and the nRF9160 DK in the Nordic Connect SDK.

The device tree file of the nRF9160 suggests that the nRF9160 chip has four UART interfaces. Is that correct? To get the terminology straight, I will call them UART_9160_[0,1,2,3] in the following.

# ncs\v1.9.1\zephyr\dts\arm\nordic\nrf9160_common.dtsi

# [...]

uart0: uart@8000 {
	compatible = "nordic,nrf-uarte";
	reg = <0x8000 0x1000>;
	interrupts = <8 NRF_DEFAULT_IRQ_PRIORITY>;
	status = "disabled";
	label = "UART_0";
};

uart1: uart@9000 {
	compatible = "nordic,nrf-uarte";
	reg = <0x9000 0x1000>;
	interrupts = <9 NRF_DEFAULT_IRQ_PRIORITY>;
	status = "disabled";
	label = "UART_1";
};

uart2: uart@a000 {
	compatible = "nordic,nrf-uarte";
	reg = <0xa000 0x1000>;
	interrupts = <10 NRF_DEFAULT_IRQ_PRIORITY>;
	status = "disabled";
	label = "UART_2";
};

uart3: uart@b000 {
	compatible = "nordic,nrf-uarte";
	reg = <0xb000 0x1000>;
	interrupts = <11 NRF_DEFAULT_IRQ_PRIORITY>;
	status = "disabled";
	label = "UART_3";
};

# [...]

The device tree file of the nRF52840 suggests that the nRF52840 chip has two UART interfaces. Is that correct? To get the terminology straight, I will call them UART_52840_[0,1] in the following.

# ncs\v1.9.1\zephyr\dts\arm\nordic\nrf52840.dtsi

# [...]

uart0: uart@40002000 {
	/* uart can be either UART or UARTE, for the user to pick */
	/* compatible = "nordic,nrf-uarte" or "nordic,nrf-uart"; */
	compatible = "nordic,nrf-uarte";
	reg = <0x40002000 0x1000>;
	interrupts = <2 NRF_DEFAULT_IRQ_PRIORITY>;
	status = "disabled";
	label = "UART_0";
};

# [...]

uart1: uart@40028000 {
	compatible = "nordic,nrf-uarte";
	reg = <0x40028000 0x1000>;
	interrupts = <40 NRF_DEFAULT_IRQ_PRIORITY>;
	status = "disabled";
	label = "UART_1";
};

# [...]

The device tree file of the nRF9160 DK suggests that the nRF9160 DK exposes three UART interfaces to the user via the board's pins and/or via the virtual comports of the J-Link debug probe. Is that correct? To get the terminology straight, I will call them UART_DK_[0,1,2] in the following.

# ncs\v1.9.1\zephyr\boards\arm\nrf9160dk_nrf9160\nrf9160dk_nrf9160_common.dts

# [...]

&uart0 {
	status = "okay";
	current-speed = <115200>;
	tx-pin = <29>;
	rx-pin = <28>;
	rx-pull-up;
	rts-pin = <27>;
	cts-pin = <26>;
	cts-pull-up;
};

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

&uart2 {
	tx-pin = <24>;
	rx-pin = <23>;
};

# [...]

General Questions

Assuming my assumptions about the device tree files are correct. Can you please answer the following questions?

  1. How do the different UART entities UART_9160_[0,1,2,3], UART_52840_[0,1], and UART_DK_[0,1,2] relate to each other?
  2. Why does the nRF9160 DK only expose three UART entities while the nRF9160 has four?
  3. How can I configure which UART entity is exposed through which pins of the nRF9160 DK
  4. Which UART entities are forwarded per default through the virtual comports?
  5. How can I configure which UART entities are forwarded through the virtual comports?
  6. How can I stop an UART entity from being forwarded  through the virtual comports?
  7. Assuming that UART_DK_0 is the "primary" UART used for console and AT data traffic, would it mess with the nRF9160 DK if UART_DK_0 would additionally be used to communicate to other external devices?

Use case specific questions

I would like to use the UARTs of the nRF9160 DK in the following way:

  1. Attach sensors which communicate, with a certain serial protocol, to one UART via the pins of the nRF9160 DK. This UART should not be exposed via the virtual comports
  2. Attach a second class of sensors, which communicate with another serial protocol, to a second UART via the pins of the nRF9160 DK. This UART should not be exposed via the virtual comports
  3. Communicate (e. g. send commands to my user application on the nrf9160 from a PC) with the nRF9160 DK over a third UART which is only exposed via a virtual comport but not via the pins of the nRF9160 DK

Can you please provide some configuration suggestions for e. g. an overlay-file and/or prj.conf-file-settings for that use case of mine and mention caveats if there are any?

Final remarks

I am aware that answering this ticket might take some effort but I really like to get this topic straight. Thus, thank you allot for your help!

  • Hi Simon,

    thank you for your answer. The documentation you pointed at looks promising. However,

    However, it is possible to re-configure them at runtime. So, e.g. assuming you don't need the SPI and the I2C at the same time, you can use the same peripheral for both (with different pins, or some switching mechanism).

    I am looking for a mechanism to re-configure (periodically back and forth) the HW peripherals at later stages during runtime (sorry if I was not clear about that). The description of the dynamic_pinctrl sample makes the following two statements:

    "The Dynamic Pin Control (nRF) sample demonstrates how to change uart0 at early boot stages, [...]"

    "Alternative configurations can only be applied if the device driver using the associated pins has not been initialized yet."

    I interpret these statements as if re-configuring HW peripherals is only possible during very early stages during the system startup and not during the "mode of operation" later on.

    Is it possible to re-configuring HW peripherals dynamically multiple times at runtime after boot and initialization? If yes, could you please explain to me how that can be done or point at the corresponding documentation?

    Thank you allot for your help!

  • What pin control enabled was to be able to reconfigure pins without needing to rebuild the app. However, you will need to reset the chip in order to change the configuration*. Is this suficcient for you? Every time you need to change pins, you reboot?

    If this is not sufficient, you could use the nrfx drivers directly, which gives you more control. However, then you loose the advantages and simplicity Zephyr brings with it. Here is a sample demonstrating how to use the nrfx drivers: https://github.com/nrfconnect/sdk-zephyr/tree/v3.0.99-ncs1/samples/boards/nrf/nrfx 


    *The reason you need to reset your chip, is because the reconfiguration needs to happen before the pins gets initialized. For example for UART, the function uart_nrfx_uarte.c-->uarte_instance_init() will run at boot (before main), and will use the pins set by the UART_NRF_UART_DEVICE macro (which gets the pins from the device tree using DT_PROP(_OR)). By using SYS_INIT, you can run stuff at boot before the initialization functions, and this is what the dynamic_pinctrl sample does: https://github.com/nrfconnect/sdk-zephyr/blob/v3.0.99-ncs1/samples/boards/nrf/dynamic_pinctrl/src/remap.c#L61.

    Best regards,

    Simon

  • Hi Simon,

    thank you for your explanation.

    Is this suficcient for you? Every time you need to change pins, you reboot?

    Well, yes and no. Of cause it would be more comfortable to re-configure the HW Peripherals without having to reboot the chip because "state" could be handled much easier this way. However, I understand why it is not possible at the moment and nonetheless, it is very good to know how the task can be tackled using either the reboot or the "direct-nrfx-driver" approach. Now it is up to us to discuss which route to take.

    Long story short, I believe I have all the information I was asking for (and more). Thus, many thanks to both of you for your support!

  • I'm glad we were able to help you and good luck with the project!

Related