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/

Committer:
star297
Date:
Fri Jun 19 16:19:31 2015 +0000
Revision:
4:3e7968bd455d
Parent:
3:bdd691977de4
Update RDS Text function

Who changed what in which revision?

UserRevisionLine numberNew contents of line
star297 0:527aa96336ac 1 #include "RDA5807M.h"
star297 0:527aa96336ac 2
star297 0:527aa96336ac 3
star297 0:527aa96336ac 4 unsigned int RDA5807M_WriteRegDef[6] ={0xC004,0x0000,0x0100,0x84D4,0x4000,0x0000}; // initial data
star297 0:527aa96336ac 5
star297 1:2c8a64e71afd 6 RDA5807M::RDA5807M(PinName sda, PinName scl) : i2c(sda, scl)
star297 0:527aa96336ac 7 {
star297 1:2c8a64e71afd 8 i2c.frequency(400000);
star297 0:527aa96336ac 9 Init();
star297 0:527aa96336ac 10 }
star297 0:527aa96336ac 11
star297 0:527aa96336ac 12 RDA5807M::~RDA5807M()
star297 0:527aa96336ac 13 {
star297 0:527aa96336ac 14 }
star297 0:527aa96336ac 15
star297 0:527aa96336ac 16 void RDA5807M::WriteAll()
star297 0:527aa96336ac 17 {
star297 0:527aa96336ac 18 char buf[30];
star297 0:527aa96336ac 19 int i,x = 0;
star297 0:527aa96336ac 20 for(i=0; i<12; i=i+2){
star297 0:527aa96336ac 21 buf[i] = RDA5807M_WriteReg[x] >> 8;
star297 1:2c8a64e71afd 22 x++;}
star297 0:527aa96336ac 23 x = 0;
star297 0:527aa96336ac 24 for(i=1; i<13; i=i+2){
star297 0:527aa96336ac 25 buf[i] = RDA5807M_WriteReg[x] & 0xFF;
star297 1:2c8a64e71afd 26 x++;}
star297 0:527aa96336ac 27 i2c.write(0x20, buf, 14);
star297 0:527aa96336ac 28 }
star297 0:527aa96336ac 29
star297 0:527aa96336ac 30 void RDA5807M::Init(){
star297 0:527aa96336ac 31 int i;
star297 0:527aa96336ac 32 for(i=0; i<6; i++){
star297 0:527aa96336ac 33 RDA5807M_WriteReg[i] = RDA5807M_WriteRegDef[i];
star297 1:2c8a64e71afd 34 WriteAll();
star297 0:527aa96336ac 35 }
star297 0:527aa96336ac 36 }
star297 0:527aa96336ac 37
star297 0:527aa96336ac 38 void RDA5807M::PowerOn(){
star297 1:2c8a64e71afd 39 RDA5807M_WriteReg[1] = RDA5807M_WriteReg[1] | RDA_TUNE_ON;
star297 0:527aa96336ac 40 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_POWER;
star297 1:2c8a64e71afd 41 WriteAll(); power=1;
star297 0:527aa96336ac 42 RDA5807M_WriteReg[1] = RDA5807M_WriteReg[1] & 0xFFEF; //Disable tune after PowerOn operation
star297 0:527aa96336ac 43 }
star297 0:527aa96336ac 44
star297 0:527aa96336ac 45 void RDA5807M::PowerOff(){
star297 0:527aa96336ac 46 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] ^ RDA_POWER;
star297 1:2c8a64e71afd 47 WriteAll();power=0;
star297 0:527aa96336ac 48 }
star297 0:527aa96336ac 49
star297 0:527aa96336ac 50 void RDA5807M::Reset(){
star297 0:527aa96336ac 51 Init();
star297 0:527aa96336ac 52 PowerOn();
star297 1:2c8a64e71afd 53 RDSinit();
star297 1:2c8a64e71afd 54 RDS();
star297 1:2c8a64e71afd 55 Volume(InitialVolume);
star297 1:2c8a64e71afd 56 Frequency(DefaultFreq); // set default start frequency.
star297 0:527aa96336ac 57 }
star297 0:527aa96336ac 58
star297 0:527aa96336ac 59 void RDA5807M::Volume(int vol){
star297 0:527aa96336ac 60 if(vol > 15){
star297 0:527aa96336ac 61 vol = 15;
star297 0:527aa96336ac 62 }
star297 0:527aa96336ac 63 if(vol < 0){
star297 0:527aa96336ac 64 vol = 0;
star297 0:527aa96336ac 65 }
star297 0:527aa96336ac 66 RDA5807M_WriteReg[3] = (RDA5807M_WriteReg[3] & 0xFFF0)| vol; // Set New Volume
star297 1:2c8a64e71afd 67 volume=vol;
star297 0:527aa96336ac 68 WriteAll();
star297 0:527aa96336ac 69 }
star297 0:527aa96336ac 70
star297 0:527aa96336ac 71 void RDA5807M::BassBoost(){
star297 0:527aa96336ac 72 if ((RDA5807M_WriteReg[0] & 0x1000)==0){
star297 0:527aa96336ac 73 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_BASS_ON;
star297 1:2c8a64e71afd 74 bass=1;
star297 0:527aa96336ac 75 }
star297 0:527aa96336ac 76 else{
star297 0:527aa96336ac 77 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_BASS_OFF;
star297 1:2c8a64e71afd 78 bass=0;
star297 0:527aa96336ac 79 }
star297 0:527aa96336ac 80 WriteAll();
star297 0:527aa96336ac 81 }
star297 0:527aa96336ac 82
star297 0:527aa96336ac 83 void RDA5807M::Mono(){
star297 0:527aa96336ac 84 if ((RDA5807M_WriteReg[0] & 0x2000)==0){
star297 0:527aa96336ac 85 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_MONO_ON;
star297 1:2c8a64e71afd 86 mono=1;
star297 0:527aa96336ac 87 }
star297 0:527aa96336ac 88 else{
star297 0:527aa96336ac 89 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_MONO_OFF;
star297 1:2c8a64e71afd 90 mono=0;
star297 0:527aa96336ac 91 }
star297 0:527aa96336ac 92 WriteAll();
star297 0:527aa96336ac 93 }
star297 0:527aa96336ac 94
star297 0:527aa96336ac 95 void RDA5807M::Mute(){
star297 0:527aa96336ac 96 if ((RDA5807M_WriteReg[0] & 0x8000)==0){
star297 0:527aa96336ac 97 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | 0x8000;
star297 1:2c8a64e71afd 98 mute=0;
star297 0:527aa96336ac 99 }
star297 0:527aa96336ac 100 else{
star297 0:527aa96336ac 101 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & 0x7FFF;
star297 1:2c8a64e71afd 102 mute=1;
star297 0:527aa96336ac 103 }
star297 0:527aa96336ac 104 WriteAll();
star297 0:527aa96336ac 105 }
star297 0:527aa96336ac 106
star297 0:527aa96336ac 107 void RDA5807M::Softmute(){
star297 0:527aa96336ac 108 if ((RDA5807M_WriteReg[2] & 0x0200)==0){
star297 0:527aa96336ac 109 RDA5807M_WriteReg[2] = RDA5807M_WriteReg[2] | 0x0200;
star297 1:2c8a64e71afd 110 softmute=1;
star297 0:527aa96336ac 111 }
star297 0:527aa96336ac 112 else{
star297 0:527aa96336ac 113 RDA5807M_WriteReg[2] = RDA5807M_WriteReg[2] & 0xFDFF;
star297 1:2c8a64e71afd 114 softmute=0;
star297 0:527aa96336ac 115 }
star297 0:527aa96336ac 116 WriteAll();
star297 0:527aa96336ac 117 }
star297 0:527aa96336ac 118
star297 0:527aa96336ac 119 void RDA5807M::SoftBlend(){
star297 0:527aa96336ac 120 if ((RDA5807M_WriteReg[6] & 0x0001)==0){
star297 0:527aa96336ac 121 RDA5807M_WriteReg[6] = RDA5807M_WriteReg[6] | 0x0001;
star297 1:2c8a64e71afd 122 softblend=1;
star297 0:527aa96336ac 123 }
star297 0:527aa96336ac 124 else{
star297 0:527aa96336ac 125 RDA5807M_WriteReg[6] = RDA5807M_WriteReg[6] & 0xFFFE;
star297 1:2c8a64e71afd 126 softblend=0;
star297 1:2c8a64e71afd 127 }
star297 1:2c8a64e71afd 128 WriteAll();
star297 1:2c8a64e71afd 129 }
star297 1:2c8a64e71afd 130
star297 1:2c8a64e71afd 131 void RDA5807M::AFC(){
star297 1:2c8a64e71afd 132 if ((RDA5807M_WriteReg[2] & 0x0100)==0){
star297 1:2c8a64e71afd 133 RDA5807M_WriteReg[2] = RDA5807M_WriteReg[2] | 0x0100;
star297 1:2c8a64e71afd 134 afc=1;
star297 1:2c8a64e71afd 135 }
star297 1:2c8a64e71afd 136 else{
star297 1:2c8a64e71afd 137 RDA5807M_WriteReg[2] = RDA5807M_WriteReg[2] & 0xFEFE;
star297 1:2c8a64e71afd 138 afc=0;
star297 0:527aa96336ac 139 }
star297 0:527aa96336ac 140 WriteAll();
star297 0:527aa96336ac 141 }
star297 0:527aa96336ac 142
star297 0:527aa96336ac 143 void RDA5807M::SeekUp(){
star297 0:527aa96336ac 144 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_SEEK_UP; // Set Seek Up
star297 0:527aa96336ac 145 WriteAll();
star297 0:527aa96336ac 146 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_SEEK_STOP; // Disable Seek
star297 0:527aa96336ac 147 }
star297 0:527aa96336ac 148
star297 0:527aa96336ac 149 void RDA5807M::SeekDown(){
star297 0:527aa96336ac 150 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_SEEK_DOWN; // Set Seek Down
star297 0:527aa96336ac 151 WriteAll();
star297 0:527aa96336ac 152 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_SEEK_STOP; // Disable Seek
star297 0:527aa96336ac 153 }
star297 0:527aa96336ac 154
star297 0:527aa96336ac 155 void RDA5807M::Frequency(float Freq){
star297 0:527aa96336ac 156 int Channel;
star297 1:2c8a64e71afd 157 Channel = ((Freq-StartingFreq)/0.1)+0.05;
star297 0:527aa96336ac 158 Channel = Channel & 0x03FF;
star297 1:2c8a64e71afd 159 RDA5807M_WriteReg[1] = Channel*64 + 0x10; // Channel + TUNE-Bit + Band=00(87-108) + Space=00(100kHz)
star297 0:527aa96336ac 160 WriteAll();
star297 0:527aa96336ac 161 RDA5807M_WriteReg[1] = RDA5807M_WriteReg[1] & RDA_TUNE_OFF;
star297 0:527aa96336ac 162 }
star297 0:527aa96336ac 163
star297 0:527aa96336ac 164 void RDA5807M::RDS(){
star297 0:527aa96336ac 165 if ((RDA5807M_WriteReg[0] & RDA_RDS_ON)==0){
star297 0:527aa96336ac 166 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] | RDA_RDS_ON;
star297 1:2c8a64e71afd 167 rds=1;
star297 0:527aa96336ac 168 }
star297 0:527aa96336ac 169 else{
star297 0:527aa96336ac 170 RDA5807M_WriteReg[0] = RDA5807M_WriteReg[0] & RDA_RDS_OFF;
star297 1:2c8a64e71afd 171 rds=0;
star297 0:527aa96336ac 172 }
star297 0:527aa96336ac 173 WriteAll();
star297 0:527aa96336ac 174 }
star297 0:527aa96336ac 175
star297 3:bdd691977de4 176 void RDA5807M::Readregisters(){
star297 0:527aa96336ac 177 int i;
star297 0:527aa96336ac 178 char rcv[12];
star297 0:527aa96336ac 179 i2c.read(0x20, rcv,12); // read 12 bytes for reg 0x0A .. reg 0x0F
star297 0:527aa96336ac 180 for(i=0; i<6; i++){
star297 0:527aa96336ac 181 RDA5807M_ReadReg[i] = ((rcv[i *2] << 8) | rcv [(i*2) +1] );
star297 0:527aa96336ac 182 }
star297 1:2c8a64e71afd 183 block1 = RDA5807M_ReadReg[2];
star297 1:2c8a64e71afd 184 block2 = RDA5807M_ReadReg[3];
star297 1:2c8a64e71afd 185 block3 = RDA5807M_ReadReg[4];
star297 1:2c8a64e71afd 186 block4 = RDA5807M_ReadReg[5];
star297 0:527aa96336ac 187
star297 0:527aa96336ac 188 rdsready = RDA5807M_ReadReg[0] & 0x8000; //if rdsready != 0 rds data are ready
star297 0:527aa96336ac 189 tuneok = RDA5807M_ReadReg[0] & 0x4000; //if tuneok != 0 seek/tune completed
star297 0:527aa96336ac 190 nochannel = RDA5807M_ReadReg[0] & 0x2000; //if nochannel != 0 no channel found
star297 0:527aa96336ac 191 rdssynchro = RDA5807M_ReadReg[0] & 0x1000; //if rdssynchro = 1000 rds decoder syncrhonized
star297 0:527aa96336ac 192 stereo = RDA5807M_ReadReg[0] & 0x0400; //if stereo = 0 station is mono else stereo
star297 0:527aa96336ac 193 freq = (((RDA5807M_ReadReg[0] & 0x03FF) * 100) + 87000); //return freq ex 102600KHz > 102.6MHz
star297 0:527aa96336ac 194 signal = RDA5807M_ReadReg[1] >> 10; //return signal strength rssi
star297 0:527aa96336ac 195 fmready = RDA5807M_ReadReg[1] & 0x0008; //if fmready = 8 > fm is ready
star297 0:527aa96336ac 196 fmstation = RDA5807M_ReadReg[1] & 0x0100; //if fmstation = 100 fm station is true
star297 0:527aa96336ac 197 rdsblockerror = RDA5807M_ReadReg[1] & 0x000C; //check for rds blocks errors
star297 0:527aa96336ac 198 //00= 0 errors,01= 1~2 errors requiring correction
star297 0:527aa96336ac 199 //10= 3~5 errors requiring correction
star297 0:527aa96336ac 200 //11= 6+ errors or error in checkword, correction not possible.
star297 0:527aa96336ac 201 }
star297 0:527aa96336ac 202
star297 1:2c8a64e71afd 203 void RDA5807M::RDSinit() {
star297 3:bdd691977de4 204 strcpy(StationName, " ");
star297 3:bdd691977de4 205 strcpy(PSName, " ");
star297 1:2c8a64e71afd 206 strcpy(PSName1, " ");
star297 3:bdd691977de4 207 strcpy(PSName2, " ");
star297 1:2c8a64e71afd 208 memset(RDSText, '\0', sizeof(RDSText));
star297 3:bdd691977de4 209 memset(RDSTxt, '\0', sizeof(RDSTxt));
star297 1:2c8a64e71afd 210 lastTextIDX = 0;
star297 3:bdd691977de4 211 mins=0;
star297 3:bdd691977de4 212 sprintf(CTtime, "CT --:--");
star297 1:2c8a64e71afd 213 }
star297 1:2c8a64e71afd 214
star297 3:bdd691977de4 215 void RDA5807M::ProcessData()
star297 1:2c8a64e71afd 216 {
star297 3:bdd691977de4 217 Readregisters();
star297 3:bdd691977de4 218 if (rdssynchro != 0x1000){ // reset all the RDS info.
star297 3:bdd691977de4 219 RDSinit();
star297 3:bdd691977de4 220 return;
star297 3:bdd691977de4 221 }
star297 1:2c8a64e71afd 222 // analyzing Block 2
star297 3:bdd691977de4 223 rdsGroupType = 0x0A | ((block2 & 0xF000) >> 8) | ((block2 & 0x0800) >> 11);
star297 3:bdd691977de4 224 rdsTP = (block2 & 0x0400);
star297 3:bdd691977de4 225 rdsPTY = (block2 & 0x0400);
star297 1:2c8a64e71afd 226
star297 3:bdd691977de4 227 switch (rdsGroupType) {
star297 3:bdd691977de4 228 case 0x0A:
star297 3:bdd691977de4 229 case 0x0B:
star297 3:bdd691977de4 230 // The data received is part of the Service Station Name
star297 3:bdd691977de4 231 idx = 2 * (block2 & 0x0003);
star297 3:bdd691977de4 232 // new data is 2 chars from block 4
star297 3:bdd691977de4 233 c1 = block4 >> 8;
star297 3:bdd691977de4 234 c2 = block4 & 0x00FF;
star297 3:bdd691977de4 235 // check that the data was received successfully twice
star297 3:bdd691977de4 236 // before sending the station name
star297 3:bdd691977de4 237 if ((PSName1[idx] == c1) && (PSName1[idx + 1] == c2)) {
star297 3:bdd691977de4 238 // retrieve the text a second time: store to _PSName2
star297 3:bdd691977de4 239 PSName2[idx] = c1;
star297 3:bdd691977de4 240 PSName2[idx + 1] = c2;
star297 3:bdd691977de4 241 PSName2[8] = '\0';
star297 3:bdd691977de4 242 if (strcmp(PSName1, PSName2) == 0) {
star297 4:3e7968bd455d 243 // populate station name
star297 3:bdd691977de4 244 n=0;
star297 3:bdd691977de4 245 for(i=0;i<(8);i++){ // remove non-printable error ASCCi characters
star297 3:bdd691977de4 246 if(PSName2[i] > 31 && PSName2[i] < 127){
star297 3:bdd691977de4 247 StationName[n] = PSName2[i];
star297 3:bdd691977de4 248 n++;
star297 3:bdd691977de4 249 }
star297 3:bdd691977de4 250 }
star297 3:bdd691977de4 251 }
star297 3:bdd691977de4 252 }
star297 3:bdd691977de4 253 if ((PSName1[idx] != c1) || (PSName1[idx + 1] != c2)) {
star297 3:bdd691977de4 254 PSName1[idx] = c1;
star297 3:bdd691977de4 255 PSName1[idx + 1] = c2;
star297 3:bdd691977de4 256 PSName1[8] = '\0';
star297 1:2c8a64e71afd 257 }
star297 1:2c8a64e71afd 258 break;
star297 1:2c8a64e71afd 259
star297 3:bdd691977de4 260 case 0x2A:
star297 3:bdd691977de4 261 // RDS text
star297 1:2c8a64e71afd 262 textAB = (block2 & 0x0010);
star297 4:3e7968bd455d 263 idx = 4 * (block2 & 0x000F);
star297 1:2c8a64e71afd 264 if (idx < lastTextIDX) {
star297 4:3e7968bd455d 265 // The existing text might be complete because the index is starting at the beginning again.
star297 4:3e7968bd455d 266 // Populate RDS text array.
star297 3:bdd691977de4 267 n=0;
star297 4:3e7968bd455d 268 for(i=0;i<strlen(RDSTxt);i++){
star297 3:bdd691977de4 269 if(RDSTxt[i] > 31 && RDSTxt[i] < 127){ // remove any non printable error charcters
star297 3:bdd691977de4 270 RDSText[n] = RDSTxt[i];
star297 3:bdd691977de4 271 n++;
star297 3:bdd691977de4 272 }
star297 3:bdd691977de4 273 }
star297 3:bdd691977de4 274 }
star297 1:2c8a64e71afd 275 lastTextIDX = idx;
star297 1:2c8a64e71afd 276 if (textAB != lasttextAB) {
star297 1:2c8a64e71afd 277 // when this bit is toggled the whole buffer should be cleared.
star297 1:2c8a64e71afd 278 lasttextAB = textAB;
star297 3:bdd691977de4 279 memset(RDSTxt, 0, sizeof(RDSTxt));
star297 3:bdd691977de4 280 memset(RDSText, '\0', sizeof(RDSText));
star297 3:bdd691977de4 281 }
star297 3:bdd691977de4 282 if(rdsblockerror < 4){
star297 3:bdd691977de4 283 // new data is 2 chars from block 3
star297 3:bdd691977de4 284 RDSTxt[idx] = (block3 >> 8); idx++;
star297 3:bdd691977de4 285 RDSTxt[idx] = (block3 & 0x00FF); idx++;
star297 3:bdd691977de4 286 // new data is 2 chars from block 4
star297 3:bdd691977de4 287 RDSTxt[idx] = (block4 >> 8); idx++;
star297 3:bdd691977de4 288 RDSTxt[idx] = (block4 & 0x00FF); idx++;
star297 3:bdd691977de4 289 }
star297 1:2c8a64e71afd 290 break;
star297 1:2c8a64e71afd 291
star297 1:2c8a64e71afd 292 case 0x4A:
star297 1:2c8a64e71afd 293 // Clock time and date
star297 4:3e7968bd455d 294 if(rdsblockerror <3){ // allow limited RDS data errors as we have no correctioin code
star297 3:bdd691977de4 295 offset = (block4) & 0x3F; // 6 bits
star297 3:bdd691977de4 296 mins = (block4 >> 6) & 0x3F; // 6 bits
star297 3:bdd691977de4 297 mins += 60 * (((block3 & 0x0001) << 4) | ((block4 >> 12) & 0x0F));
star297 3:bdd691977de4 298 }
star297 1:2c8a64e71afd 299 // adjust offset
star297 1:2c8a64e71afd 300 if (offset & 0x20) {
star297 1:2c8a64e71afd 301 mins -= 30 * (offset & 0x1F);
star297 1:2c8a64e71afd 302 }
star297 1:2c8a64e71afd 303 else {
star297 1:2c8a64e71afd 304 mins += 30 * (offset & 0x1F);
star297 3:bdd691977de4 305 }
star297 4:3e7968bd455d 306 if(mins == lastmins+1){ // get CT time twice before populating time
star297 3:bdd691977de4 307 minutes=mins;}
star297 3:bdd691977de4 308 lastmins=mins;
star297 3:bdd691977de4 309 if(rdssynchro == 0x1000){
star297 3:bdd691977de4 310 if(minutes>0 && minutes<1500){sprintf(CTtime, "CT %2d:%02d",(minutes/60),(minutes%60));}
star297 3:bdd691977de4 311 }
star297 3:bdd691977de4 312 else{minutes=0;sprintf(CTtime, "CT --:--");} // CT time formatted string
star297 1:2c8a64e71afd 313 break;
star297 1:2c8a64e71afd 314
star297 1:2c8a64e71afd 315 case 0x6A:
star297 1:2c8a64e71afd 316 // IH
star297 1:2c8a64e71afd 317 break;
star297 1:2c8a64e71afd 318
star297 1:2c8a64e71afd 319 case 0x8A:
star297 1:2c8a64e71afd 320 // TMC
star297 1:2c8a64e71afd 321 break;
star297 1:2c8a64e71afd 322
star297 1:2c8a64e71afd 323 case 0xAA:
star297 1:2c8a64e71afd 324 // TMC
star297 1:2c8a64e71afd 325 break;
star297 1:2c8a64e71afd 326
star297 1:2c8a64e71afd 327 case 0xCA:
star297 1:2c8a64e71afd 328 // TMC
star297 1:2c8a64e71afd 329 break;
star297 1:2c8a64e71afd 330
star297 1:2c8a64e71afd 331 case 0xEA:
star297 1:2c8a64e71afd 332 // IH
star297 1:2c8a64e71afd 333 break;
star297 1:2c8a64e71afd 334
star297 1:2c8a64e71afd 335 default:
star297 3:bdd691977de4 336
star297 1:2c8a64e71afd 337 break;
star297 1:2c8a64e71afd 338 }
star297 3:bdd691977de4 339 }
star297 3:bdd691977de4 340