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/

Revision:
1:2c8a64e71afd
Parent:
0:527aa96336ac
Child:
3:bdd691977de4
--- a/RDA5807M.cpp	Tue Mar 31 22:26:32 2015 +0000
+++ b/RDA5807M.cpp	Sat Apr 11 22:53:22 2015 +0000
@@ -1,13 +1,11 @@
 #include "RDA5807M.h"
 
 
-int volume;
-
 unsigned int RDA5807M_WriteRegDef[6] ={0xC004,0x0000,0x0100,0x84D4,0x4000,0x0000}; // initial data
 
-
-RDA5807M::RDA5807M(PinName sda, PinName scl, int addr) : i2c(sda, scl), addr(addr)
+RDA5807M::RDA5807M(PinName sda, PinName scl) : i2c(sda, scl)
 {   
+    i2c.frequency(400000);
     Init();
 }
 
@@ -21,13 +19,11 @@
     int i,x = 0;
     for(i=0; i<12; i=i+2){
         buf[i] = RDA5807M_WriteReg[x] >> 8;
-        x++;
-    }
+        x++;}
     x = 0;
     for(i=1; i<13; i=i+2){
         buf[i] = RDA5807M_WriteReg[x] & 0xFF;
-        x++;
-    }
+        x++;}
     i2c.write(0x20, buf, 14);
 }
 
@@ -35,24 +31,29 @@
     int i;
     for(i=0; i<6; i++){
         RDA5807M_WriteReg[i] = RDA5807M_WriteRegDef[i];
+        WriteAll();
     }
 }
 
 void RDA5807M::PowerOn(){
-    RDA5807M_WriteReg[1] = RDA5807M_WriteReg[1] | 0x0010;
+    RDA5807M_WriteReg[1] = RDA5807M_WriteReg[1] | RDA_TUNE_ON;
     RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_POWER;
-    WriteAll();
+    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();
+    WriteAll();power=0;
 }
 
 void RDA5807M::Reset(){
     Init();
     PowerOn();
+    RDSinit();
+    RDS();
+    Volume(InitialVolume);
+    Frequency(DefaultFreq);  // set default start frequency.
 }
 
 void RDA5807M::Volume(int vol){
@@ -63,15 +64,18 @@
         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();
 }
@@ -79,9 +83,11 @@
 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();
 }
@@ -89,9 +95,11 @@
 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();
 }
@@ -99,9 +107,11 @@
 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();
 }
@@ -109,9 +119,23 @@
 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();
 }
@@ -130,9 +154,9 @@
 
 void RDA5807M::Frequency(float Freq){
     int Channel;
-    Channel = (Freq-StartingFreq)/0.1;
+    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)
+    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;
 }
@@ -140,9 +164,11 @@
 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();
 }
@@ -154,6 +180,10 @@
         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
@@ -171,3 +201,140 @@
 }
 
 
+void RDA5807M::RDSinit() {
+  strcpy(PSName1, "        ");
+  strcpy(PSName2, PSName1);
+  strcpy(StationName, "        ");
+  memset(RDSText, '\0', sizeof(RDSText));
+  lastTextIDX = 0;
+} 
+
+void RDA5807M::processData()
+{
+  char c1, c2;
+  int  idx;     // index of rdsText
+  int mins;     // RDS time in minutes
+  int offset;      // RDS time offset and sign
+  Read();
+  if (block1==0) {
+    // reset all the RDS info.
+    RDSinit();
+    // Send out empty data
+    if (sendServiceName) sendServiceName(StationName);
+    if (sendText)        sendText("");
+    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 publishing the station name
+    if ((PSName1[idx] == c1) && (PSName1[idx + 1] == c2)) {
+      // retrieved the text a second time: store to _PSName2
+      PSName2[idx] = c1;
+      PSName2[idx + 1] = c2;
+      PSName2[8] = '\0';
+      if ((idx == 6) && strcmp(PSName1, PSName2) == 0) {
+        if (strcmp(PSName2, StationName) != 0) {
+          // publish station name
+          if(strlen(PSName2)<9){strcpy(StationName, PSName2);}
+          if (sendServiceName)
+            sendServiceName(StationName);            
+        } 
+      }
+    }
+    if ((PSName1[idx] != c1) || (PSName1[idx + 1] != c2)) {
+      PSName1[idx] = c1;
+      PSName1[idx + 1] = c2;
+      PSName1[8] = '\0';
+    } 
+    break;
+    
+  case 0x2A:
+    // RDS text
+  //  if(rdsblockerror > 1){memset(RDSText, '\0', sizeof(RDSText));lastTextIDX = 0;}
+    // The data received is part of the 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.
+      // now send it to the possible listener.
+      if (sendText)
+        sendText(RDSText);
+    }
+    lastTextIDX = idx;
+
+    if (textAB != lasttextAB) {
+      // when this bit is toggled the whole buffer should be cleared.
+      lasttextAB = textAB;
+    } 
+    // new data is 2 chars from block 3
+    RDSText[idx] = (block3 >> 8);     idx++;
+    RDSText[idx] = (block3 & 0x00FF); idx++;
+
+    // new data is 2 chars from block 4
+    RDSText[idx] = (block4 >> 8); idx++;
+    RDSText[idx] = (block4 & 0x00FF); idx++;
+    
+    break;
+
+  case 0x4A:
+    // Clock time and date
+    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);
+    }
+
+//    Serial.print(" >>"); Serial.print(mins/60); Serial.print(':'); Serial.println(mins % 60);
+
+    //if ((sendTime) && (mins != _lastRDSMinutes)) {
+      CTtime = mins;
+    // sendTime(mins / 60, mins % 60);
+    //  } 
+    break;
+
+  case 0x6A: 
+    // IH
+    break;
+
+  case 0x8A:
+    // TMC
+    break;
+
+  case 0xAA:
+    // TMC
+    break;
+
+  case 0xCA:
+    // TMC
+    break;
+
+  case 0xEA:
+    // IH
+    break;
+
+  default:
+    // Serial.print("RDS_GRP:"); Serial.println(rdsGroupType, HEX);
+    break;
+  }
+}