Configuring I2C communication - TDA9950 HDMI CEC

I'm making an application and I need to communicate with my TV via HDMI CEC.
At first I'm testing an IC called TDA9950 from NXP. It is an HDMI CEC to I2C BUS converter.

TDA9950 DATASHEET

I'm having difficulties setting up and starting communication.
Could someone help me giving an opinion analyzing my code sequence? I think it is necessary check the datasheet to check....
I'm try check in the serial monitor messages received.

#include <Wire.h>

void Read_TDA9950(){
  Wire.beginTransmission(0x34); // TDA9950 ADDRESS 0x34
  Wire.write(0x00); // Send WRITE "0"
  Wire.write(0x07); // Register 0x07 - REG_CDR
  Wire.endTransmission(false); // re-start
  Wire.write(0xFF); // Send READ "1"
  Wire.endTransmission();  
  Wire.requestFrom(0x34,7, true); 
  int a = Wire.read();
  Serial.println(a);
}

void Config_TDA9950(){
  Wire.beginTransmission(0x34);
  Wire.write(0x00); // Send WRITE "0"
  Wire.write(0x04); // Register 0x04 - REG_ACKH
  Wire.write(0x00);  // ACKH 00h
  Wire.write(0x20); // ACKL 20h (5 HDMI 1.3a)
  Wire.endTransmission();
  
  Wire.beginTransmission(0x34);
  Wire.write(0x00); // Send WRITE "0"
  Wire.write(0x03); // Register 0x03 - REG_CCR
  Wire.write(0x40); // Set TDA9950 ON
  Wire.endTransmission();
  delay(10);
}

void Reset_TDA9950(){
  Wire.beginTransmission(0x34);
  Wire.write(0x00); // Send WRITE "0"
  Wire.write(0x03); // Register 0x03 - REG_CCR
  Wire.write(0x80); // Reset TDA9950
  Wire.endTransmission();
  delay(10);
}

void setup() {
  Wire.begin();
  Serial.begin(9600);
  pinMode(11,INPUT); // INT PIN FROM TDA9950
  Config_TDA9950();
}

void loop() {

 Read_TDA9950();
 delay(500);
 
}

In the TV I can't show nothing in the serial port and de INT pin of TDA9950 never change to high.

Thanks all

For any I2C device the first thing I do is run the I2C scanner. It can be found in an Arduino that you have to add.
Go to Library Manager and search for "I2C Scanner" It will come up a few libraries down from the top.

I use this program every time I attach an device to my Arduino. In the past I've spent too much time troubleshooting code only to find the devices isn't communicating.

The program will Scan through all the I2C addresses and list the addresses of any device properly communicating over the I2C bus.

Hey JohnRob, thanks!!

You are right! I tested the I2C SCAN to confirm the address and communication. I think the hardware it is fine.

Works fine!! And was possible confirm the address 0x34. I use the A1 and A2 in the ground

I think have some configuration missing... I don't know..

When I change the HDMI source and turn off/on the television, I receive data in the serial monitor... But I can't receive any other message from HDMI like buttons from remote control.

I will try more and if I can't do that, I will change to HDMI CEC library for Arduino already. The guys implement a library to read CEC line directly in the I/O of Atmega.

I try this IC because have the I2C bus and interruption when the message is ready. In my mind sounds more easily.. But don't worked hahaha

You are using the Wire library in a way that is not allowed.

Can you remember this:

  • The Wire.beginTransmission() does not start something on the bus.
  • The Wire.write() does not write something to the bus.
  • The Wire.endTransmission() may not be used on its own to stop something.

Writing data is always with these three functions in this order: "beginTransmission - write - write - write - endTransmission"
See also my alternative explanation.

Normally, a I2C device has registers and a separate "register address" and any number of bytes can be read or written from any register with or without repeated start.
Instead of "register address", the TDA9950 datasheet calls that "address pointer" and it is a register itself. Very weird :roll_eyes:

Let's make things simple: Keep the "repeated start" for later, and ignore the special case where the status register can be called repeatedly without setting the register address.

Could you change your code and show the new sketch ?

Add a check before using the TDA9950:

Wire.beginTransmission(0x34);
int error = Wire.endtransmission();
if( error == 0)
{
  Serial.println( "Okay, the TDA9950 is on the bus");
}
else
{
  Serial.println( "Can not find the TDA9950 !");
}

Writing data is like this:

  Wire.beginTransmission(0x34);
  Wire.write(0x04);  // Register 0x04 - REG_ACKH
  Wire.write(0x00);  // ACKH 00h
  Wire.write(0x20);  // ACKL 20h (5 HDMI 1.3a)
  Wire.endTransmission();

If you request 7 bytes, then please read 7 bytes and print 7 bytes.

  Wire.beginTransmission(0x34); // TDA9950 ADDRESS 0x34
  Wire.write(0x07);             // Register 0x07 - REG_CDR
  Wire.endTransmission();

  Wire.requestFrom(0x34,7);
  for( int i=0; i<7; i++)
  {
    Serial.print( "0x");
    Serial.print( Wire.read(), HEX);
    Serial.print( ", ");
  }
  Serial.println();

Koepel, thanks! I just implement your code and the result is the same. But is better than before. Your code it is really the correct form.

Thanks!

So..

Initializing, confirm TDA is on the BUS
image

After than, in the loop I put the function to receive from I2C.
The point is. I receive everytime 0 to the first bit and 0xFF for another.

image

When I change the HDMI source in the TV, I receive some data, like this:

image

When I turn OFF or turn ON the television, I also receive another data.

image

I'm monitoring the INT port and always is LOW. The datasheet of TDA9950 says when the message is ready, the INT pinout will be asserted

image

I just receive like datasheet say. 0x00 and 0xFFH.

That is it I can't receive nothing because don't have nothing to receive when I press some buttons in my remote control.

I think have another point to configure missing... and I can't find what..

I will search more about HDMI CEC comunication.. sometimes I need send a message to the television.

In this case, I need create the function to send message to try.. And I cannot undesrstand how I can write it.

What is the best way to check the point in yellow?

Like:

if (CSR[7]) { // IF CSR[7] == HIGH, OK, WRITE IT!
//code write here
}

Many thanks!

I just write the code as the datasheet show...

Check it... It is right?

void Write_TDA9950(){
  Wire.beginTransmission(0x34); //  0x34 - TDA9950
  Wire.write(0x00); // SET ADDRESS POINTER - 0x00 - CSR
  Wire.endTransmission(); // CLOSE
  Wire.requestFrom(0x34,7, true); 
  
  CSR = Wire.read();
  do {
    CSR = Wire.read();
    if (bitRead(CSR,7)==1) // CHECK bit 7 OF CSR. WHEN IS HIGH, BREAK
      break;
    delay(10);
  } while (1);

  Wire.beginTransmission(0x34); //  0x34 - TDA9950
  Wire.write(0x07); // SET ADDRESS POINTER 0x07 - CDR
  Wire.write(0x04);
  Wire.write(0x00); // CECDATA.req
  Wire.write(0x40); // AddressByte = DVD/TV
  Wire.write(0x0D); // DataByte = <TextView On> - Details HDMI V1.3a
  Wire.endTransmission(); // CLOSE

  CSR = Wire.read();
  do {
    CSR = Wire.read();
    if (bitRead(CSR,6)==1) // CHECK bit 6 OF CSR. WHEN IS HIGH, BREAK. It is possible check the INT output PIN
      break;
    delay(10);
  } while (1);

  Wire.beginTransmission(0x34); // 0x34 - TDA9950
  Wire.write(0x07); // SET ADDRESS POINTER 0x07 - CDR
  Wire.endTransmission(); // CLOSE

  Wire.requestFrom(0x34,7, true); 

  for( int i=0; i<7; i++)
  {
    Serial.print( "0x");
    Serial.print( Wire.read(), HEX);
    Serial.print( ", ");
  }
  Serial.println();
}

Thanks!

Maybe this is over your head. I'm not sure if you can do this.
The datasheet is confusing, it seems to be written by a trainee on his/her first day. I assume that the chip behaves like a standard I2C device with a few extras. If I read the datasheet with that in mind, then it slowly starts to make sense.

Could you read my alternative explanation once more ?
Could you check my code once more ? You kept your old code.

I would like to see a full sketch.

To read the status byte from 0x00 "CSR", you request 7 bytes with this:

Wire.requestFrom(0x34,7, true);

It is your code, you must know why you want to have 7 bytes.
The third parameter is not really used. You can remove the third parameter.

This is not what I showed:

  Wire.beginTransmission(0x34);
  Wire.write(0x00); // Send WRITE "0"
  Wire.write(0x04); // Register 0x04 - REG_ACKH

In the code that I showed, I send the register address (pointer address) of 0x04 after the Wire.beginTransmission(). I don't write "0". That is also not in the datasheet.

You still do that here as well:

  Wire.beginTransmission(0x34);
  Wire.write(0x00); // Send WRITE "0"

I think the first while-loop is okay, waiting for the INT bit. The second one uses CSR = Wire.read() without setting the register address (address pointer) to 0x00 first.
You already use the advanced possibility to read the status by setting the register address (address pointer) just once. You don't have to do that, you may set the register address every time.

Almost every library and sketch has a function to write a number of bytes and to read a number of bytes when dealing with a sensor or other I2C device.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.