raspberrypi / bookworm-feedback

13 stars 1 forks source link

Onboard RPI4 serial port name "ttyS0" vs "ttyAMA0", "Input/output error" issue #280

Closed qrp73 closed 3 months ago

qrp73 commented 3 months ago

Previously I was used onboard GPIO serial port on my RPI4 as /dev/ttyS0 and it was worked ok. But now I'm unable to access /dev/ttyS0, it reports error:

$ stty -F /dev/ttyS0
stty: /dev/ttyS0: Input/output error

mono-runtime reports that there is present just two serial ports:

/dev/ttyS0
/dev/ttyUSB0

where ttyUSB0 is USB serial port. But attempt to access /dev/ttyS0 now leads to error: IOException: Input/output error. Previously it worked ok.

It stops to work about month ago or something like that.

Detailed investigation shows:

$ ls -l /dev/serial*
lrwxrwxrwx 1 root root  7 Jul 22 17:17 /dev/serial0 -> ttyAMA0

/dev/serial:
total 0
drwxr-xr-x 2 root root 60 Jul 22 18:11 by-id
drwxr-xr-x 2 root root 60 Jul 22 18:11 by-path

So, it appears that there is /dev/ttyAMA0 device and it works. But this device is missing from available port list reported by mono-runtime with call SerialPort.GetPortNames(). The call returns /dev/ttyS0 instead of /dev/ttyAMA0.

Source code of SerialPort.GetPortNames() method is here: https://github.com/mono/mono/blob/c6cdaadb54a1173484f1ada524306ddbf8c2e7d5/mcs/class/System/System.IO.Ports/SerialPort.cs#L518

According to the code it scans for /dev/ttyS, /dev/ttyUSB and /dev/ttyACM. So it seems like reason why /dev/ttyAMA0 don't appears in the list.

Why old working scheme with /dev/ttyS0 is changed to /dev/ttyAMA0? And why there is non working /dev/ttyS0?

Please fix it.

6by9 commented 3 months ago

According to the code it scans for /dev/ttyS, /dev/ttyUSB and /dev/ttyACM. So it seems like reason why /dev/ttyAMA0 don't appears in the list.

That would be a limitation in mono then.

Linux uart drivers generally advertise different prefixes based on the type of UART by setting dev_name in their struct uart_driver.

Cherry-picking just a couple of prefixes will have limitations.

Pi4 has a number of UARTs, some are 8250 based, and some are PL011 based. Bluetooth is driven off one of the UARTs.

I would hazard a guess that you've swapped which UART is used for Bluetooth, probably using dtoverlay=miniuart-bt. BT has now taken ttyS0, and ttyAMA0 is mapped to GPIOs 14&15. I don't believe that swap has been made in the base Raspberry Pi OS as ttyAMA0 is the better specified uart in that it supports hardware flow control.

qrp73 commented 3 months ago

It is possible that something is swapped, because I disabled GPIO 14&15 UART for some time, but BT is disabled on my system:

dtoverlay=disable-bt

How I can restore it to use /dev/ttyS0 for GPIO 14&15 UART as it worked before?

Also, I'm not sure why mono don't scan for /dev/ttyAMA* if its normal name for serial port? It works on many platforms and no one catch that issue? This is strange...

6by9 commented 3 months ago

Post your complete config.txt to avoid us having to guess. Also "vcgencmd version" and "uname -a" so we know which firmware and kernel versions you're using.

@pelwell Any changes you're aware of that might have swapped the UARTs over on Pi4?

lurch commented 3 months ago

Also, see the extensive documentation around this at https://www.raspberrypi.com/documentation/computers/configuration.html#configure-uarts

qrp73 commented 3 months ago

I google it for a little and the only issue related to /dev/ttyAMA* with mono SerialPort.GetPortNames() are issues for Raspberry Pi... This is very suspicious. It looks like raspi os specific issue, isn't it?

Also note that source code of SerialPort.GetPortNames() scans for a limited set '/dev/ttyS', '/dev/ttyUSB', '/dev/ttyACM' only when variable linux_style==true. When linux_style==false, it scans for any `/dev/tty', but exclude '/dev/tty' and '/dev/ttyC*'.

If you look at linux_style detection code, it set linux_style=true when the system has at least one device with the following names: '/dev/ttyS', '/dev/ttyUSB', '/dev/ttyACM*'.

Taken that logic it means that the system which uses any of name '/dev/ttyS', '/dev/ttyUSB', '/dev/ttyACM' cannot use '/dev/ttyAMA'. And vice versa, if system uses name '/dev/ttyAMA' it cannot use '/dev/ttyS', '/dev/ttyUSB', '/dev/ttyACM' names. Isn't it?

Current raspi os breaks this logic and uses '/dev/ttyAMA' and '/dev/ttyS', '/dev/ttyUSB' simultaneously. It leads to set linux_style==true which leads to ignore devices with names other than '/dev/ttyS', '/dev/ttyUSB', '/dev/ttyACM'. So the name '/dev/ttyAMA' is ignored because it expects linux style which allows only '/dev/ttyS', '/dev/ttyUSB', '/dev/ttyACM' names for serial port. And it leads to issue. Isn't it?

qrp73 commented 3 months ago

Post your complete config.txt to avoid us having to guess. Also "vcgencmd version" and "uname -a" so we know which firmware and kernel versions you're using.

dtparam=i2c_arm=off
camera_auto_detect=1
display_auto_detect=1
auto_initramfs=1
dtoverlay=vc4-kms-v3d
max_framebuffers=2

disable_fw_kms_setup=1
disable_overscan=1

arm_64bit=1
arm_boost=1

[pi0]
arm_freq=1100
gpu_freq=400

[pi4]
arm_freq=2100
gpu_freq=700
gpu_mem=96

[cm4]
otg_mode=1

[all]

hdmi_enable_4kp60=1
dtoverlay=disable-bt
6by9 commented 3 months ago

How many other ARM based systems are users running Mono on? ttyAMA is the prefix used by ARM's PL011 UART implementation, so you're not going to find it on x86 systems.

Linux uses different prefixes for different families of UART - that's documented in the core Linux documentation at https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/devices.txt#L2663-L2727 Any userspace application that doesn't take that into account when enumerating UARTs is going to fail when it encounters those UARTs - that's not a kernel failing.

Mono obviously partly realised that when they introduced https://github.com/mono/mono/commit/87e7f1c2d7cb85b9edb81382628664824ef28bdc to allow ttyACM, but didn't do the complete job (pretty much take any /dev/tty* node that doesn't continue with a numeric character as being a UART).

pelwell commented 3 months ago

ttyAMA0/UART0 is the better UART - it has larger FIFOs, and it's source clock does not depend on the core clock. For this reason it is normally used for Bluetooth on Bluetooth equipped Pis (but not Pi 5 which uses a dedicated SoC UART. dtoverlay=disable-bt frees up the "good" UART, so it becomes the UART available on GPIOs 14 & 15. This has been the case for as long as the disable-btoverlay has existed (and the pi3-disable-bt overlay before it).

qrp73 commented 3 months ago

How many other ARM based systems are users running Mono on? ttyAMA is the prefix used by ARM's PL011 UART implementation, so you're not going to find it on x86 systems.

Almost all Android and iOS smartphones running on ARM SoC and there are a lot of applications written with Xamarin which is a Mono edition for iOS and Android. So, this is strange that this issue with serial port name is not reported on Android and iOS, but reported on Raspberry Pi OS.

Technically speaking, x86 platform using .NET, while other non x86/non Windows platforms using Mono.

And since there is specific logic in Mono code that allows to scan for both serial port names depends on linux_style variable, it means that this code has some background to do these checks, isn't it?

qrp73 commented 3 months ago

Mono obviously partly realised that when they introduced mono/mono@87e7f1c to allow ttyACM, but didn't do the complete job (pretty much take any /dev/tty* node that doesn't continue with a numeric character as being a UART).

if you look for the code which works when linux_style==false, it include any /dev/tty* except /dev/tty (without number) and except /dev/ttyC*, see this part of code:


if (linux_style){
  if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM"))
    serial_ports.Add (dev);
} else {
  if (dev != "/dev/tty" && dev.StartsWith ("/dev/tty") && !dev.StartsWith ("/dev/ttyC"))
    serial_ports.Add (dev);
}```
qrp73 commented 3 months ago

ttyAMA0/UART0 is the better UART - it has larger FIFOs, and it's source clock does not depend on the core clock.

The problem is not hardware, the problem is that it is assigned with /dev/ttyAMA* name and as result it don't appears in available serial port list taken with SerialPort.GetPortNames().

lurch commented 3 months ago

As has already been pointed out, this is just the way that the Linux kernel assigns names to UART devices. I agree that this is a problem with Mono and not Raspberry Pi OS, so I'm going to close this.

(see also e.g. https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports_linux.py#L91 which uses a different set of pattern-matching rules to Mono)

EDIT: And see also https://raspberrypi.stackexchange.com/questions/89010/mono-cant-see-serial-port

qrp73 commented 3 months ago

As has already been pointed out, this is just the way that the Linux kernel assigns names to UART devices. I agree that this is a problem with Mono and not Raspberry Pi OS, so I'm going to close this.

(see also e.g. https://github.com/pyserial/pyserial/blob/master/serial/tools/list_ports_linux.py#L91 which uses a different set of pattern-matching rules to Mono)

This is false information. The code from your link add ttyAMA name in scan list to fix issue specifically for Raspberry Pi OS, it even noted in comment: https://github.com/pyserial/pyserial/commit/794b31003a5b671eb35daf98016a2747e4e12f3d

So, this is specific issue of Raspberry Pi OS only, isn't it?

pelwell commented 3 months ago

No it's not. The same issue will affect any devices with a PL011 UART.

pelwell commented 3 months ago

In fact, read the subject line of the commit you link to:

list_ports: add ttyAMA* devices on Linux (e.g. Raspberry Pi)
qrp73 commented 3 months ago

I see this comment:

devices.extend(glob.glob('/dev/ttyAMA*')) # ARM internal port (raspi)

Well, from my point of view, its clear that this is raspi-os internal specific issue. But if I understand correctly, it will not be fixed 'just because...' and the strategy is to enforce other developers to add kludges for this issue to all cross-platform libraries that are affected with this issue? Is this correct?

But there is another issue, what is the reason to keep this ghost device /dev/ttyS0 if it don't works? BT is disabled, I2C is disabled, SPI is disabled, and GPIO UART is assigned to /dev/ttyAMA0...

So, where does this /dev/ttyS0 port come from? And why this name is assigned but don't works?

6by9 commented 3 months ago

I believe I'm correct in saying that if you want to have /dev/ttyS0 on GPIOs 14&15, use enable_uart=1 rather than dtoverlay=disable-bt.

The fact that disable-bt restores ttyAMA0 to 14&15 is documented in the README

Name:   disable-bt
Info:   Disable onboard Bluetooth on Bluetooth-capable Raspberry Pis. On Pis
        prior to Pi 5 this restores UART0/ttyAMA0 over GPIOs 14 & 15.
Load:   dtoverlay=disable-bt
Params: <None>

As pelwell has already said, this has been the behaviour of that overlay/its predecessor since at least the 4.4 kernel back in 2017.

pelwell commented 3 months ago

ttys0 is the name for an 8250 clone, called UART1 on the Pi. The 8250 driver chooses the "s" in the name, in the same way that ARM's PL011 driver chooses "AMA". Libraries looking for UARTs need to embrace the diversity of UART naming, or just allow the users to override.

And you need to heed the comments here - this isn't a cover up or an exercise in brushing things under the carpet.

Locking,