TEA5767 Philips Programmable Low-power FM Stereo Radio Module

To say the least, I was very impressed with the TEA5767 FM radio chip.

The TEA5767 was the first radio I build and I absolutely love it.

I made all of the components their own separate modules so I could switch them out from time to time when I'm testing other things. For instance, when I get the TA7642 AM radio chip working, I'll be able to add it to the collection and be able to use the same 3.5mm jack, LM386 amplifier, etc.

The only thing I didn't like about this chip is it didn't come with holes to solder header pins into. So I ended up soldering it directly to a PCB.

 

All of the components minus the latest addition of the 5 button station presets and EEPROM

3.5mm jack

0.96" 128x64 OLED Display

TEA5767 Front

TEA5767 Back

LM386 Audio Amplifier Front

LM386 Audio Amplifier Back

Scan Up/Down Buttons

Power/I2C Distribution

 

After spending a lot of time on the station presets board, I decided to start merging everything together into two main modals with hot glue. This marks the end of what I call the Beta FM Radio Project.

Getting the 24LC256 chip to work was by far the hardest thing on this whole project. I could easier read and write string data but writing the precise radio frequencies was a bit of a pain. First I had to convert the double values into long, then finally into a character array. Then I was able to write those values to a specific address onto the chip. Reading the values was another challenge. And converting the character array back into something useful took quite a bit of time. I'll attach the code I use.

I love the PCF8574 chip. It allows me to use I2C for many different things. As you can see below, I'm using the chip to control the 5 buttons but it only takes two wires on the Arduino.

In fact, I use the I2C protocol for communication between the 24LC256, the TEA5767, the 24LC256 EEPROM and the 0.96" Display. Very useful.

Latest addition, the 5 Button Station Preset Board

Merged Main Board with Arduino, Battery and Display

The TEA5767 FM Radio Chip and 3.5 Audio Jack

The LM386 Audio Amplifier

My next version of the project will include AM and I'm hoping to do it all on a single PCB that I etch myself.

Here is the Arduino code. It's very long...

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "PCF8574.h"
#include <string.h>

//I2C Devices
//0x38 PCF8574 8 bit IO Expander
//0x50 24LC256 256K EEPROM
//0x60 TEA5767 FM Radio IC
//0x3c SSD1306 Display

//PCD8574
PCF8574 PCF_38(0x38);
uint8_t NothingAddr = 255; //Chip Button Address of Nothing
uint8_t Button1Addr = 254; //Chip Button Address
uint8_t Button2Addr = 253; //Chip Button Address
uint8_t Button3Addr = 251; //Chip Button Address
uint8_t Button4Addr = 247; //Chip Button Address
uint8_t Button5Addr = 239; //Chip Button Address
int NumberofPassestoSet = 400; //Number of times through the loop before writing the current set of Freqs
int CurrentPasstoSet = 0;
double FreqtoChangeto = 0;

//EEPROM Variables
#define EEPROM_ADDR 0x50
double button1Freq = 103.52; //Initial freq before reading EEPROM
double button2Freq = 102.69; //Initial freq before reading EEPROM
double button3Freq = 103.52; //Initial freq before reading EEPROM
double button4Freq = 102.69; //Initial freq before reading EEPROM
double button5Freq = 103.52; //Initial freq before reading EEPROM

//Scann Button Variables
//Scan Up
#define Button_next 7
//Scan Down
#define Button_prev 8
int talktoTEA5767=0; //Current run throught int
int talktoTEA5767After=20; //How often to check for scan button press rather than the TEA5767

//Radio Variables
int b=0;
int c=0;
unsigned char search_mode=0;
unsigned char frequencyH=0;
unsigned char frequencyL=0;
unsigned int frequencyB;
double frequency=0;
double freq_available=0;

//LCD Variables
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

void setup() {
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3c);
display.display();
display.clearDisplay();

/// buttons
pinMode(Button_next, INPUT);
digitalWrite(Button_next, HIGH); //pull up resistor

pinMode(Button_prev, INPUT);
digitalWrite(Button_prev, HIGH); //pull up resistor

ReadFreqs();

frequency=button1Freq; //starting with programmed button1Freq
frequencyB=4*(frequency*1000000+225000)/32768; //calculating PLL word
frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;

delay(100);

//writing TEA5767
Wire.beginTransmission(0x60);
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0xB0);
Wire.write(0x10);
Wire.write(0x00);
Wire.endTransmission();

delay(100);
}

void loop()
{
//Set Button we are pressing using I2C
uint8_t ButtonValue = PCF_38.read8();
if (ButtonValue == Button1Addr)
{
CurrentPasstoSet++;
if (CurrentPasstoSet > NumberofPassestoSet)
{
button1Freq = frequency;
CurrentPasstoSet = 0;
WriteFreqs();
}
FreqtoChangeto = button1Freq;
}
else if (ButtonValue == Button2Addr)
{
CurrentPasstoSet++;
if (CurrentPasstoSet > NumberofPassestoSet)
{
button2Freq = frequency;
CurrentPasstoSet = 0;
WriteFreqs();
}
FreqtoChangeto = button2Freq;
}
else if (ButtonValue == Button3Addr)
{
CurrentPasstoSet++;
if (CurrentPasstoSet > NumberofPassestoSet)
{
button3Freq = frequency;
CurrentPasstoSet = 0;
WriteFreqs();
}
FreqtoChangeto = button3Freq;
}
else if (ButtonValue == Button4Addr)
{
CurrentPasstoSet++;
if (CurrentPasstoSet > NumberofPassestoSet)
{
button4Freq = frequency;
CurrentPasstoSet = 0;
WriteFreqs();
}
FreqtoChangeto = button4Freq;
}
else if (ButtonValue == Button5Addr)
{
CurrentPasstoSet++;
if (CurrentPasstoSet > NumberofPassestoSet)
{
button5Freq = frequency;
CurrentPasstoSet = 0;
WriteFreqs();
}
FreqtoChangeto = button5Freq;
}
else if (ButtonValue == NothingAddr)
{
CurrentPasstoSet = 0;
if (FreqtoChangeto != 0)
{
frequency = FreqtoChangeto;
FreqtoChangeto = 0;
frequencyB=4*(frequency*1000000+225000)/32768+1;

frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;

Wire.beginTransmission(0x60);
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0xB0);
Wire.write(0x1F);
Wire.write(0x00);
Wire.endTransmission();
}
}

//Talk to TEA5767 only after the talktoTEA5767After has been reached. Makes Scan Buttons more responsive
if (talktoTEA5767 > talktoTEA5767After)
{
talktoTEA5767 = 0;
unsigned char buffer[5];

Wire.requestFrom(0x60,5); //reading TEA5767

if (Wire.available())
{
for (int i=0; i<5; i++)
{
buffer[i]= Wire.read();
}
}

freq_available=(((buffer[0]&0x3F)<<8)+buffer[1])*32768/4-225000;

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.print("FM ");
display.print((freq_available/1000000));

frequencyH=((buffer[0]&0x3F));

frequencyL=buffer[1];

if (search_mode)
{
if(buffer[0]&0x80) search_mode=0;
}

if (search_mode==1)
{
display.println(" SCAN");
}
else
{
display.println(" ");
}

display.print("Level: ");
display.print((buffer[3]>>4));
display.print("/16 ");

if (buffer[2]&0x80)
{
display.println("STEREO ");
}
else
{
display.println("MONO ");
}

display.display();
}
talktoTEA5767++;

//////////// button_next//////////
if (!digitalRead(Button_next)&&!b) {

frequency=(freq_available/1000000)+0.05;

frequencyB=4*(frequency*1000000+225000)/32768+1;

frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;

Wire.beginTransmission(0x60);
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0xB0);
Wire.write(0x1F);
Wire.write(0x00);
Wire.endTransmission();

b=100;

};

if (!digitalRead(Button_next)&&b==1) {

///scannnn UP

search_mode=1;

Wire.beginTransmission(0x60);
Wire.write(frequencyH+0x40);
Wire.write(frequencyL);
Wire.write(0xD0);
Wire.write(0x1F);
Wire.write(0x00);
Wire.endTransmission();

b=100;

};

if (!b==0) b--;

//////////// button_prev//////////
if (!digitalRead(Button_prev)&&!c) {

frequency=(freq_available/1000000)-0.05;

frequencyB=4*(frequency*1000000+225000)/32768+1;

frequencyH=frequencyB>>8;
frequencyL=frequencyB&0XFF;

Wire.beginTransmission(0x60);
Wire.write(frequencyH);
Wire.write(frequencyL);
Wire.write(0xB0);
Wire.write(0x1F);
Wire.write(0x00);
Wire.endTransmission();

c=100;
};

if (!digitalRead(Button_prev)&&c==1) {

///scannnn DOWN

search_mode=1;

Wire.beginTransmission(0x60);
Wire.write(frequencyH+0x40);
Wire.write(frequencyL);
Wire.write(0x50);
Wire.write(0x1F);
Wire.write(0x00);
Wire.endTransmission();

c=100;
};

if (!c==0) c--;
}

void WriteFreqs()
{
//Just clears the area we are using in the EEPROM for our Freq data
char clearme[] = {" "};
writeEEPROM(EEPROM_ADDR,0,clearme);

float d1a = (float)button1Freq;
char d1b[10];
dtostrf(d1a, 4, 2, d1b);
writeEEPROM(EEPROM_ADDR,0,d1b);

float d2a = (float)button2Freq;
char d2b[10];
dtostrf(d2a, 4, 2, d2b);
writeEEPROM(EEPROM_ADDR,10,d2b);

float d3a = (float)button3Freq;
char d3b[10];
dtostrf(d3a, 4, 2, d3b);
writeEEPROM(EEPROM_ADDR,20,d3b);

float d4a = (float)button4Freq;
char d4b[10];
dtostrf(d4a, 4, 2, d4b);
writeEEPROM(EEPROM_ADDR,30,d4b);

float d5a = (float)button5Freq;
char d5b[10];
dtostrf(d5a, 4, 2, d5b);
writeEEPROM(EEPROM_ADDR,40,d5b);

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("SAVED");
display.display();
delay(1000);
}

void ReadFreqs()
{
unsigned char a1[10];
readEEPROM(EEPROM_ADDR, 0, a1, 10);
char a2[10];
memcpy(a2,a1, 6);
button1Freq = atof(a2);

unsigned char b1[10];
readEEPROM(EEPROM_ADDR, 10, b1, 10);
char b2[10];
memcpy(b2,b1, 6);
button2Freq = atof(b2);

unsigned char c1[10];
readEEPROM(EEPROM_ADDR, 20, c1, 10);
char c2[10];
memcpy(c2,c1, 6);
button3Freq = atof(c2);

unsigned char d1[10];
readEEPROM(EEPROM_ADDR, 30, d1, 10);
char d2[10];
memcpy(d2,d1, 6);
button4Freq = atof(d2);

unsigned char e1[10];
readEEPROM(EEPROM_ADDR, 40, e1, 10);
char e2[10];
memcpy(e2,e1, 6);
button5Freq = atof(e2);
}

void readEEPROM(int deviceaddress, unsigned int eeaddress, unsigned char* data, unsigned int num_chars)
{
unsigned char i=0;
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress,num_chars);
while(Wire.available()) data[i++] = Wire.read();
}

void writeEEPROM(int deviceaddress, unsigned int eeaddress, char* data)
{
// Uses Page Write for 24LC256
// Allows for 64 byte page boundary
// Splits string into max 16 byte writes
unsigned char i=0, counter=0;
unsigned int address;
unsigned int page_space;
unsigned int page=0;
unsigned int num_writes;
unsigned int data_len=0;
unsigned char first_write_size;
unsigned char last_write_size;
unsigned char write_size;

// Calculate length of data
do{ data_len++; } while(data[data_len]);

// Calculate space available in first page
page_space = int(((eeaddress/64) + 1)*64)-eeaddress;

// Calculate first write size
if (page_space>16){
first_write_size=page_space-((page_space/16)*16);
if (first_write_size==0) first_write_size=16;
}
else
first_write_size=page_space;

// calculate size of last write
if (data_len>first_write_size)
last_write_size = (data_len-first_write_size)%16;

// Calculate how many writes we need
if (data_len>first_write_size)
num_writes = ((data_len-first_write_size)/16)+2;
else
num_writes = 1;

i=0;
address=eeaddress;
for(page=0;page<num_writes;page++)
{
if(page==0) write_size=first_write_size;
else if(page==(num_writes-1)) write_size=last_write_size;
else write_size=16;

Wire.beginTransmission(deviceaddress);
Wire.write((int)((address) >> 8)); // MSB
Wire.write((int)((address) & 0xFF)); // LSB
counter=0;
do{
Wire.write((byte) data[i]);
i++;
counter++;
} while((data[i]) && (counter<write_size));
Wire.endTransmission();
address+=write_size; // Increment address for next write

delay(6); // needs 5ms for page write
}
}