TEA5767 Radio Module and Xojo I2C?

Can anyone tell me how to write a sequence of 5 bytes to an I2C device? I have a TEA5767 FM Radio module that I’d like to control from Xojo. It resides at I2C address &h60. When I use the GPIO.I2CWrite() function, it appears that what I’m doing is creating 5 separate 1 byte transactions with the radio.

fd = GPIO.I2CSetup(&h60)
RetVal = GPIO.I2CWrite(fd, Byte1)
RetVal = GPIO.I2CWrite(fd, Byte2)
RetVal = GPIO.I2CWrite(fd, Byte3)
RetVal = GPIO.I2CWrite(fd, Byte4)
RetVal = GPIO.I2CWrite(fd, Byte5)

What I want to do is create a single 5 byte transaction with the radio. But I don’t see any way to do this with Xojo’s implementation of the I2C interface.

I’ve found several pieces of code writen in C and Python that are able to successfully control the radio but I can’t seem to find any way to replicate their code in Xojo. They essentially open the I2C device as a file and write 5 bytes to the file handle and then close the file.

int fd;
int devID = 0x60;
unsigned char radio[5] = {0};

radio[0] = frequencyH; 
radio[1] = frequencyL; 
radio[2] = 0xB0;
radio[3] = 0x10; 
radio[4] = 0x40; 

fd = wiringPiI2CSetup(devID);
write(fd, radio, 5);
close(fd);

I would be really thankful for any help you can provide. I’ve been searching/reading/experimenting for a couple of days now and have pretty much tried anything and everything that I could. What am I missing?

-Wes

Hi Wes.
I have not had to do this, yet, but will at some point - probably sooner than later. I will have a look and see what I can find that may be helpful.

Tim

Hi Wes.
I have no hardware to test with, but after reviewing several examples found by Google, which look similar to what you showed as python code (they are sending a 5 byte array) I recalled that Einhuger was/is into using the Pi’s of different varieties. I found this on his website with xojo code that is slightly different than the sample xojo code.

Einhuger PCF8591 analog to digital

Try it out and please advise how you make out.
Tim

Use a MemoryBlock.

dim radio as new MemoryBlock(5)
radio.byte(0) = frequencyH
radio.byte(1) = frequencyL
radio.byte(2) = &xB0
radio.byte(3) = &x10
radio.byte(4) = &x40

fd = GPIO.I2CSetup(&h60)
RetVal = GPIO.I2CWrite(fd, radio)

Hi Tim,
With that method you cannot and do not have to tell it how many bytes to send correct? In some cases not all bytes should be sent. But the method you used here is very cool! Using a Memory Block. Nice, efficient too!

Let us know Wes which solution works, and works best please!

Tim

Tim S.,

Thanks for the link. The code there didn’t seem to address my situation so I decided to look at the source code to the wiringPi library for some clues. After digging around in the wiringPi code for a while, I didn’t find anything that addressed sending a data payload larger than either a byte or a word. Although I did find evidence that I2C supports sending a data payload of up to 32 bytes. It looks like the wiringPi library omitted support for that option.

I just emailed the wiringPi author and maybe I’ll get a definitive answer soon. Hopefully, he’ll tell me how to do what I need within the constraints of library as it currently works or he’ll add that feature.

Or maybe someone here on the Xojo forum has already cracked this nut. I hope so.

-Wes

Tim H.,

I though about using a pointer to a MemoryBlock but without a way to specify how much data is in the MemoryBlock the underlying function won’t know how much data to send.

Looking at the wiringPi source code, it appears that there is a particular version of I2C call that can be made where you provide a pointer to a data structure as the payload instead of a byte or integer using the I2C_SMBUS_BLOCK_DATA option.

In this scenario, the first byte of the payload contains the length of the data structure. This would address the issue of knowing how much data is being passed in the payload. But the currently defined wiringPi functions

wiringPiI2CWrite(int fd, int data);
wiringPiI2CWriteReg8(int fd, int reg, int data);
wiringPiI2CWriteReg16(int fd, int reg, int data);

don’t appear to use the I2C_SMBUS_BLOCK_DATA option. If I’m reading the C code correctly (and I may not be) it looks like the above functions are receiving the int data on the stack instead of as pointers to the data. So passing a pointer into these functions wouldn’t work as desired.

I may be way off base with all of this. I’ve been messing with this issue for two days now and I’m pretty tired. I probably should step away and try again later.

-Wes

The C code you posted uses the equivalent of a memoryblock. It’s essentially a structure, and the function knows how much to expect.

From what I’ve read, the setup call returns a file descriptor.
You should be able to create a BinaryStream using the fd returned.
Then a standard write should work.
Assign your data to a string, then something like this:

dim b as BinaryStream(fd, binarystream.HandleTypeFileNumber) b.Write(data)
should write multiple bytes at once.
I’ve used wiringPI, but not the I2C parts so this is not tested.

I managed to get the problem handled and now I can read and write 5 byte data blocks to and from the TEA5767.

I just want to say thank you to Tim S. for jogging my stalled thought process, Tim H. for suggesting the use of memory blocks and John for providing the idea of writing to the file descriptor.

This is essentially the code did the trick for me:

  Dim mbRadioOut As MemoryBlock
  Dim fdRadio As Integer
  Dim bsRadio As BinaryStream
		
  mbRadioOut = New MemoryBlock(5)

  ' Initialize the radio.
  '
  mbRadioOut.Int8Value(0) = Integer.FromBinary("10101001")
  mbRadioOut.Int8Value(1) = Integer.FromBinary("11010100") 
  mbRadioOut.Int8Value(2) = Integer.FromBinary("10110000")
  mbRadioOut.Int8Value(3) = Integer.FromBinary("00010000") 
  mbRadioOut.Int8Value(4) = Integer.FromBinary("00000000")
		
  ' Get file descriptor of radio.
  '
  fdRadio = GPIO.I2CSetup(&h60)
		
  ' Open a binary stream to the radio.
  '
  bsRadio = New BinaryStream(fdRadio,BinaryStream.HandleTypeFileNumber)
		
  ' Write data to radio.
  '
  bsRadio.Write(mbRadioOut)

Reading the data from the radio was essentially the reverse of the above.

This is a GREAT forum, with FANTABULOUS people!
Glad you got it working!

Tim

Aside from a few cranky folk, this is a great group
I’ve discovered many hints and suggestions here
and it’s nice to be able to help others move forward.

[quote=331982:@Tim Seyfarth]This is a GREAT forum, with FANTABULOUS people!
Glad you got it working!

Tim[/quote]

Wes, your solution helped me make progress with reading and writing to a Sensiron SHT31D humidity sensor on I2C. But only for one read/write cycle. After that there is no further response until I quit the app and try again. If, while my software is still running but not getting a response, I interrogate it with a simple Python program, it responds. Hmmm.

Did you get yours working for several read/write cycles, or just the one?

Did you close the binaryStream each time?

cheers,
Richard

For anybody interested, I found the solution:

  1. make the binaryStream limited in scope to a write-only command, or a write/read cycle.
  2. at the start of the scope, do i2cSetup as well as assigning the binaryStream to the filedescriptor.
  3. at the end of the scope close it.

Hope this helps anybody finding this thread.,

cheers,
Richard

PS: I didn’t use read or write into a memory block, but used the appropriate uint8 and uint16 methods.