Raspberry Pi Serial Ports
The Raspberry Pi uses non-5V tolerant 3.3V GPIO. This also includes the serial port levels. This level does not match up with PC or RS232 levels and some USB-Serial adapters will use either 5V or RS232 levels, which can and will damage the Pi GPIO. Ensure that your serial device specs are 3.3V level compatible to avoid damaging your Raspberry Pi.
For RS232 applications, a MAX3232 level translator can be used between your PC and the Pi. For USB applications, a FT232 running at 3.3V will suffice as a USB-Serial adapter. For RS485 applications, an RS-485 level translator in the MAX3070-MAX3079 family running at 3.3V can be used.
- 1 Overview
- 2 UART Setup
- 2.1 Changing Console Assignment
- 2.2 Create The Dialout Group
- 2.3 Create Udev Rules
- 2.4 Modify The Boot Files
- 2.5 Checking The Configuration
- 2.6 Moving The Serial Ports
- 2.7 Checking The Configuration
- 3 Where To Get Help
- 4 Acknowledgements
The Gentoo arm64 stage3 at the time of this writing is missing a couple of things to make the serial ports behave as they do in Raspbian Jessie. There is no Udev rule to create the serial0 and serial1 symlinks that point to the serial ports. In Raspbian, the serial0 symlink always points to GPIO14:15 while serial1 always points to the other serial port. Raspbian has a custom Udev rule that is responsible for this, but missing in the arm64 Gentoo stage3.
While Gentoo itself does not depend on the symlinks, they are a nice convenience feature as serial0 will always point to GPIO14:15 regardless of the serial port assigned to GPIO14:15. Code that has been written using these symlinks will not have to be modified run under Gentoo.
The other issue at hand is the console serial port assignment in /etc/inittab. By default, /etc/inittab assigns ttyAMA0 as the console serial port. For non-wireless/Bluetooth Pi units, it works perfectly fine as ttyAMA0 is the console serial port. However, on wireless/Bluetooth equipped units such as the Pi 3 and the Pi Zero W, ttyAMA0 defaults to the Bluetooth module. This cannot work as the console takes over ttyAMA0, creating a conflict.
In order to set up Gentoo such that it follows the Raspbian configuration, we need to do a few things -
- Unassign ttyAMA0 as the console UART in /etc/inittab
- Assign ttyS0 as the console UART in /etc/inittab (optional)
- Create the dialout group
- Create udev rules file which handles the serial symlinks and assigns the serial ports to the dialout group
- Edit the config.txt and cmdline.txt files for your desired operation
Changing Console Assignment
Raspbian Jesse does the serial console assignment at the kernel level by passing console=ttyAMA0,115200 to the kernel command line in config.txt. Gentoo, however, uses OpenRC and thus uses /etc/inittab to assign the serial console.
Open up /etc/inittab -
nano -w /etc/inittab
Find the line below and comment it out by appending a # at the beginning of the line -
#f0:12345:respawn:/sbin/agetty 9600 ttyAMA0 vt100
Optional: If you need a console serial port, find the line below and uncomment it by removing the # at the beginning of the line. Optionally, you may also want to change the baud rate to 115200 -
s0:12345:respawn:/sbin/agetty -L 115200 ttyS0 vt100
Save the file and exit.
Create The Dialout Group
Create the dialout group with a GID of 20 -
groupadd -g 20 dialout
Any users that need serial port permissions will need to be added to the dialout group in order to use the serial ports just as they would under Raspbian Jesse.
Create Udev Rules
In Raspbian Jessie, there is a custom Udev rule in /etc/udev/rules.d called 99-com.rules. This rule is responsible for ensuring that the serial0 symlink always points to the GPIO14:15 UART while serial1 always points to the other UART. I've made a slight modification to it to assign the serial hardware to the dialout group.
Create the file 99-com.rules -
nano -w /etc/udev/rules.d/99-com.rules
Copy this text and paste it into the file.
SUBSYSTEM=="input", GROUP="input", MODE="0660" SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660" SUBSYSTEM=="spidev", GROUP="spi", MODE="0660" SUBSYSTEM=="bcm2835-gpiomem", GROUP="gpio", MODE="0660" SUBSYSTEM=="gpio*", PROGRAM="/bin/sh -c '\ chown -R root:gpio /sys/class/gpio && chmod -R 770 /sys/class/gpio;\ chown -R root:gpio /sys/devices/virtual/gpio && chmod -R 770 /sys/devices/virtual/gpio;\ chown -R root:gpio /sys$devpath && chmod -R 770 /sys$devpath\ '" KERNEL=="ttyAMA", GROUP="dialout", PROGRAM="/bin/sh -c '\ ALIASES=/proc/device-tree/aliases; \ if cmp -s $ALIASES/uart0 $ALIASES/serial0; then \ echo 0;\ elif cmp -s $ALIASES/uart0 $ALIASES/serial1; then \ echo 1; \ else \ exit 1; \ fi\ '", SYMLINK+="serial%c" KERNEL=="ttyS0", GROUP="dialout", PROGRAM="/bin/sh -c '\ ALIASES=/proc/device-tree/aliases; \ if cmp -s $ALIASES/uart1 $ALIASES/serial0; then \ echo 0; \ elif cmp -s $ALIASES/uart1 $ALIASES/serial1; then \ echo 1; \ else \ exit 1; \ fi \ '", SYMLINK+="serial%c"
Save and exit the file.
Modify The Boot Files
Mount the boot partition -
Open up config.txt -
nano -w /boot/config.txt
Add the following at the end of the file -
This locks the VPU core frequency at 250MHz under normal mode and 400MHz in turbo mode. Locking the VPU core frequency allows the mini UART to maintain a consistent baud rate.
Save and exit the file.
The console= parameter was used in Raspbian Jessie to assign ttyS0 to the console output. Gentoo uses OpenRC and /etc/inittab to assign a serial port to the console output. The caveat to this is that you will not have serial console access until after /root is mounted. If boot time serial console access is necessary, pass the console= parameter at the kernel command line in cmdline.txt.
Open up cmdline.txt -
nano -w /boot/cmdline.txt
Add console=ttyS0,115200 to the kernel command line in the file. An example kernel command line is shown below -
dwc_otg.lpm_enable=0 console=tty1 console=ttyS0,115200 root=/dev/mmcblk0p7 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
Save and exit the file, then reboot the Pi -
Checking The Configuration
Once the Pi is back up, type the following commands -
ls -l /dev | grep ttyS0 && ls -l /dev | grep ttyAMA0
lrwxrwxrwx 1 root root 5 Aug 14 22:28 serial0 -> ttyS0 crw-rw---- 1 root dialout 4, 64 Aug 14 22:28 ttyS0 lrwxrwxrwx 1 root root 7 Aug 14 22:28 serial1 -> ttyAMA0 crw-rw---- 1 root dialout 204, 64 Aug 14 22:28 ttyAMA0
If ttyS0 is assigned as the console serial port, Udev rules will assign ttyS0 to the tty group with 0620 permissions (crw--w----).
Moving The Serial Ports
By default, the Raspberry Pi 3 Model B assigns ttyS0 to GPIO14:15 while ttyAMA0 serves the Bluetooth module. As the mini UART is not a full featured UART, you may want to use ttyAMA0 on GPIO14:15 instead as it is a full featured UART. Fortunately, there are a couple of device tree overlays that will accomplish this.
This overlay flip flops the UARTs by assigning ttyAMA0 to GPIO14:15 while assigning ttyS0 to the Bluetooth module.
This overlay assigns ttyAMA0 to GPIO14:15 while disabling Bluetooth altogether.
In order to implement these overlays, we must add them to our config.txt file. It is recommended that you place both of these overlays in config.txt, then uncomment the one that suits your purpose.
# Uncomment to assign ttyAMA0 to GPIO14:15 and # the mini UART to the Bluetooth Module dtoverlay=pi3-miniuart-bt # Uncomment to assign ttyAMA0 to GPIO14:15 and # disable the Bluetooth module #dtoverlay=pi3-disable-bt
Once you've made the change, save and reboot the Pi.
Checking The Configuration
Once the Pi is back up, run ls -l again to check the configuration -
ls -l /dev | grep ttyAMA0 && ls -l /dev | grep ttyS0
lrwxrwxrwx 1 root root 7 Dec 31 1969 serial0 -> ttyAMA0 crw-rw---- 1 root dialout 204, 64 Aug 14 22:28 ttyAMA0 lrwxrwxrwx 1 root root 5 Dec 31 1969 serial1 -> ttyS0 crw-rw---- 1 root dialout 4, 64 Dec 31 1969 ttyS0
Once the device tree was implemented and the UARTs were switched around, you'll notice that serial0 now points to ttyAMA0 since it is now on GPIO14:15.
You can think of the serial0 symlink as being GPIO14:15 while ttyAMA0 is the PL011 UART and ttyS0 is the mini UART. The serial0 symlink being GPIO14:15, it is always going to point to the UART which is assigned to those pins.
Where To Get Help
Raspberry Pi Foundation UART Page - https://www.raspberrypi.org/documentation/configuration/uart.md
Gentoo On Alternative Architectures - https://forums.gentoo.org/viewforum-f-32.html
NeddySeagoon - his articles on Gentoo Raspberry Pi 64-bit got me a working Gentoo install on my Pi 3 Model B, and I've been toying with it since.