I2C issues on SLX45
Added by Conor O almost 12 years ago
Just one or two questions on the I2C ngc module. The industrialio_top.vhd example code uses a generic map to set clock rates. This seems out of sync with the MityDSP_L138_pkg.vhd package file which has no such maps. So I left them out. I also assume you cannot set the i2c clock rate then. It seems to default to 200kHz according to my oscilloscope which is rather an odd frequency. A clock divide of 256 would seem to indicate a clock of 400kHz.
Anyway, I instantiated the i2c using a SLX45 and pins 702.7 (H14) for SDA and 702.8 (H13) for SCL in the ucf file and these defines:
constant CORE_I2C_MODULE : integer := 2; constant CORE_I2C_IRQ_LEVEL : integer := 0; constant CORE_I2C_IRQ_VECTOR : integer := 1;
I'm using the kernel and drivers from MDK_2012-08-10 by the way. Modprobe seems to be happy with fpga_i2c and I can use i2cdetect to scan the bus. However i2cdetect seems to think there's a device at every address when I have just one - a temperature probe at 0x4F. Removing the probe and using just pull ups on sda/scl gives the same result.
Am I missing something? I don't think there's anything else hanging off pins 7 and 8 that would interfere. I have a FPGA GPIO and FPGA UART as well, both of which work fine.
Thanks, Conor.
Replies (17)
RE: I2C issues on SLX45 - Added by Michael Williamson almost 12 years ago
Hello Conor,
For the I2C, you are correct, the generics in the TOP were a carry over from a previous port -- should have caught that. The core is consistent with the package file, and the clock rate is controlled via a software programmable register, however in the driver, around line 411, it is just getting set to a fixed value (the register is a divisor for the EMIFA clock, the value is divided by 2 in the core, so it's 256 setting is only 128). I had set it to 200 KHz mostly because it wasn't clear if the EMIFA would ever exceed 100 MHz. Should really revisit that.
Can you scope the lines? I don't see any source of interference either.
Are you using external pull ups? To 3.3?
-Mike
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
Thanks Mike. Sure it was evident the generics shouldn't be there and if they are it won't synthesise so it's not much a problem. I see the frequency set and the TODO! - makes more sense in the driver I guess. 200KHz is fine actually - it's well within the margin of the device I'm using and now that you've pointed it out I can change it at will. Also I've just checked my setup on the normal ARM i2c and that works ok.
I'm using 10k resistors on an little interface board and 10k on the temperature probe so that makes 5k pull ups on both SDA and SCL. I scoped the lines a bit earlier - it's a bit hard to catch the data but the lines are going up and down. Rather rounded but... I'll try again tomorrow and see can I understand this Agilent scope a bit better in order to get a picture. Um. J702 is right beside the buck regulator inductors - I'm using wire connections and I'm not sure did I run the clock line right over them. I can't imagine that would help much...
I tried running i2cdetect with nothing connected at all and it still shows devices at every address. It's quite slow too. Rather odd - it's as if releasing SDA makes it low, thus looking like an ACK to the driver.
I'll also try moving the ucf pin associations just in case.
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
Oh and 5K pull ups are to 3.3V on pin J701.38. SDA/SCL read 3.3V, at least on power on they do...
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
Hi again. It looks like the fpga is doing the right thing but the rise times are just too slow. Er. I guess that's my fault - should I lower the resistor values somewhat? I've captured the scope outputs from the ARM i2c bus and the FPGA i2c bus for comparison. That's a simple empty write to 0x4F - that's what the i2cdetect routine does (somewhat boneheadedly in my opinion, doing an empty write is really dangerous on SMBus eeproms which can interpret the Write differently).
Conor.
i2c_arm.png (22.5 KB) i2c_arm.png | i2c captures from the ARM bus | ||
i2c_fpga.png (26.2 KB) i2c_fpga.png | i2c captures from the FPGA bus |
RE: I2C issues on SLX45 - Added by Michael Williamson almost 12 years ago
Hi Conor,
What are you using for drive strength on the FPGA? You might be able to lower the drive strength if there is capacitance on the lines, but yeah, I would try a lower pullup value.
I am wondering if the I2C driver is not handling ACK timeouts properly (in terms of passing the error back up the stack to the calling application) and this is why the i2cdetect is showing valid data on the other addresses.
Also, the I2C core currently does not support client clock pausing/extension -- you may have figured that out from the fact that the clock is not a tristated output. I know there are some thermistors that tend to do that, hopefully you aren't using one of those.
If you are still having trouble after you tighten up the edges let me know.
-Mike
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
(Busy writing reports instead of doing the work the reports are about!)
For drive strength I was using the Xilinx defaults - I'd never even thought about them before. According to Planahead, the SDA and SCL pins are drive strength 12. I see that's in milliamps which seems awful high! I could try lowering that by... a lot I guess. I'm not sure it should have any effect on the SDA line on its own but the SCL line seems to be adversely affecting the SDA line - the hi-lo SCL transition is dragging the SDA line down with it.
Meanwhile I decoupled the 3.3V supply a bit more just in case and used 4k resistors as pull ups (which is standard for one slave - I have nothing on the bus at all at the moment). Exactly the same waveform as before. There might indeed be a driver issue as there is a mention of ack error in the .h file but no reference in the .c file (that's not much of an analysis on my part really).
I saw that the i2c clock didn't support stretching when I read the pkg file. I had already typed "inout stdlogic" and then went "oh.." I added a quick note to the fpga core docs wiki page just now, just in case others don't see it.
I'll try lowering the i2c clock frequency to 100 and dropping the drive strength to 6 and see what I can come up with.
Conor.
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
I dropped the drive strength to 6 on the SCL and SDA lines and it makes a slight difference - not so much ground bounce. The signals looks okish but communication is unreliable - almost as if the SDA read is being done right on the edge of SCL instead of, say, the middle (?). Plus i2cdetect shows devices where there are none - this does appear to be a driver issue. Using:
i2cget -y 2 0x4F 0x05 b
to read a byte from address register 5 on i2c device 0x4F results in 0xA1 (a correct Ident for the NXP SE95 temperature probe I'm using). Sometimes. Every second read results in a wrong number!
I'll leave it for now as the MityDSP provides an i2c bus on the industrial i/o board and another on the module itself - I'll be moving to module only eventually. So I don't actually need it really!
RE: I2C issues on SLX45 - Added by Michael Williamson almost 12 years ago
Hi Connor.
I think we may have found the issue. There may be a bug in the linux driver.
If you are OK recompiling the FPGA drivers on linux, can you please apply the following patch and see if the problems clear?
There was a modification to the FPGA I2C core to support 10 bit addressing and longer block transfers. The "done" flag was converted to a write-1-to-clear. Looks like the DSP Driver got the correct logic but this was missed in the linux drivers. The result is that you may be returning from the I/O call prior to the transaction actually completing. We are testing this here as well but I wanted to throw this out there if you have a chance and want to try it.
-Mike
(UPDATED - 12/17/2012)
CSR.msBits.mb10Bit = 0; CSR.msBits.mbRnW = 1; CSR.msBits.mbStop = stop; + CSR.msBits.mbDone = 1; CSR.msBits.mbGo = 1; lpBaseReg[gnCSR_OFFSET] = CSR.mnWord; wmb(); @@ -110,7 +111,7 @@ }; if (slp_cnt > 250) { - dev_err(dev, "Timeout on write request\n"); + dev_dbg(dev, "Timeout on write request\n"); return -EIO; } @@ -153,11 +154,14 @@ CSR.msBits.mb10Bit = 0; CSR.msBits.mbRnW = 0; CSR.msBits.mbStop = stop; + CSR.msBits.mbDone = 1; CSR.msBits.mbGo = 1; lpBaseReg[gnCSR_OFFSET] = CSR.mnWord; wmb(); /* wait until done */ + CSR.mnWord = lpBaseReg[gnCSR_OFFSET]; + while (!CSR.msBits.mbDone) { msleep(1); rmb(); @@ -167,11 +171,18 @@ }; if (slp_cnt > 250) { - dev_err(dev, "Timeout on write request\n"); + dev_dbg(dev, "Timeout on write request\n"); return -EIO; } } + /** check status for ack errors, etc. */ + CSR.mnWord = lpBaseReg[gnCSR_OFFSET]; + if (CSR.msBits.mbAckErr) { + dev_dbg(dev, "Ack Error\n"); + return -EIO; + } + dev_dbg(dev, "transfer returning %d\n", msg->len); return msg->len; } @@ -205,7 +216,7 @@ dev_dbg(dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num, ret); if (ret < 0) { - dev_err(dev, "Failed to transfer message : %d\n", ret); + dev_dbg(dev, "Failed to transfer message : %d\n", ret); return ret; } }
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
Thanks Mike, I looked at the driver code but wasn't really familiar enough with it to help. I was suspicious something was wrong codewise as the i2c driver was returning nonsense on the first read and then perfectly valid information on the second read which was really odd.
I'll try the patch as soon as I get a chance and see how I get on. I reverted to the OMAP i2c interface for testing and that works fine...
The "done" flag was converted to a write-1-to-clear.
That's a killer - I've done that myself, change something in one codebase and not in the other. Leads to hard-to-find bugs.
Conor.
RE: I2C issues on SLX45 - Added by Michael Williamson almost 12 years ago
Hi Conor,
I am updateing (via editing) the patch on the previous post. We've finished some testing here and found a couple other bugs that should be cleaned up.
- Missed an additional read of that pesky done bit.
- Added a return code for the NO ACK condition to allow things like i2cdetect to work properly.
I am very sorry for the inconvenience. (we are looking at better regression testing on the FPGA cores and drivers here as a result of this).
-Mike
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
No worries Mike. I used to be a QA guy so I must have a knack for finding these things! Like communicating with a non-existent device. I'd just finished doing the make so I made those changes and did make again. I'll add -DDEBUG in case anything interesting pops up and I'll test it again a bit later.
Thanks for all the debugging on this,
Conor.
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
Scratch that - I see -DDEBUG is in the Makefile
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
Hi guys. Got a chance to test this today. That's a lot better! The i2cdetect scan picks up the device and shows "--" on non-existant devices just like it should. My i2ctemperature program reads out the ID and temperature properly now too. I'm running it at 200kHz with 3.3k pullups and it seems fine and stable at those speeds.
I tried it on a much more complex program that writes to an OLED. The initialisation works fine - it's a whole bunch of commands, one after the other, but it does fail on the line writes which are greater than 32 bytes (Error is: "fpga_i2c 2: Msg Transfer Message Length too big, 49"). I must try it on the OMAP i2c interface to check...
Oh wait, I see the driver code has a TODO on that bit - gotcha!
I'm not sure whether a 32 byte limit is supposed to be a limit in the i2c device interface spec. The i2c-dev.h headers (http://kernel.org/doc/Documentation/i2c/dev-interface) certainly limit the macro read and write lengths to 32 bytes. (ie: i2c_smbus_*). However I'm using standard write() calls to /dev/i2c-2 to write 49 bytes at a go - the OLED line length is 48 bytes + 1 control byte. I'd say few enough people do what I'm doing though.
But hey, it works now. Thanks for all the effort Mike.
Cheers,
Conor.
RE: I2C issues on SLX45 - Added by Conor O almost 12 years ago
Further - I broke my OLED writes into < 32 bytes each and retested. That works fine and if it was unreliable, the pictures would show corruption which they don't. I can live with that! Thanks Mike.
I guess there two things for future though:
- greater than 32 byte writes (which noone except me will probably use but hey...)
- speed increases. For 200kHz, the writes are very slow. I'm doing 192 consecutive 25 byte writes (4.8K) and it takes 5.76 seconds. The i2cdetect scan takes a lot longer than it should do as well. I believe you might be waiting too long (1 millisecond) in the poll for CSR.msBits.mbDone as, in theory, a whole 32 byte write + address should take less than 2ms total.
But hey - driving an LCD off I2C isn't exactly a super idea to begin with and I'll move to SPI for that later. The important thing is that the normal non-lunatic i2c devices work.
Conor.
RE: I2C issues on SLX45 - Added by Michele Canepa over 11 years ago
Hello All,
Can you please tell me if your patch about I2C FPGA linux driver is available and working?
If yes, can you please provide a sort of explaination about the exact steps to apply it to the MDK_2012-08-10 release?
Have you succeded in implementing a working configuration on hardware side (driver strenght, pullups)? Have you got suggestions about that?
This is because I need to implement an I2C controller on FPGA, and so I would like some suggestion on how avoiding the Conor inconvenience.
Naturally, I really appreciate the efforts of Conor and Micheal about that, and I thank you all!
Best regards,
Michele Canepa
RE: I2C issues on SLX45 - Added by Conor O over 11 years ago
Wow, this is a while ago. If I remember correctly the FPGA i2c driver functioned correctly after Mike's changes but, in my opinion, it was a little unoptimised. But that was for my specific app which wanted to push a lot of data across i2c fairly briskly (an LCD). For normal stuff it should be fine. I've moved to a carrier board design so I have i2c available from the 2 ports.
I patched the file manually from Mike's diffs, I still have it so I'll find it and attach it when I get a second. It's the linux driver that's patched, not the FPGA code so it's pretty straightforward - drop in file, make.
Conor.
RE: I2C issues on SLX45 - Added by Conor O over 11 years ago
Patched file is:
MDK/sw/ARM/linux/drivers/fpga/fpga_i2c.c
attached...
fpga_i2c.c (9.12 KB) fpga_i2c.c |