Building a Wifi Radio – Part 8, Adding a Tuning Control

This is the eighth part of an ongoing series about building a low cost, open source streaming internet radio based on the ASUS WL-520gU Wireless Router.  If you haven’t already, check out the previous parts (see the links at the end of this article) for some background about the project.

In part seven, we added an LCD status display for the radio that shows the stream name as well as the artist and title of the current track.  In this part, we’ll add a tuning knob that lets us change stations without using a computer.

It turns out that this is mostly a software exercise, made simple by taking advantage of the analog to digital converter function of the Atmel ATmega168 AVR that is controlling the LCD display.  The addition of the tuner control turns the display circuit into a very simple user interface.  Turn the knob and the station changes.  The position of the knob determines what station the radio is “tuned” to, and when combined with a calibrated scale it will make it easy to change to any one of the several streaming radio stations stored as presets (favorites?) in the router.

To give you an idea of how this works, here is a demo of the tuner control changing between ten preset stations I have set on the router.  The tuner control is in the upper right hand corner of the breadboard.  As I adjust the control, the music changes and LCD display updates to show the name of each new station.

Is that cool or what?

If you are interested in adding this functionality to the radio, keep reading and I’ll show you how.

Changes to the hardware:

You will need:

  • The completed AVR-based LCD display from part seven
  • A 1k-10k trimmer or potentiometer, linear taper
  • Some hookup wire

Schematic:

Here is an updated schematic of the AVR circuit showing the potentiometer connected to ADC4 (pin 27).

Wifi Radio User Interface Schematic
click to enlarge

Firmware:

The AVR firmware has been significantly expanded, slightly reworked and cleaned up in some areas.

The most important changes are:

  • The addition of a serial transmit function so the AVR can talk to the router (based on the uart_putchar function)
  • New code supporting the analog to digital converter (ADC) which reads the value of a potentiometer connected to ADC4.
  • A new Timer1 overflow interrupt has been added, which occurs roughly every 0.5 seconds.  The interrupt service routine (ISR) checks the position of the tuner control, and if it has changed, sends the value to the router.  The ISR is towards the top of the file, see the SIGNAL (TIMER1_OVF_vect) section.

The ADC range of the ATmega is 0 – 1024 for an input voltage from 0 to 5V.  The AVR sends serial data in the format “Tuner: Value” back to the router when the tuner position changes by more than ADC_SENS counts (default is 5).  The AVR waits for an “AVR Start!” command from the router before sending any data, this avoids filling up the serial receive buffer on the router before it’s ready to start processing data.  An important consequence of this is that the AVR must be reset before running the control script on the router.

You can download the source code and compiled .hex file here.  Flash it to the AVR using any compatible ISP programmer and you should be good to go.  The source is commented fairly well so if you’re interested in learning how the interface works, take a look.  You will need a copy of the ATmega168 datasheet to understand the register names and other architecture-specific parts of the code.  Feel free to post in the comments with any questions.

Modifying the circuit:

This part is pretty simple – just wire the potentiometer as shown in the schematic.  Most potentiometers have three terminals.  The left terminal goes to ground, the right one to +5V, and the middle terminal to ADC4 on the AVR (pin 27).

Tuner control on breadboard

Tweaks to the OpenWrt configuration:

To make bidirectional communication with the AVR work, we have to change a couple config files on the router and disable some services that would otherwise get in the way.

/etc/config/network

The first change is to modify the /etc/config/network file so that we can always telnet or ssh into the router on a LAN port using the IP 192.168.1.1.  The ability to access the router via ethernet is helpful in case we screw something up and lose the wireless connection or the router loses it’s IP address, etc.

Modify the LAN section of /etc/config/network to look like this (changes in bold):

#### LAN configuration
config interface lan
#option type     bridge
option ifname    "eth0.0"
option proto    static
option ipaddr    192.168.1.1
option netmask    255.255.255.0

Save changes, restart the router, and connect an ethernet crossover cable (straight cable might work on some computers) to the router.  Configure your desktop/laptop computer with a static IP, like 192.168.1.185.  Try to open a telnet connection (or ssh if you have set a password on the router) and see if you can log in.  If not, don’t continue with the next steps until you can get this working.

/etc/inittab

We previously used the router’s serial port to get a login shell.  Now that we’re trying to receive data from the AVR on the same serial port, we need to disable the login shell or it will capture the data before we can get to it.

Edit /etc/inittab to look like this (changes in bold):

::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K stop
#tts/0::askfirst:/bin/ash --login
#ttyS0::askfirst:/bin/ash --login
tty1::askfirst:/bin/ash --login

/etc/sysctl.conf

Sysrq is a fascinating and very low level debugging feature of the Linux kernel.  It can be used to perform troubleshooting operations and reboot the system.  Usually it is invoked with a magic key combination on a desktop computer, but in this case I found that it is easy to accidentally trip over the serial port when using an AVR.  (The “break” RS-232 code triggers Sysrq, this probably has something to do with it.)

Fortunately, it’s easy to disable by editing the /etc/sysctl.conf file and adding these lines:

# Disables the magic SysRq key
kernel.sysrq = 0

Reboot the router to apply the changes.  Now we can get on with the good stuff!

Shell scripting magic:

The real action happens on the router, where a shell script waits for input from the router and changes the station accordingly.

This script is called interface.sh and can be downloaded to the router using wget as shown:

root@OpenWrt:~# cd ~
root@OpenWrt:~# wget http://mightyohm.com/files/wifiradio/interface.sh
...
root@OpenWrt:~# chmod ugo+x interface.sh

The interface script calls an updated version of the display script from part 7, called display2.sh:

root@OpenWrt:~# wget http://mightyohm.com/files/wifiradio/display2.sh
...
root@OpenWrt:~# chmod ugo+x display2.sh

Once both scripts are downloaded, executable and located in /root you can launch interface.sh as follows:

root@OpenWrt:~# ./interface.sh
volume: 60%   repeat: on    random: off
volume: 60%   repeat: on    random: off
adding: http://relay3.slayradio.org:8000/
adding: http://scfire-dtc-aa01.stream.aol.com:80/stream/1046
adding: http://208.101.28.234:8004

… more stations here …

Tuner Position:  0
New station...
http://relay3.slayradio.org:8000/
[playing] #1/10   0:00/0:00 (100%)
volume: 60%   repeat: on    random: off

The interface script adds ten presets to the router, shows the playlist, and then waits for valid tuner data from the AVR.  Once it receives a “Tuner: value” line (which should occur shortly after the AVR receives a go signal from the script), the script prints the received tuner positon and changes to the requested station.  It will then wait for new tuner data from the AVR and change the station when necessary.

As you can see in the video, this works very well.  Over a fast Wi-Fi connection, the time to change stations is almost instantaneous – very satisfying!

That’s it for part eight.  In part nine, I’ll add some finishing touches to the router configuration and start talking about enclosures.  Stay tuned!

Update: There is a new Wifi Radio Discussion Forum, hop over there to ask questions about the project or see what other people are working on!  (4/12/09)

Update 2: Part nine is now available.

69 thoughts on “Building a Wifi Radio – Part 8, Adding a Tuning Control”

  1. Have been using the radio quite a bit, still looking for replacement knobs for the antique radio chassis I put it in. I just found the free MPoD app for the ipod that works perfectly for MPD allowing me to control stations, play songs from the usb drive, adjust volume etc. Its like having a remote controlled jukebox. Thanks for puting this project together.

  2. This is exactly what I’v been looking for!
    I have several old wooden antique radio’s and my intention was originally to get them working someday replacing the tubes and capacitors. Then I thought a streaming radio in an antique chassis would be soooo cool.
    perhaps when I get this completed I will post photos of the project.

    Thanks

  3. Hey guys – I created a forum for this project over here: http://mightyohm.com/forum/viewforum.php?f=2

    I am hoping that the new forums help to facilitate better discussion than the comments section on the blog. They should at least help keep the crosstalk interference from multiple discussions down.

    Sorry it took so long, I should have set forums up when I originally started posting this stuff. Check them out and let me know what you think.

    😎

  4. Thanks for that! After looking at it i managed to get a WL520GU for around £40 which isn’t too bad!

    Were trying to find the cheapest way of getting our university radio station into the halls of residence! Theres 7 halls altogether so were trying to find the cheapest way! This seems like the perfect idea!

  5. Scott, take a look at the new La Fonera 2.0.
    It will support USb soundcards and 3G sicks out of the box.
    And it runs OpenWRT.
    I’ll cost 50 Euros. I don’t know of any other router with USB
    that is cheaper than that.
    I paid 51 Euros for my WL520GU.

  6. Thanks for a pretty amazing blog here! Great use 🙂

    Two things.

    A) Do you know of any cheaper routers that would work the same? Couldn’t see any.. Its around £55 just for the router over in England! 🙁

    B) When’s part 9 about? Im looking forward to it 😛

    C) Whats your opinion on getting a 3G modem into it aswell? The ideas work in my head.. I’m sure you can see where im going with that!

  7. 22bsti, as you might have noticed, I’ve posted a simple solution to use
    the EZsetup button as a very simple user interface.
    We have only 4 gpio’s available on the board:
    Power LED, wifi LED, EZsetup button and reset button.
    All others are either dedicated to the hub or not routed.
    Shurely this would be enough for back/forth and volume up/down,
    but not for an LCD. You could use an I2C or SPI IO expander, but
    these things are more expensive than a microcontroller, and require
    a lot of work for the kernel driver. In this case, Jeff’s solution is much
    easier.
    Nevertheless, I want to convert an old tube radio to a web radio.
    And I want to use the original dial to select the stations.
    Therefore I have to read in a potentiometer. I could use a microcontroller,
    as I have lots of the lying around, and know how to write the software,
    but I have the ambition to use only one gpio for this.
    It is possible, but would require to write e very special and timing critical
    kernel driver.
    If also have some other user interfaces in mind.
    If you want, let’s work together.
    But I propose that we use a more comfortable form of communication.
    A forum would be fine.

  8. I have been following this for awhile and it seems to me that it would be less work to just use the GPIO’s on the board and have them make mpd change stations and increase/decrease volume. That is the route I will end up going.

  9. Lordxtra, maybe it’s easier for you to wait for the new fonera 2.0 router.
    It already contains a mp3 player and will cost only 50 Euros.
    But nevertheless, also a WL520GU will work.
    I as well need a configuration that will work as wifi or ethernet client.
    I’ll try it soon and post the files here.

  10. Well you guys are way beyond me…but can anybody do this type of thing for us (small communuity station in spain( where we can have an ambedded stream receiver that connects to the internet via a standard rj45 as opposed to wireless. This would really let us expand as we exploit using the smallest power possible to remain legal and could add some additional transmitter stations if we could just receive the inet stream.

    Maybe some of you could offer a solution.

    Thx and RGZ from Spain

    LX

  11. Some additions:
    Mpd uses by default the fastest sample rate converter. This produces audible
    artefakts. The slower ones give much better sound quality.
    Nevertheless, I still hear some loud clicks here and there.
    This happens only on the WL520GU, not on a NSLU2.
    I don’t know if this comes from mpd, from the USB audio driver or from
    the kernel itself.

  12. Cyk – Thanks for the tip. I know that not all USB-audio adapters are alike. Some won’t work at all!

    Tuven – Thanks for measuring the current consumption, something I have been meaning to do for a while now. That is considerably less than the 2A rating on the wall wart. Very encouraging for portable apps.

  13. Hello

    I have been playing whit solarpanels to get the Asus 520gu running in remote places, so i have been measure a lot,

    And my measurements are following:

    ASUS 520GU:

    min 290mAh=1.5w/ max 390mAh=2w @5.2v,

    The min value is when the router is only connected to the main router wireless,
    The max are when one client is attached wireless and downloading in full speed.

    But your values may be different.

  14. One tip:

    If you hear clicks and sudden dropouts in the audio output,
    open /etc/mpd.conf and change the sample rate of /dev/sound/dsp
    from 44100:16:2 to 48000:16:2.
    It solved my problems.


    Cyk

  15. The 1-Button internet radio player:

    I assume that you already have flashed Jeff’s version of openwrt and the packages
    he described (mpd, usb audio) and that you have a working internet connection and
    USB sound output.
    If you want a very simple user interface, without modifying the router hardware,
    then put this script into /etc/hotplug.d/button (vi /etc/hotplug.d/button):

    #!/bin/sh
    case “$BUTTON” in
    ses)
    case “$ACTION” in
    released)
    if [ “$SEEN” = “0” ]
    then
    /usr/bin/mpc next
    exit 1
    fi
    if [ “$SEEN” = “1” ]
    then
    /usr/bin/mpc volume -10
    exit 2
    fi
    /usr/bin/mpc volume +10
    esac
    esac

    Give it a name of your choice (doesn’t matter) and don’t forget to make it executable
    (chmod 655 yourfile). If the subdirectory button doesn’t exist, create it.
    (mkdir button)

    What it does:
    When you press the red button labeled “EZSetup” at the back of the router once for
    shorter than one second, it will switch to the next stream in the playlist.
    Whan you press it longer than one, but shorter than 2 seconds, it will decrease the
    volume. Whan you press it for longer than 2 seconds, it will increase the volume.
    This is not very comfortable, but it works.

    I’ve modified the start script of mpd a little bit, so it loads the playlist at system start:
    (it’s name is /etc/init.d/mpd)

    #!/bin/sh /etc/rc.common
    # Copyright (C) 2007 OpenWrt.org
    #logger $1 $2
    START=93

    start() {
    #create mpd directories
    md=`grep music_directory /etc/mpd.conf | cut -d “\”” -f 2 | sed “s/~/\/root/g”`
    if [ ! -d $md ]; then
    mkdir -p $md
    fi
    pld=`grep playlist_directory /etc/mpd.conf | cut -d “\”” -f 2 | sed “s/~/\/root/g”`
    if [ ! -d $pld ]; then
    mkdir -p $pld
    fi
    #create mpd db
    /usr/bin/mpd –stdout –create-db

    #optional export for mpc
    #export MPD_HOST=127.0.0.1

    #start mpd
    /usr/bin/mpd

    #load playlist and start to play
    mpc load defaultlist
    /usr/bin/mpc volume 40
    #put above your favorite startup volume
    /usr/bin/mpc play 1
    /usr/bin/mpc repeat
    }

    stop() {
    killall mpd
    }

    Now add your favorite streams to the playlist:
    mpc add http://yourradio.com/stream/:8080

    And don’t forget to save the playlist:
    mpc save defaultlist

    If mpc complains that the list already exists try:
    mpc rm defaultlist
    mpc save defaultlist

    Now restart your router.
    It should then start to play the first entry in the playlist.
    After that, you can use the button to select the music and
    volume that fits your mood.

    Have fun!

  16. Hi folks,

    is there a free and reliable alternative to commercial webradio link
    collectors like vtuner?
    Reliable means that they don’t change their format/layout every month.

    To Zexston:
    The usual way is to install a UPnP media server on your pc, or use an external hard disk
    with network connection that has an UPnP server allready installed. (A lot of NAS devices have).
    Then we’ll have to figure out how to browse/open the media files on the router.
    Does anybody know?
    Is there a sort of command line browser for UPnP shared media?
    Something like smbclient for smb?
    —-
    Cyk

  17. Have a look at icecast. I have it running on my router and in conjunction with mpd can stream and play music from a PC.

  18. Thanks, but I’m not interested in it playing MP3s from storage media, rather from my MAC or PC on the network, and maybe from a future Linux MCE machine.

    Where would I start? Maybe there is another daemon and client that I could instal in Linux. Maybe I need a server app to run on the remote machine? I don’t know linux at all, I’m a uC guy.

  19. Some have recommended the more expensive asus router, because it has two USB 2.0 ports. Then you can have the audio device and some storage.

  20. This is exactly the type of project I’ve been looking for! Low cost, practical, and lets me get my feet wet with linux embedded.

    One question: Is it possible/How hard would it be to double this project as a network MP3 player?

    That would be AWSOME! I’m going to use a BasicX LCDX as I have one lying around for the uC and LCD, plus I have a 4×4 keyboard for it and know how to program it.

  21. Hi,

    I am a big fan of AVR micro controllers (I built a robot based on a mega128). Recently I succeeded streaming a webcam using an NSLU2 and Openwrt (that’s fun to be able to see my garden from my office).

    Your project is really interesting, and the best part (the most difficult one to me), you made a tutorial with it!

    Congratulations !!!

  22. Thanks. Must say this has been a super-fun project so far.

    I’m trying to get the whole works running of some rechargeable batteries (think French radio in my garden in the UK) and considered using the on-board 3.3v reg for everything. I noticed, however, that power to the USB port is coming straight from the wall-wart. Can’t decide if I should cut the trace and re-route the on-board 3.3v or my own 5v switching regulator. Anyone know if the audio adapter will run off 3.3?

  23. Hi All,

    Not sure if it’s a problem on my end… The links to the shell scripts don’t appear to work. They redirect to the first page of the tutorial. Being much stronger on the electronics front than with linuxiness, having those examples would be really useful. Anyone else having trouble getting at them?

  24. I got some individually shielded RJ45 jacks from Molex today, so I think I’m going to go ahead with removing the left-most 4 ports and the coupling transformers. Wish me luck!

Leave a Reply to CykCancel reply