> For the complete documentation index, see [llms.txt](https://amobile-solutions.gitbook.io/yocto-developer-guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://amobile-solutions.gitbook.io/yocto-developer-guide/test-and-use-the-interface/serial/serial-iot-800n-g420.md).

# Serial - IOT-800N-G420

## Overview

The DB9 port supports three protocols, selected in software:

| Signal path | Part                                   |
| ----------- | -------------------------------------- |
| USB to UART | CH340C, behind the internal GL852G hub |
| Transceiver | Fintek F81439AN, multi-protocol        |
| Connector   | DB9 male                               |

The transceiver protocol is chosen by three GPIO lines.

{% hint style="warning" %}
With nothing holding those three lines, the on-board pull-ups select **low power shutdown** — every I/O pin goes high impedance and the port does nothing at all. A mode has to be applied before the DB9 will work.
{% endhint %}

## Identifying the port

The board exposes several USB serial devices. Two of them are the CH340C; the rest belong to the LTE module.

```
for p in /dev/ttyUSB*; do
    echo "$p -> $(udevadm info -q property -n $p | grep ID_MODEL=)"
done
```

```
/dev/ttyUSB0 -> ID_MODEL=USB_Serial
/dev/ttyUSB1 -> ID_MODEL=USB_Serial
/dev/ttyUSB2 -> ID_MODEL=LE910C4-WWX
/dev/ttyUSB3 -> ID_MODEL=LE910C4-WWX
/dev/ttyUSB4 -> ID_MODEL=LE910C4-WWX
```

## Selecting the protocol

```
am-serial-mode              show the current mode
am-serial-mode list         every supported mode and its DB9 pinout
am-serial-mode rs232
am-serial-mode rs485
am-serial-mode rs422
am-serial-mode off          low power shutdown
```

### Supported modes

| Mode            | Description                                |
| --------------- | ------------------------------------------ |
| `rs232`         | Pure RS-232                                |
| `rs485`         | RS-485 half duplex, TX enable low active   |
| `rs485-high`    | RS-485 half duplex, TX enable high active  |
| `rs485-term`    | RS-485 with termination resistor           |
| `rs422`         | RS-422 full duplex                         |
| `rs422-term`    | RS-422 with termination resistor           |
| `rs232-coexist` | RS-232 coexisting with RS-485              |
| `off`           | Low power shutdown, all I/O high impedance |

### DB9 pinout per mode

| Mode   | Pinout                                             |
| ------ | -------------------------------------------------- |
| RS-232 | pin2 RXD, pin3 TXD, pin5 GND                       |
| RS-422 | pin1 TX−(B), pin2 TX+(A), pin3 RX+(A), pin4 RX−(B) |
| RS-485 | pin1 D−(B), pin2 D+(A)                             |

## Applying a mode at boot

The `am-serial-mode` service reads `SERIAL_MODE` from `/etc/amobile/serial.conf`:

```
SERIAL_MODE=rs232
```

```
systemctl status am-serial-mode
systemctl restart am-serial-mode
```

{% hint style="info" %}
libgpiod releases a GPIO line when the process holding it exits, so the selected mode only lasts while something holds those three lines. The service keeps a `gpioset` process alive for exactly that reason, which is why `systemctl status` shows it as `running` rather than `exited`.
{% endhint %}

## Loopback test

Short DB9 pin2 to pin3, then:

```
am-serial-mode rs232
am-serial-mode test
```

Expected output:

```
Loopback test on /dev/ttyUSB0
PASS - sent and received "am-serial-loopback-1099"
```

To do it by hand:

```
P=/dev/ttyUSB0
stty -F $P 115200 raw -echo
(timeout 3 cat $P &) ; sleep 0.3 ; printf 'loop-test\n' > $P
```

{% hint style="info" %}
RS-485 is half duplex, so shorting pin1 to pin2 does **not** produce a loopback. Testing it needs a second node or an external RS-485 adapter.
{% endhint %}

## Using the port from an application

Once a mode is applied the port behaves like any other serial device:

```
stty -F /dev/ttyUSB0 115200 raw -echo
microcom /dev/ttyUSB0
```

## Controlling the mode directly

The three lines are exposed by name and left unclaimed by the device tree, so an application can drive them itself instead of using `am-serial-mode`:

```
gpioinfo | grep SER_MODE
```

```
line 153:  "SER_MODE2"  input
line 154:  "SER_MODE1"  input
line 155:  "SER_MODE0"  input
```

Each line drives the gate of an N-MOSFET whose drain is the transceiver's mode pin, pulled up through 4.7K, so a high GPIO pulls the mode pin low. The datasheet table is written for the mode pins, which are active low, so the GPIO values are the inverse of the table values:

| Mode                               | GPIO 155 / 154 / 153 |
| ---------------------------------- | -------------------- |
| RS-422 full duplex                 | 1 1 1                |
| Pure RS-232                        | 1 1 0                |
| RS-485 half duplex, TX EN low      | 1 0 1                |
| RS-485 half duplex, TX EN high     | 1 0 0                |
| RS-422 with termination            | 0 1 1                |
| RS-232 coexisting with RS-485      | 0 1 0                |
| RS-485 with termination, TX EN low | 0 0 1                |
| Low power shutdown                 | 0 0 0                |

```
gpioset SER_MODE0=1 SER_MODE1=1 SER_MODE2=0 &
```

{% hint style="warning" %}
`gpioset` in libgpiod v2 blocks while it holds the lines. Backgrounding it is required; letting it exit releases the lines and the transceiver falls back to shutdown.

Running `am-serial-mode` afterwards replaces whichever process is holding them, so stop the service first if an application is managing the mode itself:

```
systemctl stop am-serial-mode
```

{% endhint %}
