RDA5807M FM Radio library with RDS.
Dependents: RDA5807M-FM-Radio EFM32 RDA5807M RDS Radio
Example program here:
https://developer.mbed.org/users/star297/code/RDA5807M-FM-Radio/
RDA5807M.cpp
- Committer:
- star297
- Date:
- 2015-06-19
- Revision:
- 4:3e7968bd455d
- Parent:
- 3:bdd691977de4
File content as of revision 4:3e7968bd455d:
#include "RDA5807M.h" unsigned int RDA5807M_WriteRegDef[6] ={0xC004,0x0000,0x0100,0x84D4,0x4000,0x0000}; // initial data RDA5807M::RDA5807M(PinName sda, PinName scl) : i2c(sda, scl) { i2c.frequency(400000); Init(); } RDA5807M::~RDA5807M() { } void RDA5807M::WriteAll() { char buf[30]; int i,x = 0; for(i=0; i<12; i=i+2){ buf[i] = RDA5807M_WriteReg[x] >> 8; x++;} x = 0; for(i=1; i<13; i=i+2){ buf[i] = RDA5807M_WriteReg[x] & 0xFF; x++;} i2c.write(0x20, buf, 14); } void RDA5807M::Init(){ int i; for(i=0; i<6; i++){ RDA5807M_WriteReg[i] = RDA5807M_WriteRegDef[i]; WriteAll(); } } void RDA5807M::PowerOn(){ RDA5807M_WriteReg[1] = RDA5807M_WriteReg[1] | RDA_TUNE_ON; RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_POWER; WriteAll(); power=1; RDA5807M_WriteReg[1] = RDA5807M_WriteReg[1] & 0xFFEF; //Disable tune after PowerOn operation } void RDA5807M::PowerOff(){ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] ^ RDA_POWER; WriteAll();power=0; } void RDA5807M::Reset(){ Init(); PowerOn(); RDSinit(); RDS(); Volume(InitialVolume); Frequency(DefaultFreq); // set default start frequency. } void RDA5807M::Volume(int vol){ if(vol > 15){ vol = 15; } if(vol < 0){ vol = 0; } RDA5807M_WriteReg[3] = (RDA5807M_WriteReg[3] & 0xFFF0)| vol; // Set New Volume volume=vol; WriteAll(); } void RDA5807M::BassBoost(){ if ((RDA5807M_WriteReg[0] & 0x1000)==0){ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_BASS_ON; bass=1; } else{ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_BASS_OFF; bass=0; } WriteAll(); } void RDA5807M::Mono(){ if ((RDA5807M_WriteReg[0] & 0x2000)==0){ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_MONO_ON; mono=1; } else{ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_MONO_OFF; mono=0; } WriteAll(); } void RDA5807M::Mute(){ if ((RDA5807M_WriteReg[0] & 0x8000)==0){ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | 0x8000; mute=0; } else{ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & 0x7FFF; mute=1; } WriteAll(); } void RDA5807M::Softmute(){ if ((RDA5807M_WriteReg[2] & 0x0200)==0){ RDA5807M_WriteReg[2] = RDA5807M_WriteReg[2] | 0x0200; softmute=1; } else{ RDA5807M_WriteReg[2] = RDA5807M_WriteReg[2] & 0xFDFF; softmute=0; } WriteAll(); } void RDA5807M::SoftBlend(){ if ((RDA5807M_WriteReg[6] & 0x0001)==0){ RDA5807M_WriteReg[6] = RDA5807M_WriteReg[6] | 0x0001; softblend=1; } else{ RDA5807M_WriteReg[6] = RDA5807M_WriteReg[6] & 0xFFFE; softblend=0; } WriteAll(); } void RDA5807M::AFC(){ if ((RDA5807M_WriteReg[2] & 0x0100)==0){ RDA5807M_WriteReg[2] = RDA5807M_WriteReg[2] | 0x0100; afc=1; } else{ RDA5807M_WriteReg[2] = RDA5807M_WriteReg[2] & 0xFEFE; afc=0; } WriteAll(); } void RDA5807M::SeekUp(){ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_SEEK_UP; // Set Seek Up WriteAll(); RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_SEEK_STOP; // Disable Seek } void RDA5807M::SeekDown(){ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_SEEK_DOWN; // Set Seek Down WriteAll(); RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_SEEK_STOP; // Disable Seek } void RDA5807M::Frequency(float Freq){ int Channel; Channel = ((Freq-StartingFreq)/0.1)+0.05; Channel = Channel & 0x03FF; RDA5807M_WriteReg[1] = Channel*64 + 0x10; // Channel + TUNE-Bit + Band=00(87-108) + Space=00(100kHz) WriteAll(); RDA5807M_WriteReg[1] = RDA5807M_WriteReg[1] & RDA_TUNE_OFF; } void RDA5807M::RDS(){ if ((RDA5807M_WriteReg[0] & RDA_RDS_ON)==0){ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_RDS_ON; rds=1; } else{ RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_RDS_OFF; rds=0; } WriteAll(); } void RDA5807M::Readregisters(){ int i; char rcv[12]; i2c.read(0x20, rcv,12); // read 12 bytes for reg 0x0A .. reg 0x0F for(i=0; i<6; i++){ RDA5807M_ReadReg[i] = ((rcv[i *2] << 8) | rcv [(i*2) +1] ); } block1 = RDA5807M_ReadReg[2]; block2 = RDA5807M_ReadReg[3]; block3 = RDA5807M_ReadReg[4]; block4 = RDA5807M_ReadReg[5]; rdsready = RDA5807M_ReadReg[0] & 0x8000; //if rdsready != 0 rds data are ready tuneok = RDA5807M_ReadReg[0] & 0x4000; //if tuneok != 0 seek/tune completed nochannel = RDA5807M_ReadReg[0] & 0x2000; //if nochannel != 0 no channel found rdssynchro = RDA5807M_ReadReg[0] & 0x1000; //if rdssynchro = 1000 rds decoder syncrhonized stereo = RDA5807M_ReadReg[0] & 0x0400; //if stereo = 0 station is mono else stereo freq = (((RDA5807M_ReadReg[0] & 0x03FF) * 100) + 87000); //return freq ex 102600KHz > 102.6MHz signal = RDA5807M_ReadReg[1] >> 10; //return signal strength rssi fmready = RDA5807M_ReadReg[1] & 0x0008; //if fmready = 8 > fm is ready fmstation = RDA5807M_ReadReg[1] & 0x0100; //if fmstation = 100 fm station is true rdsblockerror = RDA5807M_ReadReg[1] & 0x000C; //check for rds blocks errors //00= 0 errors,01= 1~2 errors requiring correction //10= 3~5 errors requiring correction //11= 6+ errors or error in checkword, correction not possible. } void RDA5807M::RDSinit() { strcpy(StationName, " "); strcpy(PSName, " "); strcpy(PSName1, " "); strcpy(PSName2, " "); memset(RDSText, '\0', sizeof(RDSText)); memset(RDSTxt, '\0', sizeof(RDSTxt)); lastTextIDX = 0; mins=0; sprintf(CTtime, "CT --:--"); } void RDA5807M::ProcessData() { Readregisters(); if (rdssynchro != 0x1000){ // reset all the RDS info. RDSinit(); return; } // analyzing Block 2 rdsGroupType = 0x0A | ((block2 & 0xF000) >> 8) | ((block2 & 0x0800) >> 11); rdsTP = (block2 & 0x0400); rdsPTY = (block2 & 0x0400); switch (rdsGroupType) { case 0x0A: case 0x0B: // The data received is part of the Service Station Name idx = 2 * (block2 & 0x0003); // new data is 2 chars from block 4 c1 = block4 >> 8; c2 = block4 & 0x00FF; // check that the data was received successfully twice // before sending the station name if ((PSName1[idx] == c1) && (PSName1[idx + 1] == c2)) { // retrieve the text a second time: store to _PSName2 PSName2[idx] = c1; PSName2[idx + 1] = c2; PSName2[8] = '\0'; if (strcmp(PSName1, PSName2) == 0) { // populate station name n=0; for(i=0;i<(8);i++){ // remove non-printable error ASCCi characters if(PSName2[i] > 31 && PSName2[i] < 127){ StationName[n] = PSName2[i]; n++; } } } } if ((PSName1[idx] != c1) || (PSName1[idx + 1] != c2)) { PSName1[idx] = c1; PSName1[idx + 1] = c2; PSName1[8] = '\0'; } break; case 0x2A: // RDS text textAB = (block2 & 0x0010); idx = 4 * (block2 & 0x000F); if (idx < lastTextIDX) { // The existing text might be complete because the index is starting at the beginning again. // Populate RDS text array. n=0; for(i=0;i<strlen(RDSTxt);i++){ if(RDSTxt[i] > 31 && RDSTxt[i] < 127){ // remove any non printable error charcters RDSText[n] = RDSTxt[i]; n++; } } } lastTextIDX = idx; if (textAB != lasttextAB) { // when this bit is toggled the whole buffer should be cleared. lasttextAB = textAB; memset(RDSTxt, 0, sizeof(RDSTxt)); memset(RDSText, '\0', sizeof(RDSText)); } if(rdsblockerror < 4){ // new data is 2 chars from block 3 RDSTxt[idx] = (block3 >> 8); idx++; RDSTxt[idx] = (block3 & 0x00FF); idx++; // new data is 2 chars from block 4 RDSTxt[idx] = (block4 >> 8); idx++; RDSTxt[idx] = (block4 & 0x00FF); idx++; } break; case 0x4A: // Clock time and date if(rdsblockerror <3){ // allow limited RDS data errors as we have no correctioin code offset = (block4) & 0x3F; // 6 bits mins = (block4 >> 6) & 0x3F; // 6 bits mins += 60 * (((block3 & 0x0001) << 4) | ((block4 >> 12) & 0x0F)); } // adjust offset if (offset & 0x20) { mins -= 30 * (offset & 0x1F); } else { mins += 30 * (offset & 0x1F); } if(mins == lastmins+1){ // get CT time twice before populating time minutes=mins;} lastmins=mins; if(rdssynchro == 0x1000){ if(minutes>0 && minutes<1500){sprintf(CTtime, "CT %2d:%02d",(minutes/60),(minutes%60));} } else{minutes=0;sprintf(CTtime, "CT --:--");} // CT time formatted string break; case 0x6A: // IH break; case 0x8A: // TMC break; case 0xAA: // TMC break; case 0xCA: // TMC break; case 0xEA: // IH break; default: break; } }