RDS display on a Raspberry Pi

Earlier I modified my radio to output raw bits from its RDS decoder chip. The radio already displays a Programme Service name, but for FM DX purposes, it's fun to see more data. Also, the Programme Identification code can be decoded from very weak signals, identifying distant stations. And I can receive interesting traffic information messages by decrypting RDS-TMC with the encryption keys I've recovered. Now that I have a Raspberry Pi, it's time to make a dedicated little display.

First, I changed the radio connector from my previous modification. This one, salvaged from a mystery phone device I found at a flea market, doesn't come loose as easily as the Mini-DIN:

[Image: A corner of a radio labeled 'SANGEAN', with a hole cut in it and a phone connector in the hole. A phone connector is being held next to it.]

I bought a discount 2x16-character HD44780-compliant LCD at the local parts store and made a 4-pin connection to the Raspberry Pi GPIO header. I used another two GPIO pins to interface the Pi with my radio (one for data, one for clock). I then wrote a C program to read the 1187 bps RDS data, process it for error correction and synchronization, and output it to a Perl script for interpretation. The script then returns a text string to be displayed on the LCD. The bcm2835 library is used for GPIO interaction.

Turns out GPIO is not very good for data rates this high. The C program takes about 5 samples per RDS clock cycle, and uses 97 % of the CPU time. With the Perl script and LCD update running, the poor Pi can't keep up with realtime data, and lots of bits are lost. But after waiting patiently, I finally get a Programme Service name, Programme Identification code, and RadioText.

On the left, my radio. On the right, the RasPi in its doghouse:

[Image: The same radio as above, but now its LCD display and dozens of buttons are shown. On the display, the text '87.90 YLE YKSI', the time 18:41, and indicators 'FM', 'Stereo', 'RDS', 'HOME', 'Page 1'. A cable goes from the radio to a device on the right which is contained in a little thrash can of sorts. The device has a small LCD display that reads 'YLE YKSI 6201 Kultakuume'.]

Experimenting with lower sampling rates will hopefully alleviate the problems. But it kind of works already.

Update 2013-04-01: According to this benchmark, this very library should be able to handle GPIO speeds of several megahertz. So I tried running the program in strace to see what it's doing to burn so much CPU. Turns out it's sitting in a single nanosleep() call and never returning!

I experimented a bit and ended up replacing all calls to bcm2835_delayMicroseconds() (which uses nanosleep()) with calls to usleep(). And it works! CPU utilization is at 10% maximum, and a PS name appears lightning fast when changing stations. So, something was probably wrong with nanosleep() or bcm2835's implementation thereof.

9 comments:

  1. Replies
    1. Loving this I have a raspberry myself set as a Media streamer to pick up online video and movies/television from my home server. works so well I'm building one for my parents in a old IDE NAS box to make a custom box for them love seeing how people extend these past what they were ever designed for originally

      Delete
  2. There's an awful lot of overhead, if the RPi cannot sample that. 5*1187, so around 6kHz sampling vs. 97% of the 700 MHz CPU. That's like 0.1% efficiency of the sampling code :)

    Well, it's not really that simple, but it shows why one should not use overkill system to do the simplest tasks. One could read the RDS data with the smallest ~100kHz-1MHz 8bit MCU from ATMEL and send data e.g. over UART/I2C/SPI (which do have a dedicated HW on the RPi) to the RPi to make things more feasible. In fact, I bet that 8bit MCU @ 1 MHz could easily do the whole system and still be able to idle more.

    This shows well, why "embedded" linux is not the correct solution for everything. Doing bit banging etc. in user mode is not wise, especially if it needs to be done constantly. Even if this was a kernel module and utilize interrupts, it still would have an awful efficiency in terms of code complexity and performance overhead compared to the 8bit MCU solution.

    ReplyDelete
    Replies
    1. This blog is all about doing simple tasks using completely ineffective hardware

      Delete
    2. And a very good and enjoyable blog it is!

      The previous post was not meant to be critisim, just some gibberish about OS overheads and current hacking fashion trend to do ALL "embedded" stuff with RPi :) (or arduino). But yeah, its more important to explore and try out stuff with the HW available than leave things undone because they are not efficient.

      Delete
    3. The hardware-boosted I2C will be my next shot at this!

      Delete
  3. Hello,

    Would you be able to make the rds/TMC info for a RTL don gle, that has fm,dab,digital TV?
    (or publish your source code ..)
    Marc

    ReplyDelete

The comments section is pre-moderated; it will take some time for the comment to show up.

You might want to check out the FAQ first.