I’m Kayla. I flash boards, watch boot logs, and plug in way too many USB dongles. I’ve used all the usual tools on Ubuntu, Fedora, and a Raspberry Pi. Some days it was smooth. Other days I stared at a blank screen and sighed.
You want the short version? There’s a quick way, a stable way, and a “why is this broken” way. I’ve used all three.
While researching this stuff, I found an especially helpful overview on Freedom Penguin that gave me a few extra tricks.
If you’d like to dig even deeper into my serial-port rabbit hole, I turned the whole adventure into a standalone Freedom Penguin article: I Tried Viewing Serial Ports on Linux. Here’s What Actually Worked.
First look: What serial ports do I even have?
When I plug in a USB-to-serial adapter, I check these spots first. It takes seconds.
I open a terminal and run:
ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null
On my laptop, with two adapters (an FTDI and a CH340), I saw:
/dev/ttyUSB0 /dev/ttyUSB1
Curious about the hardware I trust when I’m not just tinkering but doing offensive-security work? I break down my daily drivers in The Laptops I Actually Use with Kali Linux.
I like to confirm with the kernel log. It tells me which is which:
dmesg | grep -i tty
Real output from my Ubuntu 22.04 box:
[ 542.108931] usb 1-3: ch341-uart converter now attached to ttyUSB0
[ 546.512021] usb 1-4: FTDI USB Serial Device converter now attached to ttyUSB1
If it’s an Arduino-style board (CDC ACM), it may show up as ttyACM:
[ 662.219471] cdc_acm 1-2:1.0: ttyACM0: USB ACM device
You know what? That little hint—FTDI vs CH340 vs ACM—saves time.
The stable names that don’t move around
ttyUSB0 can change when you replug. That bit me while flashing a robot car brain in my garage. So I use the by-id path. It stays steady.
ls -l /dev/serial/by-id/
Here’s what I got with an FTDI and a CH340:
usb-FTDI_FT232R_USB_UART_AH06XYZ1-if00-port0 -> ../../ttyUSB1
usb-1a86_USB2.0-Serial-if00-port0 -> ../../ttyUSB0
I now connect with the by-id link. No guessing:
screen /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AH06XYZ1-if00-port0 115200
If I need more info about a port, this helps a ton:
udevadm info -a -n /dev/ttyUSB0 | egrep '{idVendor}|{idProduct}|serial'
Sample bits I saw:
ATTRS{idVendor}=="1a86"
ATTRS{idProduct}=="7523"
ATTRS{serial}=="CH340-ABC123"
Live watch while plugging things in
When I’m swapping cables fast, I keep a live feed running:
sudo udevadm monitor --udev --property
And I plug the adapter. I see lines like:
UDEV [1062.123456] ID_VENDOR_ID=0403
UDEV [1062.123456] ID_MODEL_ID=6001
UDEV [1062.123456] DEVNAME=/dev/ttyUSB1
It’s like a tiny control tower. I plug, I read, I move on.
Can I talk to the device? Let’s open it.
I’ve tried a lot here. Some tools felt comfy; some… not so much.
- screen: always there, a bit clunky
- tio: fast, simple shortcuts, my current favorite
- minicom: old but solid, needs setup
- picocom: light, no fuss
- GtkTerm/CuteCom: GUI, nice for quick checks
I also tried out SerialTool for a quick GUI that speaks serial, TCP, and UDP alike—its feature rundown in this LinuxLinks overview convinced me to give it a spin.
Let me explain how I actually use them.
screen (works almost everywhere)
screen /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AH06XYZ1-if00-port0 115200
To quit: Ctrl-A then K (or Ctrl-A then ). It’s not friendly, but it never leaves me hanging.
tio (my daily driver now)
tio -b 115200 /dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0
Quit with Ctrl-T then Q. It shows port speed, reconnects clean, and handles weird resets better for me. On Fedora 39, it felt snappy even with noisy boot logs.
minicom (the “once it’s set, it’s fine” tool)
First time, set the port and speed:
sudo minicom -s
Then start:
minicom -D /dev/ttyUSB0 -b 9600
It’s chatty, but steady. I used it to talk to a GPS puck at 9600, and it never froze.
A barebones test (no extra tools)
Sometimes I go simple:
stty -F /dev/ttyUSB0 115200 -echo -icrnl
cat /dev/ttyUSB0
Open another terminal to send:
echo "test" > /dev/ttyUSB0
It’s basic, but it proves the link.
Real log: router console at 115200
Hooked to a little OpenWrt router with an FTDI:
tio -b 115200 /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AH06XYZ1-if00-port0
What I saw:
U-Boot 2022.07
CPU: MediaTek MT7621
Hit any key to stop autoboot: 2
I tapped a key, dropped to the boot menu, and fixed a bad env var. Clean save. Deep breath.
Need to confirm the network path once the device’s boot sequence is sorted? I lean on mtr for that, and I explain why it beats a simple ping in MTR on Linux – My Honest Take from the Terminal.
The permission gotcha that ate my afternoon
If you see “Permission denied,” it’s likely the dialout group. I forgot this on my Pi after an update.
Check your groups:
groups
If you don’t see dialout, add it:
sudo usermod -aG dialout $USER
newgrp dialout
Log out and back in if it still acts weird. Then try your port again.
When things go wrong (and they will)
I keep these quick checks handy.
- Is the kernel module loaded?
lsmod | egrep 'ftdi_sio|ch341|cp210x|pl2303'
- Did the kernel log complain?
dmesg | tail -n 30
I’ve hit this with a flaky PL2303 clone:
pl2303 ttyUSB2: usb_serial_generic_read_bulk_callback - urb stopped: -32
That adapter went in the “bad cable” jar. A new one fixed it. Harsh, but fair.
- Is it even a serial thing?
lsusb
I look for vendor IDs I know:
- FTDI: 0403:6001
- CH340: 1a86:7523
- CP210x: 10c4:ea60
- PL2303: 067b:2303
If it’s not there, it might be power. I had a board that needed a powered hub in winter, when my desk got cold. Not kidding.
Make your own stable name (like “arduino_nano”)
I like friendly names. So I add a udev rule. This is what I used for a Nano with a CH340:
Create a file:
sudo nano /etc/udev/rules.d/99-serial-friendly.rules
Add:
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="arduino_nano"
Reload and replug:
sudo udevadm control --reload
sudo udevadm trigger
Now I can do:
“`
tio –