UART
UART is the simplest way for two chips to talk: one wire for each direction, and bytes going over them one bit at a time. You'll also hear it called serial.
Each side has a TX pin that sends and an RX pin that listens, so the wires cross: TX on one side goes to RX on the other. A third wire joins the two grounds, which gives both sides the same idea of zero volts.
There is no clock wire. Instead, both sides agree on a speed beforehand, called the baud rate. At 115200 baud, one bit lasts about 8.7 millionths of a second. If the two sides disagree on the speed, the bytes arrive as garbage.
The line rests high. A low start bit says a byte is coming, eight data bits follow with the lowest bit first, and a high stop bit ends it. That's ten bits for every byte, so 115200 baud moves 11,520 bytes a second. The picture above is the letter N, which is the number 78.
UART joins exactly two devices. To put several parts on the same wires, you want I²C or SPI.
What uses it
These parts all speak UART:
- USB-serial adapters, which put your computer on the other end of the wires
- GPS receivers, such as the NEO-6M
- Bluetooth modules, such as the HC-05
- LiDAR rangefinders, such as the TF-Luna
- The LEGO Build HAT, whose library does all of this for you
UART only moves the bytes. What they mean is up to the part, and its data sheet lists them.
The Pi's pins work at 3.3 volts, and 5 volts can damage them. Check your part before you connect it. A 5 V part needs a level shifter between the two, and many USB-serial adapters have a switch or jumper that sets them to 3.3 V.
Try it with one wire
You can try UART with no other parts. Join the Pi's TX pin to its own RX pin with a jumper wire, and whatever it sends comes straight back to it. This is called a loopback.
- Pin 8GPIO 14The Pi sends here
- Pin 10GPIO 15The Pi listens here
Pi and its devices come from a library, not from the language, so this code won't build
without it. In IntelliJ, choose Tools | Nylon | Add Nylon Library… and pick raspberry-pi. That adds
one line to your project's build.markup.code:
(+dependencies : RepositoryDependency coordinate={"com.grandtheorem:raspberry-pi:0.1.0"} /)
Every file starts with its namespace. Pi is the board.
namespace loopback
import grandtheorem.rpi.Pi
Ask the board for its UART at 115200 baud.
entrypoint.default main() {
let uart = Pi.uart(115200)
Send one byte. It leaves on pin 8, and the ten bits take about 87 millionths of a second to reach pin 10.
uart.write("N")
Make room for one byte, then read. readBytes waits up to the timeout and answers how
many bytes it read.
let received = mut u8[1]
let timeout = 100.milliseconds()
let count = uart.readBytes(received, timeout)
A count of 0 means the timeout passed with nothing to read. println shows up in
IntelliJ's run window.
if (count == 1) {
println("Byte ${received[0]} came back")
} else {
println("Nothing came back: check the wire")
}
}
With the wire in place, the run window shows the N's number:
Byte 78 came back
Pull the wire out and run it again, and you get the other message. If you get it with the wire in
place, check the wire first. If you have more than one board, check the run window too: its first line, Running ... on,
names the board the program went to, and it should be the one you wired.
Connecting a real part
A real part uses the same two pins, plus ground. Remember the wires cross: the Pi's TX goes to the part's RX, and the Pi's RX to the part's TX.
- Pin 6GNDTo the part's GND
- Pin 8GPIO 14To the part's RX
- Pin 10GPIO 15To the part's TX
Then set the program's baud to the one in the part's data sheet.
Good to know
A read gives you what has arrived so far. That can be part of a message, so to read a longer one, keep reading until you have all of it.
Bytes wait for you, up to a point. Up to 2,048 bytes are kept while your program is busy with something else. Any more than that are lost.
The board's console gives way. The board normally uses these pins for its own boot
messages. The first Pi.uart call takes them over until your program ends.
For a terminal, use writeLine. It ends the line the way a serial terminal expects.
This program ran on a Raspberry Pi 3 B+, as this page shows it.