Thursday, August 21, 2014

TEA5767N FM Philips Library for Arduino explained

 Gostaria de ver este post em português?

Motivation


TEA 5767 FM radio module
In this post I´ll explain the library I wrote  for TEA5767 FM module.

In my first experiments with TEA5767 in a breadboard I used the libraries from Simon Monk and Andy Karpov. Their code helped me a lot to understand how to control the TEA5767.

Then, to make a more complete application, I felt the need to organize my code a little bit and, with the help of the TEA5767 Application Note, I encapsulated the TEA5767 commands in several convenient methods.

Data Structure

To send or receive TEA5767 commands there are always five bytes involved. Even if you need to send a single bit, all five bytes must be resent. So I kept transmission and reception data bytes as instance attributes of the object, as seen below.

The transmission bytes are initialized in the private method initializeTransmissionData() with the most common options and is called in the constructor. The comments were removed to make the reading more pleasant.

Now I can change only one or two bits and send all the five bytes with the values they had and were not affected by the change For example, a method to turn the radio mute on (or turn the sound off), has to manipulate only one bit of the five transmission bytes before resend them:

And to set the sound on again:

And most of the methods are like this, switching bits on or off.
And as said earlier, there are also five bytes that can be read from the TEA5767 module. They are stored in the reception_data array and depending on the operation there is the need to update the transmission_data array too so they can be in sync. Here is an example:

Note: Wire is an Arduino library that deals with I2C communication.

Algorithms

Reading the TEA5767 application note, you´ll find formulas and algorithms to set and read the station frequency. For example, to select a station frequency it´s necessary first calculate the optimal hi / lo injection which consists in select the (frequency - delta) and (frequency + delta), and choose the one that offers a better signal level. Delta is a constant that represents 450 kHz.

And with this hi / lo injection value, the code can call the formula that calculates the 14-bit PLL that represents the station selected.

Note that before the data are sent, they are stored in transmission_data so that it keeps always up to date.

Searching stations

Before actually starting a search, there are a few things that you have to set up: if  the search is up or down, the signal level a station must have to stop the search, and is recommended to mute the radio so that users don't hear that station change annoying sound.

To choose up or down search direction is also just change one bit in the transmission_data array.

There are three search stop levels: lo, mid and high.

To set one of these levels is a matter of changing two bits in the transmission_data.

And to effectively start searching, after setting direction and level, you just call the searchNext() method.
What this method does is
. Add or subtract 100 kHz from current station (so search doesn´t find current station again), depending on search direction;
. Sets the search bit;
. Waits for radio search;
. When search is ready, checks whether band limit has been reached or not;
. Update transmission_data array with the new selected frequency;
. Turn off the search bit;
. Returns band limit status.

Search_next() does not mute before search and is useful for debug purpose. To mute before search you can call mute() method yourself or you can use the convenient searchNextMuting() method.

This only wraps searchNext() method with calls to mute on and off and also returns is band limit has been reached.

Two other useful search methods are startsSearchFromBeginning() and startsSearchFromEnd(). What they do is set the direction and start frequency before call searchNext().
I used these methods in a project to scan and record all avalilable stations. That project, as I said, will be my next post here.

And as you could expect there are the muting versions.

Conclusion

Thanks to the ability to write this library in C++, an object oriented language, I could write more cohesive methods that are easy to use by other client software. This way, using this library you can build your system step-by-step as you try the module features. Separating methods in public and private members also helps to understand how the library is supposed to be used.

Another good practice you can find in this library is the careful choice of the variables and methods names. They reveal the intention, what´s the variable role and what the methods do.

I show how I used this library with Arduino, TEA5767 FM module and the LCD Keypad Shield to build a complete radio application.

Thank you!

Thank you for reading!
Please let me know if this library somehow helped you in your projects.
To follow my updates to this library and my other projects:

7 comments:

  1. Am I the only one who was reading the example file and started singing to myself:

    You turn the right sound on,
    You turn the right sound off,
    You turn the right sound on,
    And you shake it all about,

    You do the hokey pokey
    and you turn yourself around
    That what it's all about.

    ReplyDelete
    Replies
    1. BTW, that was NOT meant in a disparaging way (it was just funny.) I do like the library and definitely plan to use it. I may get typer's cramp with the long function names but they definitely are formatted well and easy to follow.

      Delete
    2. Mike, first of all, thank you so much for your time reading my post. And yes, the way you put it, the example sounds really funny! LOL! But.. it was just a quick and dirty way to test the library. You can find another and more useful example of the library in my other post: http://mr0ger-arduino.blogspot.com.br/2015/01/complete-fm-radio-using-arduino-tea5767.html.

      About the long function names, I´d like to share the responsibility with the guys from Spring (it´s a Java framework). I like this practice because it brings clarity about the responsibility the function, and therefore, helps to keep the function cohesive. But you´re absolutely right! It would be harmful trying to type all these function names and I suggest that you copy and paste these function names from the header file (TEA5767N.h) to avoid typer´s cramp or other types of injuries.

      Again, thank you for your time and tell me if you need anything with this library.

      Best regards!

      Delete
  2. Did you try the App Note's algorithm for determining whether or not a search stop point is a valid station or not? For me it doesn't seem to work - I get plenty of noise channels but no broadcast channels. Most strange!

    ReplyDelete
  3. Hi, I was wondering if you would please be able to help me getting this code working. Each time I try to include the TEA5767N.h library, I receive this error.

    /Users/ethanlankshear/Documents/Arduino/libraries/TEA5767-master/TEA5767N.cpp: In member function 'TEA5767N::transmitData()':
    /Users/ethanlankshear/Documents/Arduino/libraries/TEA5767-master/TEA5767N.cpp:92:34: warning: iteration 5 invokes undefined behavior [-Waggressive-loop-optimizations]
    Wire.write(transmission_data[i]);
    ^
    /Users/ethanlankshear/Documents/Arduino/libraries/TEA5767-master/TEA5767N.cpp:91:2: note: containing loop
    for (int i=0 ; i<6 ; i++) {
    ^

    Any suggestions for fixing this?
    Thank you.

    ReplyDelete
  4. Hello,i am using te same sketch and get the same trooble with TEA5767N.h .Can and will you tell me how you fixed it? Thanks,Jan.

    ReplyDelete