Skip to main content
Topic: I2C, no ACK at random times (Read 21676 times) previous topic - next topic

Re: I2C, no ACK at random times

Reply #15
I tried sending the same write over and over again.
The first write (which came after a read) didn't work properly, but afterwards, no problems anymore.

I'm not 100% sure if I understand your explanation about the 18F afterwards (with the double "0").

Still wonder if the problem is just with me or not..

Code: [Select]
I2C>[0xd0 1 [0xd1 r]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x01 GOT ACK: NO
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
READ: 0x54
I2C STOP CONDITION
I2C>[0xd0 1 0]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x01 GOT ACK: NO
WRITE: 0x00 GOT ACK: NO
I2C STOP CONDITION
I2C>[0xd0 1 0]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x01 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION
I2C>[0xd0 1 0]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x01 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION
I2C>[0xd0 1 0]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x01 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION
I2C>[0xd0 1 0]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x01 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION

Re: I2C, no ACK at random times

Reply #16
Sorry if I wasn't clear, here's what I'm talking about:

Quote
I2C> { 0x52 0x00 0x65 } Write 2 bytes to the PIC at address 0x52, starting at internal address 0x00
I2C START CONDITION
WRITE: 0x52 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
WRITE: 0x65 GOT ACK: YES
WRITE: 0x66 GOT ACK: YES
I2C STOP CONDITION
I2C> { 0x52 0x00 } { 0x53 r r } Write internal address to 0x00, then read two bytes
I2C START CONDITION
WRITE: 0x52 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION
I2C START CONDITION
WRITE: 0x53 GOT ACK: YES
READ: 0x65
READ: 0x66
I2C STOP CONDITION
I2C>

This was the test I was running before. It works up to this point. If I follow this up with other commands, the device doesn't respond properly and continues each command as a read as observed by a dump of the internal I2C registers to an LCD on the PIC18F. It stays stuck (no stop rx'd) until I send a command that ends in 0's:

Quote
I2C> { 0x52 0x00 0x00 }
I2C START CONDITION
WRITE: 0x52 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION
I2C>

After this, I can write to the internal registers and start another read cycle. I'm not 100% sure where the bug is (in my PIC18F code or in the bus pirate) but it should be pretty obvious once I get the Logic Analyzer attached.

On a side note, I2C on PIC is harder than it initially appears. :)

Re: I2C, no ACK at random times

Reply #17
As you'll note on your LA, the byes come in squirts while the terminal waits to push characters through the serial port. That could also be a potential issue.

There's a three byte UART hardware buffer, but the long term goal (on the issue tracker) is to have a big buffer (2000K?) that feeds the serial TX on an interrupt.
Got a question? Please ask in the forum for the fastest answers.

Re: I2C, no ACK at random times

Reply #18
I got a sample DS307 from Fozzy Vis today. Here's my attempt to interface it with the new hardware I2C module:

Quote
HWI2C>W
POWER SUPPLIES ON
HWI2C>p
 1. Pullup off
 2. Pullup on
(1) >2
PULLUP RESISTORS ON
HWI2C>v
VOLTAGE MONITOR: 5V: 4.9 | 3.3V: 3.3 | VPULLUP: 5.0 |
HWI2C>(1)
Searching 7bit I2C address space.
   Found devices at:
0xD0 0xD1
HWI2C>

Turn on the power supplies, turn on the pull-up resistors, check that voltages are OK, search for I2C address.
Datasheet page 12 says the slave address is 1101000x where x is R/W. 0b11010000=0xd0, so success!

Quote
HWI2C>[0xd0 0 0]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION
HWI2C>[0xd0 0]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION
HWI2C>[0xd1 r:8]
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
BULK READ 0x08 BYTES:
0x00 0x00 0x00 0x01 0x01 0x01 0x00 0x03
I2C STOP CONDITION
HWI2C>

I reset the Clock Halt (CH) bit of byte 0 to 0, enabling the clock. I then set the read/write pointer to 0 and read the 8 time-related bytes.

Quote
HWI2C>[0xd1 0x8 3 2 1]
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
WRITE: 0x03 GOT ACK: YES
WRITE: 0x02 GOT ACK: YES
WRITE: 0x01 GOT ACK: YES
I2C STOP CONDITION
HWI2C>[0xd1 0x8]
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
I2C STOP CONDITION
HWI2C>[0xd0 r:3]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
BULK READ 0x03 BYTES:

Next I wrote three bytes (3 2 1) to the RAM addresses 0x8+. Unfortunately, when I read it back the Bus Pirate freezes waiting for a reply.


So, now I'll try it with the software library at high speed.

Quote
HiZ>m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. JTAG
7. RAW2WIRE
8. RAW3WIRE
9. PC KEYBOARD
10. MIDI
11. LCD
12. HWI2C
(1) >4
MODE SET
Set speed:
 1. Slow(~5KHz)
 2. Fast(~50KHz)
SPEED>(1) >2
I2C routines Copyright (C) 2000 Michael Pearce
Released under GNU GPL
I2C READY
I2C>W
POWER SUPPLIES ON
I2C>p
 1. Pullup off
 2. Pullup on
(1) >2
PULLUP RESISTORS ON
I2C>(1)
Searching 7bit I2C address space.
   Found devices at:
0xD0 0xD1
I2C>

Good so far...

Quote
I2C>[0xd0 0 0]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION
I2C>[0xd0 0]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x00 GOT ACK: YES
I2C STOP CONDITION
I2C>[0xd1 r:8]
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
BULK READ 0x08 BYTES:
0x00 0x00 0x00 0x01 0x01 0x01 0x00 0x03
I2C STOP CONDITION
I2C>

Write 0 to CH bit, then reset read/write pointer and read the 8 clock-related bytes.

Quote
I2C>[0xd0 0x8]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
I2C STOP CONDITION
I2C>[0xd0 0x8 1 3 3 7 ]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
WRITE: 0x01 GOT ACK: YES
WRITE: 0x03 GOT ACK: YES
WRITE: 0x03 GOT ACK: YES
WRITE: 0x07 GOT ACK: YES
I2C STOP CONDITION
I2C>[0xd0 0x08]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
I2C STOP CONDITION
I2C>[0xd1 r:4]
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
BULK READ 0x04 BYTES:
0x01 0x03 0x03 0x07
I2C STOP CONDITION
I2C>

Now, set to ram 0x08, write 1 3 3 7, read it back. All worked OK.

Quote
I2C>[0xd0 0x08 [ 0xd1 r:4]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
BULK READ 0x04 BYTES:
0x40 0x01 0x01 0x01
I2C STOP CONDITION
I2C>

If I try a repeated start like you did, I get the wrong data. Don't know who sent what, I'll have to drag out the LA to be sure. I'm almost certain it's a problem with the library.

Quote
I2C>[0xd0 0x08] [0xd1 r:4]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
I2C STOP CONDITION
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
BULK READ 0x04 BYTES:
0x20 0x01 0x00 0x90
I2C STOP CONDITION
I2C>[0xd0 0x08] [0xd1 r:4]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: NO
WRITE: 0x08 GOT ACK: NO
I2C STOP CONDITION
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
BULK READ 0x04 BYTES:
0x00 0x00 0x01 0x25
I2C STOP CONDITION
I2C>

I tried several ways to read everything in a single command, including with a delay (&:255). First time I just got the wrong values, the second time I had an ACK problem like you experienced.

For now, try read and write commands in seperate entries. In the long term, it looks like there's a bug in SW I2C and a timeout is needed in the HW I2C.
Got a question? Please ask in the forum for the fastest answers.

Re: I2C, no ACK at random times

Reply #19
Found a minor non-problem...

The SW I2C routine is one of two pieces of GPL code in the Bus Pirate. It came with a uS delay routine that used a signed const char as the variable type. For some reason I never migrated it to the bpDelayUS function shared by all other libraries. This wasn't actually a source of a problem because all the I2C delays are less than 128, I initially thought I solved it though. I migrated it anyway, maybe it will be more reliable.

New nightly for v2go with cleaned up delays and terminal I/O is in the SVN.
Got a question? Please ask in the forum for the fastest answers.

Re: I2C, no ACK at random times

Reply #20
I think I've found another problem, while reading the specs and some sites about I2C. I've noticed that your software implementation doesn't send a NACK after reading the last byte.

On this site, it suggests that's a requirement:
http://www.robot-electronics.co.uk/htm/ ... 2c_bus.htm

I've decided to rewrite the software I2C routines using the outline on this website. The size of the code drops by about 250 bytes with my new routines and they'll be licensed the same way as the rest of the BP code, which is nice. I've been busy over the weekend and didn't have time to test the code, but will have a chance in the evening tonight. Once I'm sure it's okay, I'll post the diff and hopefully we'll have something working properly.

Re: I2C, no ACK at random times

Reply #21
That's fantastic. I'd thought about doing it, but I'm so familiar with the old code that I don't think I could make a non-infringing version.

After reading the page I'm not sure if the SW library does clock stretching, which could also be a problem. It should probably have a timeout.

For NACKing the last byte, I'm not sure. I think it just signals the slave the TX is over, which the stop condition also does. The NACK ends the read high, so SDA still needs to go low again before the stop condition can happen. We can try some tests with the raw2wire library. [] also create I2C style start/stop pulses in that library, and the ack can be simulated by setting the ACK (_) or NACK (-) and doing a clock tick (^).
Got a question? Please ask in the forum for the fastest answers.

It's ugly, really ugly

Reply #22
I used a Saleae Logic to look at the signals. It's not pretty.

All my tests used the search for device ID macro, I didn't bother to look at anything else.

With the software I2C my first search for device scan works fine, but then I always get an extra device (0xd2) on subsequent searches (as noted also by Fozzy Vis):

Quote
I2C>(1)
Searching 7bit I2C address space.
   Found devices at:
0xD0 0xD1
I2C>(1)
Searching 7bit I2C address space.
   Found devices at:
0xD0 0xD1 0xD2
I2C>

On the first scan (T3) it works, but you can see in the waveform that there's no proper stop condition for the NOACK addresses. On the second time through there's a bunch of garbage for two bytes after the first two addresses which causes the 0xd2 ACK (T4).

I looked at the I2C code and noticed that the getack() function just exists and doesn't complete the clock cycle if there's no ack. I changed this and tried again with prettier, but no more successful results (T6 first try, T7 second try).

My first thought is to go through and make sure every function starts and stops with the proper bus state, etc. But there's no point in doing that to the GPL code if you're going to post a patch to replace it.

*0x68 + W/R = 0xd0/0xd1
Got a question? Please ask in the forum for the fastest answers.

Re: I2C, no ACK at random times

Reply #23
Sorry, I've been kind of busy with work and haven't had time to figure out what's not working with my I2C code (with open drains turned on, it seems to always hold the line low, even if the tristate shouldn't be allowing that). I'll hopefully get a chance next week, but I can't promise anything right now.

Sorry again!

 

Re: I2C, no ACK at random times

Reply #24
No problem, today is the first chance I've had to get out the logic analyzer.

In my experience the open drain pin only works for outputs, the OD configured pin won't work as an input until you clear the open drain bit. It's easier to set PORT to ground and then switch TRIS.
Got a question? Please ask in the forum for the fastest answers.

Re: I2C, no ACK at random times

Reply #25
I wrote my own I2C routines using the public domain pseudo code posted here:
http://www.esacademy.com/faq/i2c/general/i2cpseud.htm

They're not great, just enough to play with. I think I'm going to make a base library of bitbang commands to share among all the software libraries (1-wire, I2c, raw2/3wire, JTAG, LCD).

The address scanner problem is this: when the address scanner sends a read address some chips go immediately into read mode and create bus contention that prevents us from making the stop condition. That's why it's always an extra address after the read address, we send the read address and then the chips clocks out 8bits before it gets a NACK on the final byte. You can see it happen in the attached LA output.

Couple solutions:
1. Just scan write addresses, read address can be inferred as +1. But what about hidden read-only ports?
2. Change current search to send 0 and then NACK when it gets an ACK on a read address.
3. Variations on the above themes.

I've implemented #2, it's rock stable so far (second image below).

Quote
I2C>(1)
Searching 7bit I2C address space.
   Found devices at:
0xD0 0xD1
I2C>(1)
Searching 7bit I2C address space.
   Found devices at:
0xD0 0xD1
I2C>(1)
Searching 7bit I2C address space.
   Found devices at:
0xD0 0xD1
I2C>(1)

I am open to other suggestions. I'd eventually like to display the 7bit I2C base address as well as the raw read/write address so it's consistent with my logic analyzer.

Now I'm going to implement the rest of the new library and see if I can clear up the other issues.
Got a question? Please ask in the forum for the fastest answers.

Re: I2C, no ACK at random times

Reply #26
This should solve the problem with reads on the DS1307. I've uploaded the latest compile to SVN, but I'm going to test all the changes and release as 2.1RC1 since this was such a huge bug.

These examples read and write from the DS1307 RAM located at 0x08 to 0x3f.

Quote
I2C>[0xd0 8 7 6 5 4 3 2 1 ]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
WRITE: 0x07 GOT ACK: YES
WRITE: 0x06 GOT ACK: YES
WRITE: 0x05 GOT ACK: YES
WRITE: 0x04 GOT ACK: YES
WRITE: 0x03 GOT ACK: YES
WRITE: 0x02 GOT ACK: YES
WRITE: 0x01 GOT ACK: YES
I2C STOP CONDITION
I2C>[0xd0 8 [ 0xd1 rrrr]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
READ: 0x07 ACK <<
READ: 0x06 ACK
READ: 0x05 ACK
READ: 0x04 NACK <<
I2C STOP CONDITION
I2C>

The I2C library now uses a delayed ACK/NACK on reads. When I2C reads begin, the Bus Pirate won't issue a (N)ACK until the next operation. If the next operation is a stop (or start in case of repeated starts) the Bus Pirate sends a NACK on the 9th bit. On all other operations it sends an ACK. This doesn't effect writes where the slave ACKs to the Bus Pirate. The terminal output now shows the (N)ACK status.

Quote
I2C>[0xd0 8 [0xd1 r
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
READ: 0x07 *(N)ACK PENDING <<
I2C>r
 ACK <<
READ: 0x06 *(N)ACK PENDING <<
I2C>r
 ACK
READ: 0x05 *(N)ACK PENDING
I2C>r
 ACK
READ: 0x04 *(N)ACK PENDING
I2C>]
 NACK <<
I2C STOP CONDITION
I2C>

If you leave a read without an additional operation, then the read isn't complete because the 9th bit (ACK) hasn't been sent. The Bus Pirate will warn you of this.

This should work fine for every chip I've tested or demoed in the past. It might have issues if there's protocols that switch reads and writes between START ([) and STOP (]) statements, but I'm not aware of anything that does this.

I've moved all the software library bitbang functions to bitbang.c, and adapted the I2c, raw2/3wire, and LCD libraries to share them. 1-wire and Jtag will also be added eventually. All software libraries now have a speed option, for the moment only low speed is tested, high speed seems to have some unresolved timing issues.

EDIT: Also works for bulk reads.
Quote
I2C>[0xd0 8 [0xd1 r:5]
I2C START CONDITION
WRITE: 0xD0 GOT ACK: YES
WRITE: 0x08 GOT ACK: YES
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
BULK READ 0x05 BYTES:
0x07 ACK 0x06 ACK 0x05 ACK 0x04 ACK 0x03 NACK
I2C STOP CONDITION
I2C>
Got a question? Please ask in the forum for the fastest answers.

Re: I2C, no ACK at random times

Reply #27
Release candidate info and link. Please let me know if this helps.
Got a question? Please ask in the forum for the fastest answers.

Re: I2C, no ACK at random times

Reply #28
Here's a full update guide and "incident analysis" of the I2C problem.
Got a question? Please ask in the forum for the fastest answers.

Re: I2C, no ACK at random times

Reply #29
I finally posted a demonstration of this chip:
http://dangerousprototypes.com/2009/09/ ... ime-clock/
Got a question? Please ask in the forum for the fastest answers.