author: Tyson Liddell
tags: capturing-composite-video-with-a-microcontroller
Microcontrollers like the TM4C123GH6PM include UART (universal asynchronous receiver-transmitter) hardware. Two devices connected via UART can establish a serial communication channel for sending data to each other. The communication is asynchronous because the two ends of the channel do not need to synchronise their clocks. Rather, each transmitted frame (of 5-9 bits) is bookended by a start bit and a stop bit that the receiver uses to sync itself up with the incoming data at the time of receipt.
Communication over a raw UART channel is not reliable, especially when prototyping on a breadboard, where electrical noise and poor connections are common. Indeed, data corruption was observed on the UART when sampling the PAL active video signal. However, now that a robust method for detecting data transmission errors has been implemented, a reliable communication protocol can be built.
Initially, I came up with a simple protocol to allow the MCU to send packets to a receiver, where each packet would contain a complete scanline:
/*
* Send video field on UART with following simple, probably not robust,
* protocol:
* - Tx a protocol packet (contains an entire scanline):
* +-----------------+--------------------+---------------+---------------+
* | scanline_number | num_scanline_bytes | scanline_data | CRC32 checksum|
* +-----------------+--------------------+---------------+---------------+
* - Wait for response from the recipient and then:
* - If ACK (0xFF) received, increase sequence number and send packet for
* next scanline
* - If response is anything other than `0xFF`, resend the same packet.
*/
The MCU would continually attempt to send each packet in sequence, advancing to the next only after receiving an ACK from the receiver.
{% include github_commit.html repo='tysonliddell/bare-metal-tiva' sha='c226b5036a3c67841fe1f5d052d76d8549090645' %}
In an effort to loosely couple the receiver to the data being transmitted, the protocol uses packets of variable size, but this is where things get dicey. If the value of num_scanline_bytes gets corrupted, the receiver will not be able to make sense of the packet. The protocol could be modified to use byte stuffing or COBS to iron out this wrinkle; however, another problem arises with variable length packet sizes: a CRC checksum is only guaranteed to perform well if the packet size is capped. In the end, I settled on the XMODEM protocol. It's simple, elegant and can easily solve all of these problems.
XMODEM is an iconic file transfer protocol that has been around since the 70s. Its simplicity allowed it to be widely adopted by BBSes across the world and it has formed the foundation for a number of newer protocols. The protocol itself is specified in this one-pager, which I won't repeat here. It's similar to my attempted protocol above, but with some important differences:
This project uses the XMODEM/CRC protocol, which replaces the naive checksum of the original spec with a 16-bit CRC. Unfortunately, the XMODEM/CRC protocol does not account for the fact that bits are sent least significant bit first on UART. As mentioned earlier, this means that burst error detection will not be optimal. However, the protocol is still good enough for the purposes of this experiment.
{% include github_commit.html repo='tysonliddell/bare-metal-tiva' sha='7812d8f55a99e687c0aeef218ceacda2f3c287a1' %} {% include github_commit.html repo='tysonliddell/bare-metal-tiva' sha='094376a435302c29d2460d0f5f50de920f933bd9' %}
With the reliable XMODEM/CRC protocol in place, application-level data
corruption was eliminated! Minicom was configured to receive the data on the
xmodem protocol with lrx -c, provided by lrzsz. Using a script to
convert the measurements to a pgm file, an image is successfully obtained
from the signal:

This is an image from a scene in Men of Honour, starring Robert De Niro and Cuba Gooding Jr.
{% include github_commit.html repo='tysonliddell/bare-metal-tiva' sha='b4941050c938c656b33e864ee92a2d765cc87132' %}
Here is a quick recap of what went into obtaining the image above: