v21-i2c

The I2C mode in Bus Pirate firmware prior to v2.1 has a major deficiency, an upgrade to v2.1-RC2 or later is highly recommended.

The Bus Pirate I2C library underwent major changes between v2.0 and v2.1. We added a hardware I2C mode, and squashed a huge bug in the way the Bus Pirate reads from devices and scans for addresses on the I2C bus. This guide details the updated I2C library.

Software and Hardware I2C modes

I2C has a new configuration option that selects between software or hardware I2C mode.

HiZ>m<<<open the mode menu
1. HiZ

4. I2C

(1) >4<<<choose I2C mode
MODE SET
I2C mode:
1. Software
2. Hardware
(1) >1<<<select software I2C
Set speed:
1. Slow(~5KHz)
2. Fast(~50KHz)
(1) >1<<<choose software I2C speed
I2C READY
I2C>

Software I2C mode uses a new public domain bit-bang library. The centralized bit-bang functions provide all software libraries with a speed option (~5KHz and ~50KHz).

MODE SET
I2C mode:
1. Software
2. Hardware
(1) >2<<<select hardware I2C
WARNING: Hardware I2C is broken on this PIC! (REV A3)<<<warning
Set speed:
1. 100KHz
2. 400KHz
3. 1MHz
(1) >2<<<choose hardware I2C speed
HARDWARE I2C READY
I2C>

We added a hardware I2C mode for PICs that support it. PICs prior to revision B4 have a flaky I2C module, a warning is displayed if you use the hardware option on a broken chip. Some have reported success using the hardware I2C library on revision 3 hardware.

I2C address search scanner update

Some chips produced ghost addresses during a search. We updated the search routine to read a byte and send a NACK bit if the detected address is a read address. Searches now appear to be rock solid.

I2C>(1)<<<search for I2C addresses
Searching 7bit I2C address space.
Found devices at:
0xD0(0x68W) 0xD1(0x68R)
I2C>

Here’s the new address scanner layout. In addition to the raw bus byte addresses (0xd0, 0xd1), the scanner now displays the 7bit I2C (R) and write (W) addresses. It’ll be easier to line up the output with a datasheet or logic analyzer, without manually converting the addresses.

ACK/NACK management, major bug fix

These examples read and write from the RAM of a DS1307 RTC chip.

I2C> [ 0xd1 rrrr]
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES<<<read address
READ: 0x07 ACK <<<sent ACK[
READ: 0x06 ACK
READ: 0x05 ACK
READ: 0x04 NACK <<<last read before STOP,  sent NACK
I2C STOP CONDITION
I2C>

The new I2C library doesn’t ACK/NACK a read operation until the next command. If the next command is a STOP (or START) the Bus Pirate sends a NACK bit. On all other commands it sends an ACK bit. The terminal output displays the (N)ACK status.

Nothing changes for write commands because the slave ACKs to the Bus Pirate during writes.

I2C> [0xd1 r:5]
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>

Here’s an example using the bulk read command (r:5).

I2C>[0xd1 r <<<setup and read one byte
I2C START CONDITION
WRITE: 0xD1 GOT ACK: YES
READ: 0x07 *(N)ACK PENDING <<<no ACK sent yet
I2C>r<<<read another byte
ACK <<<ACK for previous byte
READ: 0x06 *(N)ACK PENDING <<<no ACK yet
I2C>] <<<STOP command
NACK <<<next command is STOP, so NACK
I2C STOP CONDITION
I2C>

A consequence of the delayed ACK/NACK system is that partial transactions will leave read operations incomplete.

Here, we setup a read operation ([0xd1) and read a byte (r). Since the Bus Pirate has no way of knowing if the next operation will be another read (r) or a stop condition (]), it leaves the ninth bit hanging. The warning “*(N)ACK PENDING” alerts you to this state.

Our next command is another read (r), so the Bus Pirate ACKs the previous read and gets another byte. Again, it leaves the (N)ACK bit pending until the next command.

The final command is STOP (]). The Bus Pirate ends the read with a NACK and then sends the stop condition.

Incident analysis

There were several large bugs in the Bus Pirate I2C library prior to version 2.1, so we thought a debriefing was in order.

i2cbug.ii

Prior to firmware v2.1, the Bus Pirate used a GPL I2C library from outside the project. Our implementation of the library always acknowledged byte reads with a low bit called an ACK (top transaction). The I2C specification, however, requires that the final byte read should be ‘not acknowledged’ with a high bit called a NACK (bottom transaction). When the slave sees the NACK bit it stops sending data.

All I2C slave chips are supposed to shut down when they see a STOP condition on the I2C pins. Even though the old firmware ACKed every byte, the STOP signal should shut down the chip anyway. However, if the slave is sending data during a read operation, and the first bit is 0, then it can’t see the STOP signal because the bus is busy. This is called bus contention.

There’s several reasons we didn’t catch this bug sooner. First, the method outlined above actually works for many chips because of chance bit-order or bus contention detection features. Second, our short demonstrations usually involved a single read operation at their conclusion, so we never saw the problems that were revealed with extended use.

The new delayed (N)ACK method should work fine for every chip we’ve tested or demoed in the past. It might have issues if there’s protocols that switch reads and writes between START ([) and STOP (]) bits, but we’re not aware of anything that does this.

The address scanner ghosting was related to the read NACK problem. 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 there’s sometimes an extra address after the read address during an address search. When we send the read address, the chip clocks out 8bits before it gets a NACK on the final byte.

Advertisements