- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi all,
I am trying to implement the I2C protocol (master side) on an EPM570 CPLD. I am new to VHDL so I am having trouble finding the errors of my code. Basically the code is working, I can see the communication using a scope. The problem is that the data that I get from the slave (AD7151 - Capacitance Converter for Proximity Sensing) doesn't match its spec - for example the 4 last bits of the 16-bit data register are supposed to be constantly '0' but they change all the time. I suspect that the problem is with the "read" packet (maybe timing or something) since the "write" packets work fine. I am using a 32.768kHz clock for the CPLD and the protocol uses the same clock divided by 2. The code is attached (some parts are irrelevant since I am posting only the communication implementation) Thanks a lotLink Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What you will need to think about is the clock edge that is latching each data bit into the FPGA.
I am assuming your external device will drive data out on a rising edge of the clock. If you then latch read data internal to the FPGA on the same edge then depending on your FPGA timing/external interface timing you may or may not latch the correct data. For example if the period from clock rising to you latching data inside the FPGA is less than the time taken from Clock rising to the External part driving data + the transmission delay back to the FPGA then the data latched will be incorrect. I am not an I2C expert so am not 100% sure that the the rd/wr data is driven on the rising edge but it is worth taking a look at. Look at the timing diagrams of your analog devices part and try and work out what will happen Hope this helps- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@ vernmid
Thanks for the reply. As far as I know, the latching does take place on the rising edge. This is the reason that I am using a 16kHz clock for the communication while the process is triggered by a 32kHz clock - in this case I can change/sample the data line in the middle of the bit, avoiding race (hopefully). During the "write" sequence, I can see both the bits that I transmit and the ACKs from the device with proper timing. The problem is that when I try to read data from the device, it sends something different then defined in its spec, for example the zeroes that I mentioned earlier, which makes me think that I've done something wrong with the read process.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, sounds reasonable.
Have you verified that the Data relationship to the clock is OK in the FPGA to EPM570M100 direction? i.e. If the Analog part latches data in on the rising edge is there going to be a setup violation? This could happen if the data changes very close (or even before) the clock at the EPM570M100 inputs. Might be worth looking at the timings on your scope and checking the setup/hold times on the EPM570M100 datasheet.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I see in Quartus simulator, that SDA is changed simultaneously with rising SCL edge, which is not complying to the I2C specification. I see, that SDA is driven in push-pull mode. This may possibly work, but do you have also an SDA pullup resistor as required at least for data reception.
Generating a correct I2C timing requires more than two clock phases per bit. It may be, that the AD7151 tolerates some deviations from I2C specification, but would expect, that they tested the device with an I2C master following the standard, e. g. a uP with I2C interface.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@ vernmid:
The reason that I use a 16kHz clock for the I2C communication is so I can change the data on the falling edge and prevent race conditions. When I look at the communication with a scope, I see that it is well functioning during the "write" sequence. My problem is that during the "read" sequence, it acts differently though for my understanding I implemented it in the same way that I did with the "write" procedure. For example, after reading the second 8 bit register, I "miss" 1 clock (during that clock the data line goes high due to the pull-up resistor). I can't find the reason for that miss in the code. @ FvM: Could you explain more please? As I said earlier, I can see with the scope that the data changes on SCL falling edge, so that when the rising edge occurs, the data is already stable. You say that :"Generating a correct I2C timing requires more than two clock phases per bit". What exactly do you mean? Thanks- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I assumed, that you know the basic I2C timing specification, but I see, that this apparently isn't the case. See http://www.nxp.com/acrobat_download/usermanuals/um10204_3.pdf
Unlike SPI, it has SCL to SDA setup and hold times for both SCL edges.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I understand that. In my code both SCL and SDA work with 16kHz but they have a 180 deg. shift to each other. Isn't it enough?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Not according to the specification. Both SCL edges are significant in the slave logic. I don't have a HDL I2C code at hand, but usual uP software implementations have a delay after changing either SDA or SCL. This would be the basic method for a HDL implementation (usually based on a fast system clock): Have a state machine and a delay timer.
A very simple (but typically undocumented and somewhat cryptic Verilog I2C master code) can be found with the Terasic DE2 demonstrations. Also opencores.org has some I2C projects, but possibly more complex than necessary for your application.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi all,
I managed to implement the protocol. You were right, my problem was with the timing. I did a little trick in order to implement it with only 2 clock phases per bit. I divided the main clock by 2 using the falling edge as a trigger. I used the resulting clock for the SCL line. In another process I've implemented the communication on the SDA line while it used the main clock divided by 2 with its rising edge as a trigger. Thus, all of the protocol's timing requirements were met. It came out a little "ugly" in some places, but it works well. Thanks for all the help.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page