element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Personal Blogs
  • Community Hub
  • More
Personal Blogs
Michael Conners's Blog FM Radio on the Raspberry Pi
  • Blog
  • Documents
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: mconners
  • Date Created: 6 Feb 2016 2:24 PM Date Created
  • Views 2174 views
  • Likes 2 likes
  • Comments 8 comments
  • raspberry
  • radio
  • raspberry pi
  • ras pi
Related
Recommended

FM Radio on the Raspberry Pi

mconners
mconners
6 Feb 2016

In my never ending (it seems) quest to make my Pi talk to all of the devices I had talking to my Arduino, I have finally gotten around to one of the funner, yet more frustrating devices. Funner because it was challenging, frustrating because it was challenging. There was a lack of documentation on the device, the detailed programming manual was in Chinese, the register specs were limited, and it just didn't seem to work like I expected it to.

 

This device was the Parallax FM Radio Receiver Module (#27984) , from www.parallax.com. According to the documentation:

 

"The FM Radio Receiver Module uses an RDA5807SS FM stereo radio tuner chip, which provides an easy way for your microcontroller to receive local FM radio statons. Using the onboard antenna and headphone jack, you can easily create your own portable radio! "

 

I can't disagree with any of that, except for maybe the easy part, but it should be easy now that I have prepared this blog post!

 

I've seen a few other posts on this chip/module, but they have mostly taken from the perspective of the TEA5767, which is a mode that the RDS5807 emulates, but I wanted to control it natively.

 

A few prerequisites are required, you need to enable the I2C on your pi. You can do this by following the first 1/2 of a related post here: Enabling RTC on the Raspberry Pi 2

 

You can stop when you get to the part about i2cdetect, and return here.

 

Speaking of i2cdetect, when this device is connected properly, and I type

 

sudo i2cdetect -y 1

 

I find 3 i2c devices

 

image

 

at addresses 0x10, 0x11, and 0x60. This is part of what makes this device strange, and where the documentation starts to get a little fuzzy.

 

It seems like accessing the device at address 0x60 is how you perform the TEA5767 compatible commands, so this is the last I will mention it, I didn't find that in documentation, and I found no mention in the docs regarding TEA5767, it just seems to be data I've found here and there.

 

Address 0x10 seems to be an address where you write to the I2C device without specifying a register address, the device starts to write the bytes to the 16 bit registers starting at register 0x02, high byte first, then it increments the register counter internally and writes to the next register, and it does this until you have finished writing. This turned out to be a little challenging, but I was able to get it done. I'll explain it when I get to the code.

 

Address 0x11 purports to behave like a regular I2C address in that it expects a register number to be included in the command, I was not able to successfully write to the device in this manner, but I was able to successfully read from the device registers, so that's something.

 

 

OK. On to the code, this is just a simple driver with a rudimentary interface, I'm not a big bells and whistles guy, I just wanted to write the methods to access the device and exercise it. I didn't take advantage of the interrupt capabilities of the module, they are there, it should be a trivial exercise to take advantage of it.

 

Another prerequisite. You need wiringPi. The best place to get that is here Raspberry Pi | Wiring | Download & Install | Wiring Pi . That should get you all set up, then you can return here.

 

This code was pretty much a port of an arduino sketch I had written. I renamed the setup() function to main(), and added a call to loop(). Replaced Serial.println() functions with printf() functions, and had to rewrite the individual functions that talked to the device registers. But other than that, it was much the same. I had isolated the register functions so it was trivial to replace those as I only had to change the code in 2 places, the read and the write.

unsigned int readRegister(int regAddr)
{
  return be16toh(wiringPiI2CReadReg16(statusFd,regAddr)); 
}

 

The readRegister()  method was pretty simple. I just called the wiringPiFunction wiringPiI2CReadReg16(), passing in the fd I got from opening the I2C device at address 0x11, along with the register number. I noticed that the results returned were reversed from what I expected. That is the low byte from the read was being stored in the upper byte and the high byte was being returned in the lower byte, so when I expected something like 0xA55A, I was instead getting 0x5AA5, so I used a system call be16toh from endian.h, to convert the data from big endian to host format. This accomplished what I needed.

 

 

void writeConfigRegisters()
{
  int index,ii=0;
  unsigned char tempRegisters[CONFIGREGLEN * 2];
  

  for(index = 0;index < CONFIGREGLEN;index++)
  {
   tempRegisters[ii++] = (configRegisters[index] >> 8) & 0xff;
   tempRegisters[ii++] = configRegisters[index] & 0xff;
  }
  write(deviceFd,tempRegisters,CONFIGREGLEN * 2);
 }

 

I handled writing the config registers as a block. This seemed to be how the device liked it. I maintain a copy of the state of the registers in an integer array named configRegisters, then I just write that out to the device, I first convert the integer array to an array of characters, then just using the write function, I write out the data all at once to the fd I got from opening the I2C device at address 0x10.

 

I mentioned the fd I got from the devices a couple of times. Here is an example of how I opened them using the wiringPi libraries.

 

#define CONFIGADDR 0x10
#define STATUSADDR 0x11
#define CONFIGREGLEN 5


int deviceFd;
int statusFd;

int main()
{
  deviceFd = openDevice(CONFIGADDR);
  statusFd = openDevice(STATUSADDR);
...
...
...
} 

int openDevice(int i2cAddress)
{
  int fd;
  if((fd = wiringPiI2CSetup(i2cAddress)) < 0)
  {
  printf("Error opening device at I2C Address %x\n",i2cAddress);
  exit(fd);
  }
  return fd;
}

 

Once they were opened I was able to use the file descriptors all over the program.

 

After that is was just a matter of bit twiddling to write to the registers and get the device in the state I wanted. My initial config registers looked like the following:

 

unsigned int configRegisters[] ={
  0xc001,0x0000,0x0400,0x86d3,0x4000};

 

I'll leave it up to the reader to decode, this was the document I used as a reference https://www.parallax.com/sites/default/files/downloads/27984-FM-Radio-Receiver-v1.0.pdf

the elements of the array correspond to registers 0x02-0x05 on the device. So as an example 0xc001 sets register 2 as follows

 

High Impedance - Normal Operation

Mute - Normal Operation

Mono - Stereo Mode

Bass Boost - Not Enabled

Power up - Enabled

 

an example of how I used the config registers is as follows

 

void powerOn()
{
  configRegisters[1] |= 0x10;
  configRegisters[0] |= 0x1;
  writeConfigRegisters();
  configRegisters[1] &= 0xffef;
}

 

and

 

void tuneToChannel(int frequency)
{
  frequency -= 870;
  configRegisters[1] |= 0x10;
  configRegisters[1] = (configRegisters[1] & 0x3f) | (frequency << 6);
  writeConfigRegisters();
  configRegisters[1] &= 0xffef;
  checkTuneComplete();
}

 

so I would change my local copy of the config registers, write them out to the device, and restore any of the bits I needed.

 

I have attached the code necessary so if you have this device and would like to learn more, feel free to download it and compile and run it.

 

To extract use:

tar xvzf radio.tgz

 

that should give you 2 files

radio.c and

radio.h

 

the compile command line is

gcc -Wall -o radio radio.c -lwiringPi

 

then run it with

 

./radio (if you have an issue, use sudo ./radio)

 

you can look in the loop() function for the commands, a few are

+ - Seek Up

- - Seek Down

r - reset tuning to inital station (103.7)

x - power off

o - power on

v - volume up

c - volume down

d - display register values

 

follow any of the commands with the enter key.

 

just look in the big ugly switch statement for the rest

 

There does seem to be a bit of a bug in the channel display after a seek, but if you hit d to dump the registers, it should show the proper tuning.

 

Hope you enjoy.

Attachments:
https://community.element14.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/00-00-00-03-24/radio.tgz
  • Sign in to reply

Top Comments

  • shabaz
    shabaz over 9 years ago +1
    Hi Mike, Thanks for making it look easy! It does seem a fun thing to try.. I might try this project sometime. I've used another NXP part in the past (TEF6600 series which is their automotive entertainment…
  • mconners
    mconners over 9 years ago in reply to shabaz +1
    Thanks for the comments, shabaz It was pretty easy this time. When I had originally written this for the arduino it was much harder. I found some basic stamp code from parallax, which I was completely…
  • shabaz
    shabaz over 9 years ago in reply to mconners +1
    This is an excellent set of code for someone to use straight away. Regarding further ideas, it could be a fun thing for someone to try to create a GUI for your project on the 'Pi or BBB to extend this…
  • mconners
    mconners over 9 years ago in reply to packetgeek

    Yeah, I've found a couple of data sheets here and there. I had stumbled across your pages, and had seen you had gotten in working in TEA5767 mode. I had wanted to do all native.

     

    I know you had mentioned doing the native mode stuff, but I only saw the TEA stuff posted.

     

    It was fun to play with. Can't help on the RDS decoder.

     

    Mike

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • packetgeek
    packetgeek over 9 years ago

    I never got around to writing a decent RDS decoder.  Anyone have one?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • packetgeek
    packetgeek over 9 years ago in reply to mconners

    Michael,

     

    Yep.  Had a lot of fun with the FM receivers.  The RDA5807xx does come with TEA5767 emulation.  RDA even fixed the issue with the TEA5767 (when used with an external crystal, search doesn't work on the TEA5767 but does on the RDA5807xx in TEA5767 emulation mode).

     

    I wrote code for both of the above breakout boards (all three modes on the RDA5807) as well as for the SI4703.  I also rewrote some of the code to avoid use of the WiringPi library.  This allowed me to easily port the code to run on the CubieTruck (so far, only for the TEA5767 mode on the RDA5707SP).

     

    Various notes are in: Short Attention Span Geekery

     

    Misc. bits of code are at: https://github.com/packetgeek?tab=repositories

     

    Have you found the spec sheets for your chips?  I have copies around here somewhere.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • mconners
    mconners over 9 years ago in reply to shabaz

    Yeah, that's kind of what I was thinking. The device control is fairly complete and modular. Get a gui in place of the switch statement, take out some of the debug print statements, add some callbacks and you're good to go.

     

    Mike

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • shabaz
    shabaz over 9 years ago in reply to mconners

    This is an excellent set of code for someone to use straight away.

    Regarding further ideas, it could be a fun thing for someone to try to create a GUI for your project on the 'Pi or BBB to extend this project even further.

    There is a BBB Internet Radio project by the EAGLE team, they used some Python based GUI method (can't recall what it was called).

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube