sniffing i2c with the BusPirate

I received my BusPirate v4 a while ago, but didn’t really use it so far. That’s a cool analysis/debug tool for serial buses such as uart, spi, i2c and the like. For me i2c is the most interesting. From time to time, the communication doesn’t work as it should, and so far, I worked it out with trial and error. I hope the BusPirate can be of help in such situations in the future. So, here is my first test run.

The BusPirate is controlled through an uart textual interface:

minicom -D /dev/ttyACM1 -b 115200

When you connect to it, it performs a self test, and then you can choose the mode by entering m. In my case, that’s 4 for i2c. Next I get to choose between hardware and software. I don’t know the implications yet, but what I see is that hardware offers higher speeds, and locks up more often. Then I get to choose the bus speed. 100KHz is the standard. With ? you can always get a list of possible commands. (0) shows a list of available macros. (1) scans all possible addresses for connected devices, just like i2cdetect would do it on the computer. (2) finally is what I was after, that’s the i2c sniffer.

I was actually hoping it could find out why I’m having problems reading back a simple value from an AtMega8 to a RaspberyPi. The AtMega8 is at address 0x11 and the command to read the value is 0xA1. I verified with a serial connection to the AtMega8 that it has a proper value, but on the RaspberryPi I always get a 0. At least the command was received on the AVR as I could verify with the UART, but writing the value back is the problem. So here is what the sniffer outputs for the attempted read:

[[[][]][[[0x01+][0x04-[][[0x20+][[[[[][0x20-[][0x4C+][0x04-[][0x24+][0x20-][]]]

Let’s decipher those numbers. Plus means ACK and minus means NACK. Opening square bracked means start bit, and closing square bracket means stop bit. The expected sequence would be 0x22 (the address for sending to the AVR) 0xA1 (send back which value) 0x23 (the address for receiving from the AVR) 0x08 (or whatever value was stored on the AVR). But the above output doesn’t look like this at all. So, lets try to communicate from the BusPirate to the AVR directly. Here we go:

I2C>[0x22 0xa1] [0x23 r:1]                                                      
I2C START BIT                                                                   
WRITE: 0x22 ACK                                                                 
WRITE: 0xA1 ACK                                                                 
I2C STOP BIT                                                                    
I2C START BIT                                                                   
WRITE: 0x23 ACK                                                                 
READ: 0x00                                                                      
NACK                                                                            
I2C STOP BIT

Seems to reflect what I also observed from the RaspberryPi. So, I tried to sniff a simpler sequence from the RaspberryPi:   0xa3 0x01 and then 0xa3 0x00 sent to the AVR. This is for switching on and off a specific output transistor. And that’s the output from the sniffer:

[0x24-][0x04+[][0x24-[][0x44+]

Something seems to be off here. Somewhere I read that the i2c sniffer is only usable up to 70kHz. Standard i2c frequency is 100kHz and it’s not always easy to change. That would be a pitty, since i2c sniffing is the primary reason, I bought the BusPirate. Other sources indicate, i2c sniffing is usable up to 100kHz, which would be just what I need. In fact, the manual says “The I2C sniffer was updated in firmware v5.3, and the maximum speed increased from around 70kHz to around 100kHz.”. I just checked my device by hitting i, and here is what it reports:

Bus Pirate v4                                                                  
Firmware v6.1 r1676                                                            
DEVID:0x1019 REVID:0x0003 (24FJ256GB106 A5)                                    
http://dangerousprototypes.com

So, let’s sniff a communication that works better. In a former blog post I described how I read the value from a light sensitive resistor from the RaspberryPi through i2c from an AtTiny. The communication is almost the same as with the AtMega8 above. The address is 0x10, which translates to 0x20 and 0x21. The command to request the value is 0xC1. Here is what I get from the BusPirate:

Hardware 100kHz : [[]][0x20+][0x20+]][0x00-[]]]]
Hardware 100kHz : [0x20+[][0x20+][]]][]][[]]
Software 100kHz : [[][[0x00+][0x20+]][0x20-[][0x22+]]]
Software 100kHz : [0x20-[][0x40+][0x20+][0x20-[][0x22+]]

In both cases I got a correct value of about 120 at the RaspberryPi, but the sniffed data doesn’t look good at all. So lets again try to communicate directly from the BusPirate to the AtTiny:

I2C>[0x20 0xc1] [0x21 r:1]                                                     
Warning: *Short or no pull-up                                                  
I2C START BIT                                                                  
WRITE: 0x20 ACK                                                                
WRITE: 0xC1 ACK                                                                
I2C STOP BIT                                                                   
Warning: *Short or no pull-up                                                  
I2C START BIT                                                                  
WRITE: 0x21 ACK                                                                
READ: 0x00                                                                     
NACK                                                                           
I2C STOP BIT

Now, the read back value is wrong here as well, but at least I get a meaningful warning now. So far I assumed, the internal pullups were enough, But I added external resistors as well. After soldering in the resistors, the warning was still there. And even after enabling the internal pullups of the BusPirate, I still get this warning. I have to admit, I’m a bit disappointed with the device. It doesn’t seem to perform well on the task that that I bought it for. I didn’t give up on it yet, though.

Switching one more gear back, I grabbed the BlinkM that I frequently use to debug i2c. After going into the i2c mode in the BusPirate, I had to enable the power source for the BlinkM hitting the ‘W’ key. That switched the BlinkM on, and it came into it’s usual startup program. There is also a very elaborate description on how to test the BusPirate with a BlinkM. Stopping the startup script worked only after enabling the internal pullups:

I2C>[0x00 "o"]                                                                  
I2C START BIT                                                                   
WRITE: 0x00 ACK                                                                 
WRITE: "o ACK"                                                                  
I2C STOP BIT

Also reading a value from the BlinkM worked, but in the tutorial they use a different syntax from what I tried before:

I2C>[0x12 "a" {0x13 r]                                                          
I2C START BIT                                                                   
WRITE: 0x12 ACK                                                                 
WRITE: "a ACK"                                                                  
I2C START BIT                                                                   
WRITE: 0x13 ACK                                                                 
READ: 0x09                                                                      
NACK                                                                            
I2C STOP BIT

So, I used this syntax with the AtTiny, but it didn’t help:

5V on-board pullup voltage enabled
 I2C>[0x20 0xc1 {0x21 r]
 Warning: *Short or no pull-up
 I2C START BIT
 WRITE: 0x20 ACK
 WRITE: 0xC1 ACK
 Warning: *Short or no pull-up
 I2C START BIT
 WRITE: 0x21 ACK
 READ: 0x00
 NACK
 I2C STOP BIT

I get the impression, the AVR chips are a bit problematic as I2C slaves, or maybe my BusPirate from China is not as good as the original.

 

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *