Tuesday, January 1, 2013

Bus Pirate meets the 93LC46B

One of the toys I acquired last year (or possibly even the year before) was a DangerousPrototypes Bus Pirate. Among the many things it can do is read/write EEPROM chips, which is a type of memory. They are used in electronics to store things like programs and state information. People have used Bus Pirates to recover motherboards that have been bricked by a bad BIOS flash. Some laptops have start-up password protection. The password is stored on an EEPROM chip, and if the user should become forgetful, reading the chip is one way to recover it.

I found an old EEPROM chip in my spare parts collection, the 93LC46B. The data sheet says it communicates using 3-wire serial I/O, and can store 1024 bits organized either as 8- or 16-bit words.

Next was the question of how to wire the bus pirate to the chip. I liked the idea of plugging some headers into a breadboard:

These give the Bus Pirate's clips something to grab onto.

Then, I wasn't sure if I needed to create a separate power supply. Turns out one can simply power the chip directly from the Bus Pirate's 3.3V connector. This is undoubtedly one of the reasons the Bus Pirate is such a well-regarded tool.

Finally, I hooked up the CS (chip select), CLK, MOSI (to the DI or data in pin), and MISO (to the DO or data out pin) connectors.

I used putty as a terminal to control the Bus Pirate. Configuring the Bus Pirate in 3-wire mode took a little trial-and-error, but I finally found settings that worked:

=~=~=~=~=~=~=~=~=~=~=~= PuTTY log 2013.01.01 19:28:55 =~=~=~=~=~=~=~=~=~=~=~=

1. HiZ
2. 1-WIRE
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

Set speed:
 1. ~5KHz
 2. ~50KHz
 3. ~100KHz
 4. ~400KHz

 1. CS
 2. /CS *default

Select output type:
 1. Open drain (H=Hi-Z, L=GND)
 2. Normal (H=3.3V, L=GND)

Power supplies O

The 93LC46B's data sheet says the chip select needs to be held high before sending any commands, which is why I chose "CS" instead of "/CS" from the menu ("/CS" means the chip select pin is held low).

The other thing that got me was the output type. At one point, I selected "Open drain" and then couldn't figure out why CS wouldn't go to 3.3V when it was enabled. Something I found out while debugging this is the Bus Pirate's ADC connector can be used to measure voltages, up to 6V. At any rate, after realizing the CS problem was caused by the wrong output type, things started working a lot better.

The 93LC46B's commands take the form of a start bit, 2 op code bits, 7 address bits, and optionally 8 data bits for some write commands. This means having to tell Bus Pirate to write 10 or 18 bits. This is one way to from address 0:

3WIRE>[0b110;3 0b0000000;7 r;8]
WRITE: 0x06;3 
WRITE: 0x00;7 

The command broken down:

[            Enable CS
0b110;3      Write 3 bits: start bit '1', opcode '10' (read)
0b0000000;7  Write 7 bits: address 0x00
r;8          Read 8 bits
]            Disable CS

So far so good. I am able to issue 10-bit commands to the chip. These commands include write-enable and erase-all. (Erase writes '1' into each bit position). Unfortunately, I haven't got any 18-bit commands, which take data, to work. So I'm not yet able to write arbitrary data into the eeprom.

Lessons learned:

  • Learned how to wire up the Bus Pirate to a chip.
  • Got some experience with driving the BP in 3-wire mode.
  • Learned how to write words which are not 8-bits in length to the device.
  • The BP's ADC connector can be used to confirm the CS goes to the correct level.
  • Read the datasheet carefully, watch for gotchas like "write-enable must be sent before writing data or erasing cells".


Finally found the correct data sheet. Turns out the 93LC46B only operates in 16-bit mode. So that jumper in the first picture has no effect on the chip's organization. The correct command format takes 6-bit addresses and 16-bit data:

3WIRE>[0b110;3 0b000000;6 r:2;8]  // read two 8-bit words from address 0x00
WRITE: 0x06;3 
WRITE: 0x00;6 
READ: 0xFF 0xFF 
3WIRE> [2K
3WIRE>[0b100;3 0b110000;6]  // enable write
WRITE: 0x04;3 
WRITE: 0x30;6 
3WIRE>[0b101;3 0b000000;6 0x12;8 0x34;8]  // write 0x1234
WRITE: 0x05;3 
WRITE: 0x00;6 
WRITE: 0x12 
WRITE: 0x34 
3WIRE>[0b110;3 0b000000;6 r:2;8]
WRITE: 0x06;3 
WRITE: 0x00;6 
READ: 0x12 0x34 
Power supplies OFF
Power supplies ON
3WIRE>[0b110;3 0b000000;6 r;16]  // another way to read 16 bits
WRITE: 0x06;3 
WRITE: 0x00;6 
READ: 0x1234 

No wonder the chip wasn't accepting any data. Lessons learned:

  • Find the right datasheet. Be excruciatingly exact. A single incorrect letter or digit can waste a lot of your time.
  • Hardware doesn't return error codes. Either it works or you made a mistake. Figuring out where you went wrong is hard.

No comments:

Post a Comment