Go Down

Topic: RDA5807SP FM Radio Receiver - i2C (Read 8271 times) previous topic - next topic

KC8OZA

I've been pounding at this all day, and I'm missing something.  If somebody can point my nose I would appreciate it.

I picked up a couple of RDA5807SP I2C based FM Radio Receiver IC's off the FleaBay a few days ago. They came in the mail, and I'm anxious to hook them up to my arduino.   They're I2C controlled, they have a couple of registers storing what looks like 2 bytes of data each, and we can manipulate these registers to control the radio.  I'm fairly new to I2C, but starting to get my feet wet, and I just can't seem to get the hang of the appropriate read/write on this thing.  I write values to the registers, but when I read them back, they're different from what I wrote. I'm not sure where to go from here.

See my attached code.

So for example, lets say I want to write the register at 0x05, and set bits 0-3 as the value 1 (forget the other bits, they're not important yet), I'm doing whats shown below.   But its not working. When I read it back, its not how I set it.  What am I doing wrong?

Code: [Select]

#include <Wire.h>

int device_address = 96;
int seekPin = 12;
int seekPinState = 0;

void setup(){
pinMode (seekPin,INPUT); 
 
Wire.begin();
Serial.begin(9600);

getVolume();
maxVolume();
getVolume();

}


void loop(){

Serial.print("Device addres is: ");
Serial.println(device_address);

seekPinState = digitalRead(seekPin);

if (seekPinState == 1) {
  Serial.println("High!");

  }

getVolume();
delay(5000);

}


void maxVolume(){
Serial.println("Setting Volume");
Wire.beginTransmission(device_address);
Wire.write(5);

Wire.write(136); // first byte 10001000
Wire.write(175); // second byte 10101111  <-- This is the 1111 for the first 3 bits of the byte.

Wire.endTransmission();

}

void getVolume(){

Wire.requestFrom(device_address, 2);

while (Wire.available() == 0);
 
int byte1 = Wire.read();
int byte2 = Wire.read();
String binaryByte1 = String(byte1, BIN);
String binaryByte2 = String(byte2, BIN);

Serial.print("The currnet volume setting is: ");
Serial.print(binaryByte1);
Serial.print(":");
Serial.println(binaryByte2);
}

Grumpy_Mike

Code: [Select]
while (Wire.available() == 0);
This just hangs about until at least one byte is available.
Then:-
Code: [Select]
 
int byte1 = Wire.read();
int byte2 = Wire.read();

Reads two bytes. At this point the second byte almost certainly has not arrived.
So I would try:-
Code: [Select]
while (Wire.available() < 2);

I haven't looked at the rest of the code so there might be other errors as well.

Nick Gammon

It's I2C Mike, not Serial.

@op:

Don't do this:

Code: [Select]
 while (Wire.available() == 0);

Wire.requestFrom blocks until it gets the data you wanted, or it never will. Better is:

Code: [Select]
if (Wire.requestFrom(device_address, 2) != 2)
 {
 // error
 return;
 }


I don't know what this achieves:

Code: [Select]
 int byte1 = Wire.read();
 int byte2 = Wire.read();
 String binaryByte1 = String(byte1, BIN);
 String binaryByte2 = String(byte2, BIN);


Just do:
Code: [Select]

 byte byte1 = Wire.read();
 byte byte2 = Wire.read();

 Serial.print("The current volume setting is: ");
 Serial.print(byte1, BIN);
 Serial.print(":");
 Serial.println(byte2, BIN);
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Grumpy_Mike

Quote
It's I2C Mike, not Serial.

Yes I know, but you still have to wait until the data arrives.

KC8OZA

My timing must be lucky - I was getting both bytes in time... but your recommended modification is certainly a good idea, I've implemented it.   So the fact remains, when I set the values, and then try to read them, they come back different. I think this is more than likely a learning curve issue... I've gotta be doing something wrong.

Nick Gammon


Yes I know, but you still have to wait until the data arrives.


No, because requestFrom blocks. Building in the wait only makes an infinite loop possible.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon


I've gotta be doing something wrong.


I've looked but I can't find the programming guide. Can you link to it please? The thing that specifies the I2C commands/responses.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

KC8OZA

The chip is the same as the FM receiver that Parallax sells, so I've been using their datasheet and example code as reference.

http://www.parallax.com/portals/0/downloads/docs/prod/audiovis/27984-FM-RadioReceiver-v1.0.pdf
http://www.parallax.com/portals/0/downloads/docs/prod/audiovis/ParallaxFMRadio-spin.zip

Some additional things I don't quite 'get' ....   When I send a bitstream to try and write the register, do I send it with bit 7 first, then 6, 5, etc (like you'd write it in binary on paper)  or does it go LSB first (unlike how you'd write it on paper). Do I have to send it one byte at a time, or can I send the full two bytes at once?  I think if I can get my arms around the proper way to read and write the registers, I'll be home free.

Thx

Grumpy_Mike

The registers are 16 bit wide therefore you have to send them in two parts.
That data sheet says the high byte followed by the low byte. So to send a value in a variable called val use:-
Code: [Select]
Wire.write(val >> 8); // hi byte
Wire.write(val & 0xff); // lo byte  


Values come back from the chip with the hi byte first.

KC8OZA

Ok so we're sending it as two bytes. I get that.    We're sending the high byte first - I get that.  So when I create the variable that is going to be split with the code you provided, do I write it with bit 15 first or bit 0 first?

Grumpy_Mike

Quote
do I write it with bit 15 first or bit 0 first?

I don't understand what you mean by first.
Declare the variable as an int
Code: [Select]
int var;
if you want to set bit 0 then:-
Code: [Select]
var = var | 0x1;
or if you want to set bit 15 then:-
Code: [Select]
var = var | 0x8000
The bits are the same as in a normal value.

KC8OZA

So lets say I wanted bits 0123 to be 1's.    Would I write the variable as shown in A or B

A - var = "0000000000001111"
B - var = "1111000000000000"

I think I write it as A

Grumpy_Mike

Quote
I think I write it as A

Yes so do I.

Except don't put the value in quote marks, write it in hex.

KC8OZA

So when you say var = var | 0x8000  is this simply starting at the position identified?  Like I could write just the last 4 bits of the register if I really wanted to?

Grumpy_Mike

The | is the inclusive OR operation it is used to set those bits in the variable that are a 1 in the mask (the number you are ORing) and leave the other bits in the variable unchanged.

Quote
I could write just the last 4 bits of the register if I really wanted to?

If you want to set the variable to 0000000000001111 then you can just use:-
var = 0xf

Go Up