This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi All,
Using the i2c_ex1_loopback example code, I'm not seeing how to receive data over I2C.
In loopback mode, the code operates as advertised. When I take it out of loopback mode, I don't see how it's getting data from the I2C receive buffer. I don't know if data is getting into the buffer.
Sending commands is not problem. I'm connected to a display, and all commands I send it are responding as expected, except for values that should be returning over I2C.
I'm getting the FIFO receive interrupts, so I thought I was getting data from the I2C bus, but all it ever presents is 0x00.
I know the display is working properly, because I have some Arduino example code that it's working with.
Here are my changes to the receive part of the ISR to grab a single byte of data:
// // I2C A Transmit & Receive FIFO ISR. // __interrupt void i2cFIFOISR(void) { uint16_t i; // // If receive FIFO interrupt flag is set, read data // if((I2C_getInterruptStatus(I2CA_BASE) & I2C_INT_RXFF) != 0) { uint16_t bytes_Received; bytes_Received = I2C_getRxFIFOStatus(I2CA_BASE); for(i = 0; i < 1; i++) { rData[i] = I2C_getData(I2CA_BASE); if(rData[i] != 0) { bytes_Received = bytes_Received + 1; bytes_Received = bytes_Received - 1; } DEVICE_DELAY_US(10); } // // Clear interrupt flag // I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_RXFF); Example_PassCount++; }
What I see coming in is a copy of what I'm sending out. The DLB bit is cleared, so I don't think the I2CDRR register is getting the outgoing data loaded internally. Here's the register setup:
I suspect I'm not getting the registers setup properly. Let me know what you'd like to see, and I'll gladly oblige.
Can you please point me in the right direction?
Thanks,
robin
Robin,
In digital loop back mode, data transmitted out of I2CDXR registers are directly received in I2CDRR register through internal path. Disabling DLB, you disconnect this path and will not receive the data transmitted on I2CDXR.
If you're looking for an example code where you want to have two I2C talking to eachother like in real application, you need to use i2c_ex3_external_loopback example code available in
Path:<C2000Ware>\driverlib\f2837xd\examples\cpu1\i2c
Example project:i2c_ex3_external_loopback
In this example code, you connect I2CA and I2CB externally
Regards,
Manoj
Thanks for the quick response Manoj.
I understand that by disabling DLB, I2CDXR xmit data won't be internally passed into the I2CDRR. But I thought the I2CDRR would pick up I2C bus responses from the peripheral display that it's communicating with. I expected them to be passed into the FIFO receive buffer where they could be retrieved by my code.
Sending a command from the MASTER_SEND_MODE TMS320F28379D to the display should trigger an I2C response from that display. It's most likely causing that response to occur, but the I2C hardware/software of the TMS320F28379D doesn't seem to be picking it up.
FIFO receive interrupts are occurring, but the data in the receive buffer is only ever one of two values:
I will look over the i2c_ex3_external_loopback example code again. Maybe I'll find some configuration there that doesn't exist in my modified version of the I2c_ex1_loopback example.
I'd greatly appreciate it if you could help me understand the flow of how a slave response is received by the I2C port on the TMS320F28379D. There are a lot of configuration options, and I suspect I may have overlooked (or misunderstood) one or more settings.
All help is very much appreciated.
robin
Robin,
Have you tried probing I2C bus? Do you see any valid data on it? Also, what display are you trying to interface with I2C?
Regards,
Manoj
If possible please share logic analyzer (or) oscilloscope snapshots?
Regards,
Manoj
Hi Minoj,
The display is eGTT50A from Matrix Orbital. It has an I2C interface that only carries commands from the MCU master (in this case the TMS320F28379D) to the slave (eGTT50A), and responses from the slave display back to the master MCU. All the heavy lifting regarding drawing graphics and text, and deciphering touch screen operations are handled inside the display module. In the grand scheme of things, there is very little communication between the two.
From the Matrix Orbital manual, here's the MCU master's request for a value embedded in the display's registers that indicate the module type: (0x28-write 0xfe 0x37)
And here's the expected response from the slave display to that request for module type: (0x28-read 0xfc 0x37 0x00 0x02 0x93 0x10)
Here's a scope image of clock and data signals: (appx. 50kHz clock rate)
Here are logic analyzer images of the correctly working, complete transaction on the Arduino connected system: (I2c address = 0x28)
Here are the logic analyzer images of the failing transaction on the TMS320F28379D system:
The TMS320F28379D receives 0x00 into its I2CDRR ad infinitum.
I ran the i2c_ex3_external_loopback example code and found similar results. The unmodified code runs without failing, seemingly because the I2CDRR is filling with the data being put out through the I2CDXR register. Once I break that connection, and rely on the I2CDRR pulling slave data written on the I2C bus, the system stops receiving anything but 0x00.
I suppose I'm just missing a crucial piece of the puzzle, but I've read documentation over and over again, and I'm not seeing it.
Thanks for your help.
UPDATE
Hi Minoj,
After manipulating the I2C register configuration and where and when I pull data from the I2CDRR, I'm now receiving the data that the slave is transmitting.
However, the data being captured from the I2CDRR is losing its lsb. The lsb is there, but it's always zero. The data being transmitted through the I2CDXR is perfect. There's no lsb issue with transmitted data.
I know these results would lead one to believe the problem lies with the display sending the errant data, but the system works perfectly when using an Arduino Uno as the MCU instead of the TMS320F28379D.
I'm hoping this explanation will spark some new thoughts. Do you have any suggestions on what to check next?
Thanks,
robin
Robin,
1) Check whether I2CMDR.BC bitfield is configured 0 (or) 7? This I2CMDR.BC bit field control the number of bits to be transmitted (or) received by the I2C module.
I2CMDR.BC = 0 corresponds to 8 bits / data packet
I2CMDR.BC = 7 corresponds to 7 bits / data packet.
2)Are you waiting for Receive-data-ready interrupt bit (I2CSTR.RRDY = 1) to be set before reading I2CDRR register?
3) Is your logic analyzer reading your data packet (including LSB bits correctly bit correctly?
4) Possibility of VIL / VIH / rise time violation. Though highly unlikely would suggest you to check rise time? If your rise time is slow. Check the following:
Regards,
Manoj
Incorrectly pressed "TI thinks resolved". Don't worry this thread is still considered open
Hi Manoj,
Thanks for your response.
I've forwarded my modified version of i2c_ex1_loopback example code to Matrix Orbital, but I don't know how much they can help. They're not familiar with the C2000 series, and it's doubtful they'll be willing to spend significant time learning about the TMS320F28379D.
Thanks,
robin
Robin,
C2000 I2Cs support only upto 400 KHz. Is everything working around 400 KHz?
Regards,
Manoj
Did you try running I2C at 400 KHz? Is everything working as expected at 400 KHz?
Regards,
Manoj
Hi Manoj,
I made a new discovery.
Here’s what we already knew:
The lsb of each data byte was being mysteriously zeroed out. Here’s the series of I2C commands and replies that were expected versus what appeared in logic analyzer readouts:
Command: (Query Module Type)
0x28 W - 0xfe - 0x37
Expected Response:
0x28 R – 0xfc – 0x37 – 0x00 – 0x02 – 0x93 – 0x10
Actual Response:
0x28 R – 0xfc – 0x36 – 0x00 – 0x02 – 0x92 – 0x10
To corroborate the lsb theory, I sent this Command: (Query Module String)
0x28 W - 0xfe - 0x38
Expected Response:
0x28 R – 0xfc – 0x38 – 0x00 – 0x06 – 0x47 – 0x54 – 0x54 – 0x35 – 0x30 – 0x41
Actual Response:
0x28 R – 0xfc – 0x38 – 0x00 – 0x06 – 0x46 – 0x54 – 0x54 – 0x34 – 0x30 – 0x40
I sent other commands, all having the same problem of returning the lsb as zero. I’m convinced this phenomenon is consistent. I define it as: all data bytes being returned by the slave device will have zero at the lsb. Address bytes are not affected, only data bytes are affected.
Here are a couple of scope traces that zoom in on one of those erroneous data bytes: (should be 0x47, not 0x46)
And zoomed in further on the data byte:
And here’s the logic analyzer readout of the same byte:
Here’s what’s new:
I noticed that the lsb wasn’t being held as close to zero as the other bits in the returned data byte. I suspected it was because the MCU was taking it low, not the display. By adding a resistor in series with the data line (SDA), we’re able to see that the TI MCU (TMS320F28379D) is in fact taking SDA low during the lsb of the data byte. Since this data byte is being returned by the display, the MCU should be hands-off until the NACK has occurred.
I added a resistor in series with SDA, so I could determine precisely which device was taking the data line low. Here’s where I added the resistor:
Following is an image of scope traces. The blue trace is taken from the display side of the resistor, and the green trace is taken from the MCU side. The pullup resistors are at the display end of the I2C bus. Clearly, the MCU is driving SDA low, as is evidenced by the line not going as near ground in the blue trace. Here it is:
Finally:
So, the question is: “Why is the TI TMS320F28379D MCU taking the data line (SDA) low during the least significant bit of the data byte that is being returned by the display?”
It’s not because of the I2CMDR.BC setting. It’s always been set to zero, which means 8bits (not 7bits).
It’s not a problem with I2C clock speed. I now have the MCU clocking the SCL at ~113kHz. The display default speed is 115.2kHz. Anyway, the same problem exists at any reasonable speed.
I’m using the fifo receive interrupt to determine when to copy the I2CDRR contents. The transmit interrupt is disabled. I’m not waiting for the RRDY to be set. (Let me know if you think this could be a problem.)
I don’t think it’s an SCL or SDA rise-time issue. As seen in the scope images, the edges are pretty crisp. Here are close-up images: (fall-times are shorter)
SDA rise-time is ~46ns and SCL is ~38ns. SPRS880K spec’s max timing requirements as 300ns:
I appreciate your help.
Thanks,
robin
Robin,
I'm not sure. But, my guess is the problem is because of the minor timing difference between I2C slave (115 KHz) and I2C master (113 KHz). Can make sure to have both I2C master and slave are working at the same frequency?
Regards,
Manoj
Hi Manoj,
With I2C, clock speed is determined by the master. The slave will use the master's clock signal to clock in data. Speed matching is not necessary.
Here's a link with more info.
Thanks,
robin
Robin,
Well, unfortunately I have run of ideas what could be the possible reasons why this can happen without active hardware / scope infront me. I wouldn't doubt F28379D.I2C as this peripheral has been used by many of customer over the years without any issues.
Regards,
Manoj
Have you already tried running them at same speed (100 KHz) as suggested in previous post. I think it is worth a try.
Regards,
Manoj
Hi Manoj,
Yes, I dialed in the I2C clock to produce 115.2kHz, but exactly the same problem exists.
This is good:
All data is being transmitted by the F28379 perfectly, and the display is receiving it perfectly.
This is bad:
However, the F28379 is taking SDA low during the lsb of all data bytes received from the display.
Again, in different words, all data transmitted by the slave display is being corrupted by the F28379.
The F28379 is interfering with the display's control of SDA by taking SDA low during the lsb of the display's data.
The F28379 doesn't interfere with the display's address response, but it does interfere with all of the display's data responses.
Here's the image again, with some new info added in blue:
Please let me know if you don't completely understand the exact symptoms. I have it well defined, and am able to explain it further if needed.
I have no doubt that the TMS320F28379D is well capable of communicating properly over I2C. I don't fully understand all the various register settings and their effects. I need help from someone fluent in these operations. No doubt, I have something setup wrong. I'm using a fifo interrupt to determine when incoming data is available. I'm not using an interrupt for outgoing data.
Do you have a LaunchXL-F28379D and a peripheral device to communicate with? If you do, I'm happy to send you the code that I modified from the i2c_ex1_loopback example.
I'm also available via Skype to go through code and share screen images of code, logic analyzer, scope, etc..
I'm quickly approaching a deadline, and am feeling pressure to make progress. Please help.
Thanks,
robin
Robin,
Can you provide some insight into your hardware setup?
How have you configured GPIO pins for I2C? Please provide configuration details?
You can send across the modified example code. I can take a brief look into and see whether I see any glaring mistake.
Regards,
Manoj
Based on your description, it looks like you're having a problem when I2C is configured as master receiver. I want confirmation that display isn't pulling the LSB low. To do that, configure SDA pin as GPIO input pin before enter I2C master receiver mode. This way, F28379D.I2C pin doesn't control the SDA pin. If the LSB is pulled low, it is the display and not F28379D I2C.
Regards,
Manoj
Hi Manoj,
There is no series resistor on SCL or SDA lines.
There is one each 909 Ohm resistor pulling up to 3.3V on SCL and SDA at the slave end.
Here's a quick scheme:
Here's an image of my bench setup:
I2C ports assigned in the example code (GPIO32 and 33) aren't exposed to the user on the LaunchXL-F28379. I assigned GPIO 104 and 105 instead. Here's the assignment:
// // Initialize GPIOs 104 and 105 for use as SDA A and SCL A respectively // GPIO_setPinConfig(GPIO_104_SDAA); GPIO_setPadConfig(104, GPIO_PIN_TYPE_PULLUP); GPIO_setQualificationMode(104, GPIO_QUAL_ASYNC); GPIO_setPinConfig(GPIO_105_SCLA); GPIO_setPadConfig(105, GPIO_PIN_TYPE_PULLUP); GPIO_setQualificationMode(105, GPIO_QUAL_ASYNC);
Code to follow...
Thanks,
robin
Hi Manoj,
Attached is my modified i2c_ex1_loopback example code.
I tried adding code to change the SDA pin to a GPIO input during reads, but I can't get that to work. If it's not receiving data, it's not generating ACKs. Without ACKs, the data stream ends abruptly.
Instead I took another look at bus levels with a resistor in series with the SDA line. I'm very convinced it is the f28379 that is taking the SDA line low. Here's another look at it:
Here's how it works:
Scenario 1: Slave takes SDA to logic zero
The BLUE connection is made and the voltage level where the blue scope probe is connected goes to zero. The voltage level on the green scope probe goes to zero as well, because there's no pullup resistor at the master end of the bus.
Scenario 2: Master takes SDA to logic zero
The RED connection is made and the voltage level where the green scope probe is connected goes to zero. The voltage level on the blue scope probe is a bit above zero, due to the voltage divider caused by the 270 Ohm resistor in series with the 909 Ohm pullup resistor.
You would expect the voltage at the blue probe to be:
(270 / (270 + 909)) * 3.3V = 756mV
As can be seen in the image above, the difference between the green and blue scope traces is pretty close to 756mV.
This is pretty conclusive. If you want me to further experiment with it, let me know what you'd like to see.
I'm hoping you'll see something wrong with the attached code.
Thanks,
robin
Hi Manoj,
It's been a long day (month), and I'm a little loopy, but I think I found the problem.
In initialization, I set the I2COAR register to the same address as the slave.
I'll take a closer look in the morning, but I'm pretty sure that's it.
I'll let you know what I find out.
Thanks,
robin
Hi Manoj,
I've confirmed the final issue with my bidirectional I2C communications was that I had inadvertently assigned the same I2C address to both the master and slave.
As a result, responses from the slave (display) were being interfered with by unwanted responses from the master.
Thanks for your patient assistance.
robin