Discovering I2C with the Bus Pirate
I had a few I2C compatible sensor break-out-boards from sparkfun laying around in my project box. I intend to use them in a future series and they seemed like good test devices to interact with.
The first device is a TSL2561 Luminosity sensor. Skimming through the data sheet it has a default address of 0x39. I carefully study the pinout and the Bus Pirate wiring diagram to map out how I'm going to hook them up. The sensor has a 3v3, Gnd, SCL, and SDA pin. From the bus pirate I'll connect the 3.3V pin to the sensor's 3v3 pin with a red cable. Grounds will be connected with a brown wire. The Bus Pirate's CLOCK pin becomes SCL when in I2C mode, they will be connected with a Purple wire. The MOSI pin on the Bus Pirate will become SDA while in I2C mode, these will be connected with a Gray wire. I make these connections while the Bus Pirate is powered off (perhaps I should put that first.)
I power up the Bus Pirate and see the "HiZ," or Hi Impedance mode, prompt. This means that the pins aren't active yet, so one could safely hook things up while in this mode, but with my luck I chose to be cautions and hook them up un-powered.
First I check the voltages present on the lines:
HiZ>v Pinstates: 1.(BR) 2.(RD) 3.(OR) 4.(YW) 5.(GN) 6.(BL) 7.(PU) 8.(GR) 9.(WT) 0.(Blk) GND 3.3V 5.0V ADC VPU AUX CLK MOSI CS MISO P P P I I I I I I I GND 0.00V 0.00V 0.00V 0.00V L L L L L
Then I put the Bus Pirate into I2C mode:
HiZ>m 1. HiZ 2. 1-WIRE 3. UART 4. I2C 5. SPI 6. 2WIRE 7. 3WIRE 8. LCD x. exit(without change) (1)>4 Set speed: 1. ~5KHz 2. ~50KHz 3. ~100KHz 4. ~400KHz (1)>4 Ready I2C>
Note the I2C> prompt. Now I check voltages again:
I2C>v Pinstates: 1.(BR) 2.(RD) 3.(OR) 4.(YW) 5.(GN) 6.(BL) 7.(PU) 8.(GR) 9.(WT) 0.(Blk) GND 3.3V 5.0V ADC VPU AUX SCL SDA - - P P P I I I I I I I GND 0.00V 0.00V 0.00V 0.00V L L L L L
There's no change in voltage, but note how pins 7 and 8 are now labelled with I2C nomenclature. Let's bring up the power and see what happens:
I2C>W POWER SUPPLIES ON I2C>v Pinstates: 1.(BR) 2.(RD) 3.(OR) 4.(YW) 5.(GN) 6.(BL) 7.(PU) 8.(GR) 9.(WT) 0.(Blk) GND 3.3V 5.0V ADC VPU AUX SCL SDA - - P P P I I I I I I I GND 3.24V 5.00V 0.00V 0.00V L H H L L
Now we have voltage on the 3.3V line and the states of SCL and SDA have changed. Now let's see what is on the I2C bus. The Bus Pirate can run macros for you and there are some pre-made for I2C already. You can view what macros are available with "(0)".
I2C>(0) 0.Macro menu 1.7bit address search 2.I2C sniffer
I want to see what's on the bus, so we run the address search:
I2C>(1) Searching I2C address space. Found devices at: 0x72(0x39 W) 0x73(0x39 R)
Now, from the documentation we expected 0x39, what's up with the 0x72 and 0x73? Looking at the datasheet particularly Figure 14 on page 12, you see the setup of an I2C write command. There's the start bit, the 7-bit address 0x39 followed by a Wr or a R depending on if it's a write or read request. A write is a 0, and a read is a 1. In binary, 0x39 is 111001. That's 7 bits, so if you append the read or write bit you'll get 8-bits or a byte, which is where the 0x72 and 0x73 come from. Got it? It took me a while to catch on and I had to scribble out a few calculations before it sunk in for me.
Continue reading through the datasheet and you'll find that in order to get a reading from the chip you must first " issue a command to access the CONTROL register followed by the data value 03h to power up the device" from page 18. Huh? Skim back up and you'll find that after the address and the r/w bit, it's expecting a byte sized COMMAND registers (not to be confused with CONTROL.) Table 3 on page 13 shows how this is constructed. The first bit must be a 1, followed by three zeroes, and then 4 bits to identify the register. You'll find the register addresses in Table 2. So we have 1000 and then the address for the CONTROL register 000. 10000000 is 0x80.
So in order to instruct the device to start the ADC to take readings we'll enter the following into the Bus Pirate that will send a write command to address 0x39 storing 0x3 at register 0x0.
I2C>[0x72 0x80 0x03 [ 0x73 r ] I2C START BIT WRITE: 0x72 ACK WRITE: 0x80 ACK WRITE: 0x03 ACK I2C START BIT WRITE: 0x73 ACK READ: 0x03 NACK I2C STOP BIT
We followed the write with a read and want something that has the last 2 bits set, or a 0x03 in this case. Now we want to read what the sensor is reporting. To do that, we point the register to address 0x2C with a write command, and then read two bytes from there, the Least Significant Byte and the Most Significant Byte. 0x2C becomes 0xAC for the write command so a sample looks something like this:
I2C>[0x72 0xAC [0x73 r r ] I2C START BIT WRITE: 0x72 ACK WRITE: 0xAC ACK I2C START BIT WRITE: 0x73 ACK READ: 0x22 READ: ACK 0x00 NACK I2C STOP BIT
Where the reading is 0x00 0x22 in a dimly lit room. Or once again with more lights on.
I2C>[0x72 0xac [0x73 r r ] I2C START BIT WRITE: 0x72 ACK WRITE: 0xAC ACK I2C START BIT WRITE: 0x73 ACK READ: 0x26 READ: ACK 0x0D NACK I2C STOP BIT
Where it's reading 0x0D 0x26 for the sample.
Now, to back out of the session, I'll turn off the power supply, and change the mode back to HiZ, and check the voltages to be safe.
I2C>w POWER SUPPLIES OFF I2C>m 1. HiZ 2. 1-WIRE 3. UART 4. I2C 5. SPI 6. 2WIRE 7. 3WIRE 8. LCD x. exit(without change) (1)>1 Ready HiZ>v Pinstates: 1.(BR) 2.(RD) 3.(OR) 4.(YW) 5.(GN) 6.(BL) 7.(PU) 8.(GR) 9.(WT) 0.(Blk) GND 3.3V 5.0V ADC VPU AUX CLK MOSI CS MISO P P P I I I I I I I GND 0.00V 0.00V 0.00V 0.00V L L L L L
Now, I had a lot of help with this in the form of some sample code that happened to include some Bus Pirate-like syntax. If I want to see if I've really got it, let's try my luck on a different sensor: a TMP102 Temperature Sensor.
Skimming through the datasheet my guess is that I have to write to the device to point it to 0x00 for the temperature register and then read two bytes from the bus, MSB first, LSB second. let's see how this goes...
I plug in the pins while in HiZ mode, then I set it to I2C, enable power and check voltages.
HiZ>m 1. HiZ 2. 1-WIRE 3. UART 4. I2C 5. SPI 6. 2WIRE 7. 3WIRE 8. LCD x. exit(without change) (1)>4 Set speed: 1. ~5KHz 2. ~50KHz 3. ~100KHz 4. ~400KHz (1)>4 Ready I2C>v Pinstates: 1.(BR) 2.(RD) 3.(OR) 4.(YW) 5.(GN) 6.(BL) 7.(PU) 8.(GR) 9.(WT) 0.(Blk) GND 3.3V 5.0V ADC VPU AUX SCL SDA - - P P P I I I I I I I GND 0.00V 0.00V 0.00V 0.00V L L L L L I2C>W POWER SUPPLIES ON I2C>v Pinstates: 1.(BR) 2.(RD) 3.(OR) 4.(YW) 5.(GN) 6.(BL) 7.(PU) 8.(GR) 9.(WT) 0.(Blk) GND 3.3V 5.0V ADC VPU AUX SCL SDA - - P P P I I I I I I I GND 3.34V 5.00V 0.00V 0.00V L H H L L
Since SCL and SDA are now hi, I'm inferring that there are pull-up resistors present on the break out board for the sensor. Let's scan for addresses...
I2C>(1) Searching I2C address space. Found devices at: 0x00(0x00 W) 0x90(0x48 W) 0x91(0x48 R)
I'm confused by the unexpected 0x00 response, but I recall reading something in the docs on page 11 about it responding to a general call of all zeroes. So our device is 0x48. My guess is that if I enter something like [ 0x90 0x00 [ 0x91 r r ] I might get something.
I2C>[ 0x90 0x00 [ 0x91 r r ] I2C START BIT WRITE: 0x90 ACK WRITE: 0x00 ACK I2C START BIT WRITE: 0x91 ACK READ: 0x17 READ: ACK 0x30 NACK I2C STOP BIT
I do! What is it reporting to me?
So we have 0x17 and 0x30, we split those out...
0x17 0x30 0001 0111 0011 0000
We only count the first 12-bits and drop the last 4 zeroes. 0001 0111 0011 which is 317 ticks or counts. There are 16 counts per degree Celsius in the datasheet, so it's reporting 23 degrees Celsius at my workbench under the worklights.
- Log in to post comments