I2C Timeout

Discussion to talk about software related topics only.
Post Reply
hector
Posts: 14
Joined: Mon Sep 06, 2010 6:16 am

I2C Timeout

Post by hector »

Hi Netburners,

I'm currently developing a NB application that communicates with a touch display connected via I2C to the 5270 board.
Unfortunately I'm not able to read/write data from/to the display. Here's my source code:

Code: Select all

int Hardware::ControlUnit::TouchDisplay::eDIPTFT43A::sendToDisplay(int length, char *textToSend)
{
   BYTE readBuffer = 0x00;
   int ret = 1;

   this->i2cCommunication->initialize(0x00, 0x0E); // = I2CInit(0x00, 0x0E);

   this->i2cCommunication->start(0x10, I2C_START_WRITE, 20);    // Start I²C in order to write (= I2CStart(0x10, I2C_START_WRITE, 20);)
   this->i2cCommunication->send(0x11, 2); // Send display start byte (= I2CSend(0x11, 2);)
   this->i2cCommunication->send(length, 2); // Data length (= I2CSend(0x11, 2);)
   this->i2cCommunication->sendString(length, textToSend, 20); // Text to send

   // Restart I²C in order to read
   this->i2cCommunication->restart(0x10, I2C_START_READ, 2);

   if (this->i2cCommunication->read(readBuffer, 2) == 1)
   {
       if (readBuffer == EDIP_ACK) // = Acknowledge from display
       {
           ret = 0;
       }
   }

   this->i2cCommunication->stop(); // = I2CStop();

   return ret;
}

The return value from the I2CStart call is 1 (= I2C_NEXT_WRITE_OK ( 1 ) // I2C bus is OK for a write). The following (first) I2CSend call
returns a 5 (= I2C_BUS_NOT_AVAIL ( 5 ) // A timeout occured while trying gain I2C bus control). I've connected a logic analyzer to see if there goes out any data
onto the bus. Nothing is being transmitted. :?

Regards
v8dave
Posts: 333
Joined: Thu Dec 31, 2009 8:31 pm

Re: I2C Timeout

Post by v8dave »

Hi there,

Is this you own custom board and if so, do you have you got PULLUPS (1K) on the bus lines? The Netburner module itself is not terminated. If you are using the DEV board, it has the 1K pullups fitted.


Which IO lines are you connected to? Are they the correct way around?

Regards
Dave...
hector
Posts: 14
Joined: Mon Sep 06, 2010 6:16 am

Re: I2C Timeout

Post by hector »

v8dave wrote: Is this you own custom board and if so, do you have you got PULLUPS (1K) on the bus lines?
Yes, a custom board. We got the pullup resistors on the bus lines.

Our main problem is the fact, that we are using the board with the 2.24 release for the first time.
Our other projects were developed using the 1.98 release, where the I2C implementation was
obviously a different one. The old one works with our custom board, the new one doesn't.

Code: Select all

this->i2cCommunication->initialize(0x0, 0x0E);   
this->i2cCommunication->sendBuffer(0x10, (PBYTE)textToSend, strlen(textToSend), false);
If I use the SendBuffer method instead I get a I2C_NO_LINK_RX_ACK ( 9 ) (// We are in Master TX mode and recieved no ACK from slave device, possibly during start).

Regards
User avatar
lgitlitz
Posts: 331
Joined: Wed Apr 23, 2008 11:43 am
Location: San Diego, CA
Contact:

Re: I2C Timeout

Post by lgitlitz »

The I2C driver is independent of all other system code besides the real time clock driver (rtc.cpp). You should be able to replace the existing driver with the old one. You could actually just put the old one in your project.

You are using the i2cmaster.h version of the I2C driver, correct? Why does the initialize have two parameters, the master driver only has a single baud parameter? Neither the 0x0 or the 0xE parameter would work for the baud rate as it is too fast. If you do not include a parameter then the default parameter will be used for the standard 100kbit.

If you are not able to communicate at all you should set up an I2C test loop in your code that scans through all the possible addresses. Take a look at the following two threads for sample code:
http://forum.embeddedethernet.com/viewt ... ?f=5&t=730
http://forum.embeddedethernet.com/viewt ... ?f=5&t=784
It would also be a good idea to possibly jumper over wires to the I2C bus on a NetBurner dev-board. That way you can see the the RTC responds to its address and you can rule out a hardware problem on your bus lines.

-Larry
hector
Posts: 14
Joined: Mon Sep 06, 2010 6:16 am

Re: I2C Timeout

Post by hector »

lgitlitz wrote: You are using the i2cmaster.h version of the I2C driver, correct? Why does the initialize have two parameters, the master driver only has a single baud parameter? Neither the 0x0 or the 0xE parameter would work for the baud rate as it is too fast. If you do not include a parameter then the default parameter will be used for the standard 100kbit.
I am using the i2cmulti.h version of the driver. According to the runtime documentation the function takes two parameters:

Code: Select all

void I2CInit(BYTE slave_Addr = 0x08, BYTE freqdiv = 0x11); 
The 0x0 is the slave address and the 0xE frequency divider. I applied these values from the old implementation, where the I2C worked fine.
lgitlitz wrote: If you are not able to communicate at all you should set up an I2C test loop in your code that scans through all the possible addresses. Take a look at the following two threads for sample code:
I've tried that. One out of twenty attempts I receive three addresses (0x0, 0x8, 0x68). The other nineteen times I get nothing back from the bus. Maybe a timing problem? Weird...

*edit*

I finally receive some addresses (0x0, 0x68) using the following code:

Code: Select all

I2CInit(0xE);

for( int x =0; x<128; x++)
{
   I2CInit(0xE);
   int e = I2CStart(x, I2C_START_READ);
   
   if( e < I2C_TIMEOUT )
      iprintf("We have a %X on the bus\r\n", x );
   else
      //iprintf("%X not found\n", x);

   I2CStop();
}

iprintf("Detection done\n");
If I try to access the bus with the following code:

Code: Select all

I2CInit(0xE);
BYTE b = I2CStart(0, I2C_START_WRITE);
iprintf("%X\n", b);
b = I2CSend(2);
iprintf("%X\n", b);
I2CStop();
...I receive result = 1 (I2C_NEXT_WRITE_OK ( 1 ) // I2C bus is OK for a write) from
I2CStart and 9 (I2C_NO_LINK_RX_ACK ( 9 ) // We are in Master TX mode and
recieved no ACK from slave device, possibly during start) from I2CSend.
v8dave
Posts: 333
Joined: Thu Dec 31, 2009 8:31 pm

Re: I2C Timeout

Post by v8dave »

hector wrote:If I try to access the bus with the following code:

Code: Select all

I2CInit(0xE);
BYTE b = I2CStart(0, I2C_START_WRITE);
iprintf("%X\n", b);
b = I2CSend(2);
iprintf("%X\n", b);
I2CStop();
You are using an address of ZERO. Is this correct? This seems very unlikely for an I2C device.

Be careful with the addresses used by the module. They do not include the READ/WRITE bit and this can often lead to using a value that is LEFT shifted by 1.

Do you have a datasheet for the device you are using?
hector
Posts: 14
Joined: Mon Sep 06, 2010 6:16 am

Re: I2C Timeout

Post by hector »

v8dave wrote: You are using an address of ZERO. Is this correct? This seems very unlikely for an I2C device.
Ahh, no it's not correct, my fault...The device itself has the address 0x10. The I2C is being initialized used the frequency divider of 0xE.
I replaced the address in I2CStart by 0x10. Still receiving 9 as return value. I still can't see anything on the bus (via logic analyzer). It seems as
there is a problem with the bus initialization.
v8dave wrote: Do you have a datasheet for the device you are using?
http://www.lcd-module.de/eng/pdf/grafik ... t43-ae.pdf
v8dave
Posts: 333
Joined: Thu Dec 31, 2009 8:31 pm

Re: I2C Timeout

Post by v8dave »

OK. Assuming you have TIED the SA0, SA1 and SA2 lines low, then the internal address is indeed 0x10. If you left these open, they are pulled high so check this.

Actually for the NB code it will be 0x08 (0x10 divided by 2). The reason for this is that the address is shifted LEFT 1 bit to account for the R/W bit. The address expected by the NB code is this non-shifted address.

I fell into this trap the very first time I used the NB with I2C.

It still don't explain why your search test did not find something at this address. In fact, if I look through your note below I see that there is something at 0x68. This would be SA0, 1 and 2 all high, IE, left open. This when shifted left would be 0xD0, being the last address in the datasheet on page 7.

With this info I think you might get it working if you use 0x68 as your working address.

Good luck and post back your results.

Dave...
hector
Posts: 14
Joined: Mon Sep 06, 2010 6:16 am

Re: I2C Timeout

Post by hector »

Guys, I'm going postal over here. The I2CStart/I2CSend-Calls are returning whether 0 (= I2C_OK) or 1 (= I2C_NEXT_WRITE_OK), but I'm not
able to see anything going over the bus lines (via logic analyzer). I've tested the logic analyser with the old implementation (containing the
fully functional old I2C part (1.98)). He instantly registered the outgoing data without any problems.

Code: Select all

int Hardware::ControlUnit::TouchDisplay::eDIPTFT43A::sendToDisplay(int length, char *textToSend)
{
   BYTE readBuffer = 0x00;
   int ret = 1;
   int rc = -1;

   // Initialize the eDIP display
   this->i2cCommunication->initialize(0x0, 0x0E);
   this->i2cCommunication->stop();

   // Start I²C in order to write
   rc = this->i2cCommunication->start(0x68, I2C_START_WRITE, 20);
   iprintf("\nStart RC = %X\n", rc);

   // Send the DC1 command
   rc = this->i2cCommunication->send(0x11, 2);
   this->checksum = 0x11;
   iprintf("Send DC1 RC = %X\n", rc);

   // Send the data byte count
   rc = this->i2cCommunication->send(length, 2);
   this->checksum += length;
   iprintf("Send Length RC = %X\n", rc);

   // Send the actual data bytes
   char *pointerToDataByte = textToSend;
   for (int i = 0; i < length; i++)
   {
	rc = this->i2cCommunication->send(pointerToDataByte[0], WAITTICKS_RTC);
	iprintf("Send data RC = %X\n", rc);
	this->checksum += pointerToDataByte[0];
	pointerToDataByte++;
   }

   // Calculate the eDIP checksum 
   this->checksum = this->checksum % 256;

   // Send the eDIP checksum
   rc = this->i2cCommunication->send(this->checksum, 2);
   iprintf("Send checksum RC = %X\n", rc);

   // Restart I²C in order to read
   rc = this->i2cCommunication->restart(0x68, I2C_START_READ, 2);
   iprintf("Restart RC = %X\n", rc);

   // Read from the I²C bus and check if the display acknowledged our previous transmission
   if (this->i2cCommunication->read(readBuffer, 2) == 1)
   {
      if (readBuffer == EDIP_ACK)
      {
         ret = 0;
      }
   }

   // Send a I²C stop
   this->i2cCommunication->stop();

   return ret;
}
User avatar
lgitlitz
Posts: 331
Joined: Wed Apr 23, 2008 11:43 am
Location: San Diego, CA
Contact:

Re: I2C Timeout

Post by lgitlitz »

So with the exact same hardware you can swap between the 1.98 version and the new version and only the new version fails? If this is the case why not just drop in the 1.98 I2C driver in the new build to see if it works?

The 0xE baud rate is about 400kbit. While I have gotten this to work with some devices I definitely suggest you go back to the default 100kbit baud until you get this working, this is the max speed rating for the I2C peripheral by Freescale. Also the LCD has a minimum voltage of 3V for its minimum logic high voltage since it is a 5V part. This is close to the 3.3V that pulls up the I2C bus. Depending on the bus speed and capacitance you may get glitching if the 3V threshold is not reached for a segment of the transmission.

The NetBurner module is not 5V tolerant and you should only have pull-up resistors tied to the 3.3V rail. You must make sure that there are no 5V signals being driven into the NetBurner as this will eventually burn out the pin's input driver. The real way to go 3.3->5 on I2C is with a special I2C level translator. They cost less then a $1 on Digikey.

So for the I2C driver, if you are not ever addressing the NetBurner as a slave device then you should just use the i2cmaster driver. This is pretty much the same driver but with all the slave mode and bus arbitration code removed. Assigning the NetBurner to address 0x0 is not a good idea as this is considered the broadcast address for many I2C devices. v8dave is also correct about his comment with the address lines. Do you have BA0, BA1, BA2, SA0, SA1 and SA2 all tied to ground? If so you should be addressing 0x8 not 0x10. The I2C address is only 7-bits as to their specification, the least significant bit of the data sent during a start is for direction.
Post Reply