Serial debugging

From postmarketOS
Revision as of 05:45, 20 November 2020 by Knuxfanwin8 (talk | contribs) (fix link)
Jump to navigation Jump to search

To get kernel or bootloader logs on a system without a working display/full USB configuration, a serial cable may be used, which allows us to preview the serial console on the device.

To debug your device with a serial cable, you will need:

  • A serial debugging cable for your device. You will need to make this yourself, so prior experience with soldering and soldering tools is recommended.
  • An USB-UART adapter that will allow you to connect the UART cable from your phone/tablet to your computer.
  • A piece of software like screen, PuTTY or CuteCom that will be used to access the output from the USB-UART adapter on the computer.

For the purpose of this page, the device is the phone/tablet you want to debug, and the computer is the device you want to access the logs from.

Finding the UART ports on your device

The serial port can be accessed by different means, depending on the device - through the microUSB port with a special cable, through the headphone jack, or only through UART ports on the main board. As such, the first step will be finding the proper way to connect to the UART ports on your device.

First, look at your device's wiki page and the Serial debugging:Cable schematics page. You may find your device on there already - in which case, this section can be skipped. If you can't find any info, or you're unsure, continue with this section.

Identifying the MUIC

Start by identifying the Micro-USB Interface Controller used in your device. The MUIC is what handles things like USB-OTG - it usually figures out what a cable is supposed to do by checking the resistance between the ground pin and the ID pin. Most MUICs implement an UART jig mode as part of the Carkit standard (see the Micro-USB Interface Controller page), which allows the USB port to be used as a serial input/output port.

You can try looking for kernel options with "MUIC", "USB" or "UART" in the name in the downstream kernel's defconfig - if you find a seemingly SOC-specific option, grep through the kernel source to find the driver (hint: don't include the CONFIG_ part). Sometimes the MUIC is integrated into the PMU/PMIC or handled by the device's chipset, in which case using generic values from the MUIC page may work.

Once you've found the model of your MUIC, look for similar chips in the MUIC page to find the resistance values you should use for your cable. If you're unsure, look up your MUIC chip's datasheet; if you can't find one, or the datasheet does not have the resistance value table, use the default values.

Finding the UART ports on your device's main board

Sometimes there is no other solution but to poke at random motherboard pins to find the serial port. This is mostly a lucky process, and you need to have access to an oscilloscope (maybe a sensitive multimeter would work as well?). With such an instrument you try to find tx (and gnd) by measuring between different pins when you:

  • send either garbage, or a repeating pattern to the serial port at /dev/ttysomething (if you have a kernel where it's working)
  • reboot your phone, hopefully it writes something during boot (but that's really trying luck)

Locating tx is usually good enough for debugging, but rx should be quite close, with a high impedance, or more likely a pulling resistor. A pull-up or pull-down resistor will make the pin look like gnd or vcc.

Building the cable

Depending on the cable you need to make (microUSB, headphone jack, USB-C or just pins on the board) the process might be different. It's helpful to have a breadboard and some goldpin connector cables to go with it, as it makes putting together and tweaking the cable easier and reduces the amount of soldering that has to be done. You can find the build instructions for your cable on the Serial debugging:Cable schematics page.

microUSB-based cables

There are several ways to connect wires to a microUSB plug:

  • solder the wires to a breakout board (at the time of writing this is only available in backorder, perhaps we should increase the demand somewhat?)
  • using a USB Micro B Male Plug to 5-pin Terminal Block
  • solder the wires directly to a microUSB type B plug (note: the solder pads are very small, so it can be difficult to get just right. If you plan to use this method, order multiple plugs, in case you need to start over.)

Soldering a connector on your device

This can be a bit involved, but is generally necessary if you want to use it:

  • This procedure is dangerous for your device, even more so if you are not very experienced
    • Prefer to ask help in a hackerspace, makerspace, fablab or similar you'll practice another day on something easier
    • If you have to solder it yourself, it's probably a good idea to practice on an old motherboard before
  • Prefer soldering short cables to the PCB instead of full-length ones
    • The smaller (diameter) the cables, the better, generally
    • too long or too thick and the pads you have soldered risk being teared apart by the cables
    • too small and it will be a hassle to work with
    • The best is to have them a couple (4-8) centimeters long, to solder them, solder a connector on the other end, and scotch tape them to the pcb
    • Please, don't forget to pick insulated wires

Plugging the cable in

Once your cable is assembled, it is time to plug it into your USB-UART converter. The most important pins you need to know about are:

  • Ground - usually a black cable.
  • Power/VCC - usually a red cable.
  • TX - The transmission line, aka the output.
  • RX - The recieve line, aka the input.
Warning! DO NOT CONNECT THE POWER PIN IF YOU DON'T KNOW YOUR DEVICE'S UART OUTPUT VOLTAGE! Most UART adapters will send 5v or 3.3v by default and phones will usually use 1.8v (occasionally 3.3v). Plugging the power/VCC pin in when the voltages don't match on your adapter and device may kill it. See the "3.3v vs 1.8v" section at the bottom of this page.

To recieve logs, you will only need to connect the ground and RX wires. To send information through the serial console, you will also need to connect the VCC and TX wires.

Plug the TX (output) wire from your cable to the RX (input) line on your adapter. (You'll need to do the reverse - RX to TX - if you want to connect the TX line.)

Then, plug the other end of the cable into your device. Some devices may automatically boot up when the jig is plugged in - if your device starts up without you pressing the power button when you plug the cable in, it means that the resistance is being detected and the serial mode has been triggered.

Connecting to the serial console from your computer

To connect to the serial console, you'll need a program that can do so. For this you can use:

  • screen - $ screen /dev/ttyXXX <baud_rate>
  • PuTTY (GUI)
  • CuteCom (GUI)
  • ...or any other program that supports connecting to the serial console.

The baud rate used for the serial console will be stored in your device's device tree (assuming you are using mainline, otherwise you may have some luck looking around downstream's board and defconfig files).

If you're using an USB serial adapter, the path to your TTY will be /dev/ttyUSB[X], where [X] is a number. You can also look through the output of ls /dev/tty*; this will come up with a few different TTYs though, including ones that are used by the system.

TODO Is there a better command for this?

Alternatives to using a serial cable

You may have some luck with using RAM-storage-based methods of serial debugging. Tools like pstore and ramoops make this easy - they usually just need to be enabled in mainline and downstream, and a downstream kernel can be used to access the pstore-reserved RAM region where logs are dumped. The path for this is /sys/fs/pstore/console-ramoops, although older devices may use /proc/last_kmsg.

TODO Verify this and elaborate.

3.3V vs 1.8V UARTs

Schematic for a 3.3v->1.8v UART voltage divider

Most phones expose their UART pins on 1.8V voltage, and most USB-UART converters expect UART side to have 3.3V. This works well for receiving characters from device; this is enough to read bootloader logs or kernel boot logs (dmesg). However sending 3.3V to device that expects 1.8V is dangerous; so you can't use shell over UART without an additional effort.

You'll need a voltage divider at least on converter->device TX line: use this answer

See also