Issue with HW CTRL flow on ttyTHS1

Hello:

I am using the Orin AGX Dev Kit with JetPack_6.0 to communicate with a device using uart with HW control. I am using ttyTHS1, available on J30 (40-Pin Expansion Header).

I have tried multiple ways to control the UART and enable HW control flow (My own C code using the TERMIO library, and other serial testers such as minicom or this test code) but I cannot seem able to control the RTS pin. The pin is always low. I attached a logic analyzer to the RX, TX, RTS and CTS pins. I also tried connecting CTS to GND, to always indicate to the HW that it can send information. I am able to see the data in the RX and TX pins correctly, but the RTS pin never changes. In all instances of test, HW control flow is enabled by using the flag CRTSCTS, and verified with stty -a -F /dev/ttyTHS1.

My understanding is that, when using TERMIO with the CRTSCTS enabled, that the RTS pin would go high when transmitting, and low when reading. In my case, the RTS pin is always low, regardless if the UART is transmitting or receiving, with HW control flow enabled. Below is an example of a capture of RX and TX pins working, but no change in RTS.

I would appreciate any help on this matter. If nVidia has any scripts or code that can be used to verify the functionality of the HW control flow on their ttyTHSx devices, that would be a huge help!

We want to validate the HW control flow of the nVidia to see if it can be a good fit for our system, and to better understand if we need to do any modifications. In particular, we want to better understand how the delay between the end of a message being transmitted, and the change in the RTS pin. Our understanding is that this pin should be controlled by the kernel if the flag CRTSCTS is passed as a enabled flag of the serial port setup, which we are doing. And this is controlled on the kernel file serial-tegra.c as function set_rts()

Thank you!

Hi,
On Jetson platforms, we support using peripherals like CAN, SPI, I2C, UART… etc. for the user.
For CAN usage:
https://docs.nvidia.com/jetson/archives/r36.3/DeveloperGuide/HR/ControllerAreaNetworkCan.html
For the connection of peripheral on the devkit, please refer to expansion-headers guide and carrier board specification:
https://docs.nvidia.com/jetson/archives/r36.3/DeveloperGuide/HR/ConfiguringTheJetsonExpansionHeaders.html

For pin configuration, please refer to pinmux spreadsheet:
https://developer.nvidia.com/embedded/secure/jetson/agx_orin/jetson_agx_orin_pinmux_config_template.xlsm

By default, the configuration is used for the devkit. If you are using the custom carrier board, please configure it according to your custom board design.

There are also several examples which have been verified from us, please check
https://elinux.org/Jetson/L4T/peripheral/
Please share the full dmesg and device tree for us to check your status in detail.

Thanks!

Hello:

Thank you for your help!

Regarding the HW, we are using the NVIDIA® Jetson AGX Orin™ 64GB Developer Kit (Model P3730). Regarding the pinout configuration, it seems we do have the respective pins configured for UART - in particular, I see that RTS and CTS are enabled. Please forgive the crude picture - I am working with the device disconnected to the internet

Regarding the device tree, how could I query that to share it with you?

Regarding the tests for the UART, some of the tests ask for uarttest. Do you know where I could find this file? And also, I guess in my case it would be necessary to change everything to ttyTHS1 for testing? In particular we want to test the HW control flow, the RX and TX are working.

Thank you!

Hi eduardo45,

You can run the following command on your board and share extracted_proc.dts for further check.

$ sudo dtc -I fs -O dts -o extracted_proc.dts /proc/device-tree

Please also provide the full dmesg as file here.

To verify UART with HW flow control enabled, you can simply short TX/RX and RTS/CTS before running the test.

I would also suggest you verifying with the latest JP6.1(R36.4.0) since you are using the devkit.

Hi KevinFFF,

Thank you for your help! I have connected RX and TX together as well as RTS to CTS. I also have my logic analyzer connected to these signals.

I performed the following test and I do get the correct response on the RX/TX line, but RTS is still not affected (always stays low). I only added the HW control flow flag “crtscts” since that is what we need to test.

stty -F /dev/ttyTHS1 115200 raw -echo crtscts
cat /dev/ttyTHS1 &
echo "test" > /dev/ttyTHS1

In the below Image I do get the correct responses but no action on the RTS/CTS line.

I tried to follow the other steps but could not find anywhere the files uarttest or reader_writer.py.
I also tried programs like Minicom with HW control flow on, but I get the same result as above - no change on RTS.

I attach the device tree and dmesg to this message. I will try again with a fresh reinstall with jetpack 6.1 and report back. Thank you!
dmesg.txt (63.5 KB)
extracted_proc.zip (48.9 KB)

Hello:

I have made a fresh install of the latest Jetpack 6.1(R34.6.0) into the Orin AGX dev board and did the same tests above. Sadly I got the same results - I cannot get the RTS pin to change state with HW control flow on. It always stay low. I tried both the code above as well as with Minicom and my custom C code based on TERMIO, with the CRTSCTS flag enabled.

I attach the dmesg.txt as well as the proc for this.

Thank you!

dmesg_jetpack_6-1.txt (66.8 KB)
extracted_proc_jetpack_6-1.zip (49.6 KB)

Could you share the result of the following command on your board?

$ sudo busybox devmem 0x02430098

Have you also tried other application like minicom to use UART with HW flow control enabled?

Hi Kevin, thanks again for your help.

Here is the result:

sudo busybox devmem 0x02430098

0x00000400

I have tried both minicom and screen and sadly have had the same result as above. With minicom I made sure that HW control flow is on, and the RTS pin is always low on all transactions (with RX/TX being ok). If I do not enable HW control flow, the pin is always high.

I just opened a brand new Orin AGX dev kit and did the same tests as before, but got the same results. Something I notice on this one however is that the ttyTHSx present on the 40 pin header is ttyTHS0 (On my previous devkit with JP6.1 it was ttyTHS1). On the brand new dev kit with JP 5.1.2-B104 it is ttyTHS0. Is this expected?

This is the Minicom setup (shown on the new dev kit, with JP 5.1, but I did the same configuration on the first test device with JP6.1)

Thank you.

Hi:

As a note, I have been trying to read the registers of the UART by using devmem, for example:

sudo busybox memdev 0x3100000
sudo busybox memdev 0x3100004
sudo busybox memdev 0x3100008
sudo busybox memdev 0x310000C
sudo busybox memdev 0x3100010

But unfortunately I am reading everything as 0xFFFFFFFF. To my understanding this is due to a firewall - is there a way to disable this? If it is something that is disabled when flashing, is this an option that can be changed when using the SDK Manager?

I also tested again with minicom on the Orin AGX dev kit that has JP 6.1 again to no success. I short RX to TX, RTS to CTS, open Minicom and type, but only see RX and TX signals. I do notice that there are more options on minicom when doing it on the JP6.1 device. I tried with only HW control flow on - I noticed some RS485 options not available on the JP5.1 device, but any combination of them do not change the fact it is not working.


On these tests I still get

sudo busybox devmem 0x02430098

0x00000400

Hi Kevin,

doing further testing I believe I misunderstood how the RTS pin behaves on the Orin, but I wanted to check with you to better understand if I am on the right path.

From other forum posts I was under the impression that the RTS pin would go logic low when transmitting, and when the transmission is done, would go high. That aligns with an RS-485 mode of operation

But it seems that the RTS pin behaves more like a traditional RS-232 mode of operation, where it goes high to indicate it is not ready to transmit. That is why on my tests of sending 1-10 bytes it did not change.

I did a test where I send ~70 bytes at once with “echo”, changing the HW control on and off.

Test with no HW control flow:


It seems data is sent on block of 32 bytes, with some delay between packets - maybe it is the system preparing the other 32 bytes to send.

Test with HW control flow:


The RTS pin aligns with the behavior of going high when the system is busy and cannot transmit.

Is this behavior the expected one?

If so, I have some questions:
1.) Is there any way we can modify the behavior to be the other way? My idea would be to modify serial-tegra.c to directly change the RTS pin by modifying register UART_MCR_0::RTS to toggle RTS on and off (with HW mode disabled). What do you think?

2.) If this is possible, do you know where it the driver would be a good idea to place this code (to ensure that RTS goes high when TX starts, and goes low when the complete packet is sent).

Our challenge is that we would like to have this RTS pin change happen as quickly as possible when the data has finished sending.

3.)We could also change RTS to be a GPIO and to toggle it in user space. Our challenge there is to toggle it quick enough as soon as transmission has finished. Is there a way in user space to toggle this pin when an UART interrupt has happened?

Thank you for your time!

Yes, it should be expected since JP5.x and JP6.x have some differences in device tree for the numbering of UART interface .

Yes, they are expected that RTS would pull low when it is busy and turn back to high when it is idle.

Are you using Uart interface for RS-485 so that you want the opposite behavior?
If so, you can refer to Need to Invert UART2 RTS - #5 by KevinFFF for this use case.

Hi Kevin,

Thank you. We are interested in using it for RS485, but would inverting the signal work for this? I see that the RTS only changes when the uart cannot send more data with my tests above. Our ideal solution would be for it to go high when sending data and low when not sending data, but that does not seem to be the case.

I did see the post you referenced but I still do not understand how they can get the rs485 to work if the RTS behaves as it does. I did see that post before making my post here, and that was one of the posts that made me think this was possible. Am I missing something on how the RTS behaves and can make this possible?

Thank you

Yes, it should be since the enable PIN of RS-485 has different behavior as RTS of UART by default.

Have you tried to configured the bit 3 of Uart register to check if it could help in your case?

Hi Kevin,

Thank you for your help. We have tried but it has not helped - the RTS pin still does not behave in the matter we think it does to allow for RS-485 comms, even if flipped.

We are seeing that the RTS pin activates to indicate that it needs some time to transfer data to the uart buffer. In my examples above the RTS pin never changes if I send small series of bytes at a time (for example, 1 byte). The only way I could get the RTS pin to change is if we order a lot of bytes to be transferred at a time, which results in the buffered solution from above (I repeat this graph below):

If I invert it I am seeing the same as above (but inverted) - the RTS pin never changes on small byte qty, and when it does, it is when it is buffering the rest of the data. The behavior you mention is the one that would work for us, but we are not seeing that.

Is this something that perhaps would be possible to check on your side? We have tested on multiple devices, multiple Jetpacks, but always get the same result. We would greatly appreciate it!!

Or if it is confirmed that what we are seeing is the correct RTS behavior we can switch our effort on solving this another way (either in HW or modifying the kernel).

Thank you.

From the image you shared, it seems RTS is working as expected.
Do you mean that RTS not work if there’s only few data is transmitted?

Please let me share the uarttest binary and refer to the following steps to verify.
uarttest (66.2 KB)

$ sudo su
# mkdir /data
# dd if=/dev/urandom of=/data/tx_testfile.bin bs=1M count=1
# ./uarttest -test 0x800000 -tty /dev/ttyTHS1 -tx -rx -baud 1000000 -hwflow enable

Hi Kevin:

Thank you again. I have performed the test on an nVidia Orin AGX dev kit with the latest jetpack, and by shorting TX/RX and CTS/RTS on the 40 pin header.

./uarttest -test 0x800000 -tty /dev/ttyTHS1 -tx -rx -baud 1000000 -hwflow enable
-------------Serail Port Configuration-------------
prim tty Port: /dev/ttyTHS1
Receive Flow: Enable
Rx File Name: /data/rx_testfile.bin
CRC check : Disable
Transmit Flow: Enable
Tx File Name : /data/tx_testfile.bin
Serial setting: 1000000, N, 8, 1
HwFlow Control: Enable
variable FrameSize transmission: Enable
Frame Sizes: 1 4 12 21 41 100 101 102 512 515 1021 1024 2049 4096 6096 8193 10193 16384 32768 33001 65536 65839 
Fixed Frame Size: 2048
Test Id	: 0x00800000
Number Of runs: 1
----------------------------------------------------
do_loopback_file_transfer_test()++ 
Opening the device /dev/ttyTHS1 as blocking mode baud 4104
uart_info->is_rx_test: 1 
uart_info->is_tx_test: 1 
start_receive_process()++ 
start_transmit_process()++ 
FileName is /data/tx_testfile.bin 
get_transmit_filesize(): FileSize: 1048576 Bytes
FileName is /data/tx_testfile.bin 
get_transmit_filesize(): FileSize: 1048576 Bytes
Total data Sent: 1048576 Bytes,Total Time for transfer: 11705MS,Avg time for transfer: 86 KBps
start_transmit_process()-- 
Total data received: 1048576 Bytes,Total Time for transfer: 13726MS,Avg time for transfer: 74 KBps
start_receive_process()-- 
Both the files are same
do_loopback_file_transfer_test()-- 
TotalRunTest 1: Passed 1: Failed 0 
root@robustai-desktop:/home/robustai/Documents# ./uarttest -test 0x800000 -tty /dev/ttyTHS1 -tx -rx -baud 1000000 -hwflow enable
-------------Serail Port Configuration-------------
prim tty Port: /dev/ttyTHS1
Receive Flow: Enable
Rx File Name: /data/rx_testfile.bin
CRC check : Disable
Transmit Flow: Enable
Tx File Name : /data/tx_testfile.bin
Serial setting: 1000000, N, 8, 1
HwFlow Control: Enable
variable FrameSize transmission: Enable
Frame Sizes: 1 4 12 21 41 100 101 102 512 515 1021 1024 2049 4096 6096 8193 10193 16384 32768 33001 65536 65839 
Fixed Frame Size: 2048
Test Id	: 0x00800000
Number Of runs: 1
----------------------------------------------------
do_loopback_file_transfer_test()++ 
Opening the device /dev/ttyTHS1 as blocking mode baud 4104
uart_info->is_rx_test: 1 
uart_info->is_tx_test: 1 
start_receive_process()++ 
FileName is /data/tx_testfile.bin 
get_transmit_filesize(): FileSize: 1048576 Bytes
start_transmit_process()++ 
FileName is /data/tx_testfile.bin 
get_transmit_filesize(): FileSize: 1048576 Bytes
Total data Sent: 1048576 Bytes,Total Time for transfer: 11517MS,Avg time for transfer: 88 KBps
start_transmit_process()-- 
Total data received: 1048576 Bytes,Total Time for transfer: 13536MS,Avg time for transfer: 75 KBps
start_receive_process()-- 
Both the files are same
do_loopback_file_transfer_test()-- 
TotalRunTest 1: Passed 1: Failed 0 

I also used a logic analyzer to capture the waveforms during this test.

Here is a closeup of the waveforms. As you can see, the RTS only activates to indicate the HW device needs time to process before being able to work, mostly due to the ammount of data being sent. It does not activate when the TX is being sent. Is this behavior expected? It does coincide with what we are seeing. And also, the RTS never activates unless we are sending a lot of data at a time. If 8 bytes are sent, for example, the RTS never activates. This does coincide with the RTS being activated when the system needs time to process rather than activating when transmission is happening.

For example, I did mutiple tests of sending data to the UART at 1Mbps. Here is 12 bytes. RTS is always low

I did see a change starting at 16 byte packages. RTS is high after for some time.

An example at 32 byte packages. There are times where RTS is high while the system manages the transaction

I will try an automatic control flow device and report back, but these findings are leading me to believe that the RTS cannot be used for half duplex control flow (connected to the DE/RE’ pins).

Thank you.

Thanks for sharing the test results and findings.
Please let me check with internal if this behavior is expected.

Hi Kevin,

Thank you for your continued help. Have you had any answer from internal? I would still be interested in knowing the answer!

For posterity and other people running into this:
We have had luck with solutions like this one, making automatic direction detection with HW solutions, all with quick change on direction detection which fits our needs of peripherals replying to messages in the order of microseconds.

Or a chip like THVD1420DR , although there are some timing caveats if your baud rate does not align with their IC spec.

For a solution where USB is acceptable, the following adapter is good. It is based on an FTDI chip

Section 7.2 USB to RS485 Converter

We also pursued changes on the driver itself (serial-tegra.c) but found it difficult to determine the end of the transmission quick enough to toggle the direction GPIO to change directions and meet our window of reply. We put very little time to this endeavor however, so it might be possible with more work.

Hi eduardo45,

I’ve checked this with internal that is is expected.
RTS is activated only after we fill the RX FIFO of the receiver up to a certain extent. It basically says that the FIFO is full, please do not send further data. Once there is a space in FIFO, it would pull the signal and the sender resumes sending the data. TX basically relies on CTS (clear to send) signal. Which is controlled by RTS on the receiver side.

So, for small data < 16 bytes, RTS would not activate generally.
It is the expected behavior for UART interface.
We would suggest you sending larger data if you want to use it for RS-485.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.