How I discovered RDS

One stormy night in 2007, I was listening to local FM stations while viewing a live spectrogram of the audio on the computer, through the radio's Line Out. Nearly all stations seemed to have a persistent sinusoid tone at 19 kHz, on the edge of human hearing. Turned out it's a pilot tone that the receiver uses to regenerate various subcarriers at their correct phases. The most prominent of these is the stereo subcarrier at 38 kHz, used to transmit the stereo difference signal.

[Image: Spectrogram with a frequency scale from 0 to 22000 Hz. There's a signal that looks like music, from 0 to 17000 Hz. A pure sine tone is centered at 19000 Hz. A low-power, double-sideband signal with a bandwidth of 4000 Hz is also centered at 19000 Hz.]

But something else is also visible on the spectrogram, mirrored on both sides of the pilot tone. It's a quiet signal that has a strange repetitive pattern, almost like binary data of some sort. Let's listen to a gradual downconversion I made on an FM station, revealing how the mystery signal sounds. Here I tune the heterodyne from baseband to 19 kHz.

It definitely sounds like data. I knew FM station names are transmitted alongside the audio, and that it's called RDS (Radio Data System). Could this be the RDS signal? Why does it appear at 19 kHz when the specification says it should be on the third harmonic of the pilot tone, a 57 kHz subcarrier? Just a weird aliasing/mirroring artifact? It's so close to the audio band that it actually gets interfered by some of the highest audio frequencies. But the symbol rate indeed seems to be close to 1187.5 bps, which is the RDS baud rate.

How exactly did the data end up there from 57 kHz? It could be a complex mechanism. Afterall, what I'm getting out of Line Out is not the raw FM demodulated radio signal, because the sound would be monophonic. If I switch the radio to mono reception, the data disappears altogether. So the data is probably being leaked by the stereo decoder, and is somehow related to the way the decoder applies the difference signal to the monophonic main signal. The manufacturer just didn't want to go through the trouble of filtering the artifacts out, because they're near-ultrasonic and thus practically inaudible. The mono/stereo switch probably just switches the stereo decoder off and feeds the actual demodulated baseband audio to Line Out instead.

Being the signals geek that I am, I just couldn't leave it at that. I read the 160-page specification and wrote a complete RDS demodulator and decoder to solve this mystery. And I was right! Here's a station called YLE Radio Suomi, running Radioterapeutti. The data is being decoded live from the quiet artifacts in the Line Out audio.

[Image: A screenshot resembling an LCD with various text fields. The dominating elements read 'YLESUOMI' and 'Radioterapeutti'. Smaller fields read '6203', '94.0', and 'Varied Speech'. A row of indicators shows positive status for 'RadioText', 'EON', 'TMC', and 'TP', and negative status for 'RT+', 'eRT', and 'TA'. There's also a signal level indicator showing roughly 40%.]

But it's so much more than just a station name. There's RadioText that often contains a description for the currently running programme; there's a numeric station identifier that can be decoded from even faint signals; there's information about what's currently on on other stations and what are their frequencies; and so on. Also the traffic messages displayed by car GPS navigators are transmitted to cars over RDS. And there are options for pager systems, emergency messages, and whatnot.

All this led me to make modifications to my radio and also embed all this onto a Raspberry Pi.

Portable TV, Raspberry-Pified

Recently I entered the era of video-capable portable music players. About time, too. My device of choice is this Action-branded Taiwanese gem from 1988 with a 5-inch CRT display (B/W), AM/FM radio, television receiver, and cassette player (mono, no rewind). It takes 9 D-sized batteries.

[Image: A person holding a portable television-cassette player measuring roughly 30 by 30 by 20 cm. The tape compartment is open and a yellow cassette is in. The device is labeled 'BLACK/WHITE TELEVISION-RADIO-CASSETTE PLAYER' with the brand name 'ACTION'. There's a cathode-ray type display roughly 20cm across; band selector for VHF low, VHF high, UHF, FM, and AM; A tuning wheel; a volume wheel; cassette control buttons on top; and a carrying handle. In the background, there's a bigger cassette deck, and a coffee cup with drawings of sheep.]

The batteries inside were leaking quite a bit so I removed them in favor of a DC adapter. They actually occupied roughly half of the casing. After removing them the device looked very empty and was unbalanced because of the heavy CRT. So I had to come up with something to fill the space with.

Then it struck me: it's a perfect video terminal and tape drive for the Raspberry Pi!

The screen

The Action has a 5" black-and-white CRT display and a television tuner. The receiver is on an AN5151N integrated circuit. Now, the Raspberry Pi outputs composite video. Someone else has tried injecting composite video onto the AN5151N before, with results that didn't look very successful to me at first sight, so I just ended up buying a cheap RF modulator. It modulates a TV-frequency carrier with the composite signal, and that can be fed into the aerial input of the TV to be demodulated again.

[Image: The cathode ray display showing the Linux console running the 'top' command. On top of it, a Raspberry Pi with two small devices connected into its USB ports and an RCA cable connected into its analog video output.]

Aerial input to the TV is via a miniplug, so I had to improvise an adapter for coax. It works almost perfectly, except that the CRT crops out the extremes of the display.

The battery compartment before and after refurbishing:

[Image: Two photos showing a big battery compartment, empty in the first picture and filled with electronics in the second one, with several wires coming out.]

The tape

The cassette player of this device is pretty simple. It does not have stereo, rewind, auto-stop, or any of the other hi-tech functions that many modern-day Walkmen have. It doesn't even stop automatically when Eject is pressed. But it works.

[Image: The cassette player opened, showing the tape drive mechanism with several wheels connected to each other via rubber strings, and the control buttons connected to them via springs and levers.]

I've written a little Perl program that can write data onto cassettes and read it back using a sound card. For this project I removed the sound card step. The way I've written the data onto the tape is such that when amplified with the tape player's U821B chip, the voltage can directly be used as a binary 3v3 GPIO logic level. I wouldn't recommend this though, unless you know what you're doing, because the GPIO port is essentially a direct connection to the CPU and there's no overvoltage protecti... blast, I've just fried my RasPi!

A moment of silence. And a screenshot honouring the memory of its last words over ssh. Here, a logic "1" is low voltage, and "0" is high. A wee bit too high.

111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111110110011Write failed: Broken pipe
$ █

Anyway, I also modified the TV's power circuitry to supply power to both the CRT and tape player at the same time, and installed a switch to silence the speaker when reading data. If it weren't for the aforementioned overvolt accident, this would now be complete. Cassettes could be used to store e.g. Vectrex games; also reading C64 cassettes will be supported.

Moral of the story: The GPIO port is not 5V tolerant! Assuming there will a second attempt some day, I'll just use a transistor to pull the GPIO pin high when there's a high on the tape. Or use a sound card.