1
Project logs / First Bus Pirate project, modifing the EEPROM on an LED Fan.


Once I took the fan apart, I noticed a portion of the circuit board was sealed and next to the sealed portion was an EEPROM. The EEPROM was a model 24LC02B with 256 bytes of storage and an I2C interface. Next, I went to the dangerousprototypes.com boards and read all I could about I2C EEPROMS. After wiring up my EEPROM similar to the example here: http://http://dangerousprototypes.com/docs/File:24aa02e48.png, I began my quest to change the contents of the EEPROM and thus the message displayed while the fan was on.

One thing to mention that I overlooked and drove me crazy, was that the +3v pin AND the pullup pin need to be wired to the VCC on the EEPROM.
Once everything was wired I dumped the contents of the LED fan's EEPROM:
Code: [Select]
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.31V 5.13V 0.00V 3.32V L H H H H
I2C>P
Pull-up resistors ON
I2C>W
Power supplies ON
I2C>(1)
Searching I2C address space. Found devices at:
0xA0(0x50 W) 0xA1(0x50 R) (Note: The datasheet for the eeprom confirms)
I2C>[0xa0 0x00 [0xa1 r:256]
I2C START BIT
WRITE: 0xA0 ACK
WRITE: 0x00 ACK
I2C START BIT
WRITE: 0xA1 ACK
READ: 0x04 ACK 0x0C ACK 0xFD ACK 0xFE ACK 0xEE ACK 0x09 ACK 0xEF ACK 0x8F ACK 0x7B ACK 0x7B ACK 0x7B ACK 0x8F ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xBF ACK 0x7B ACK 0x7B ACK 0x7B ACK 0x8F ACK 0xFF ACK 0x7F ACK 0x0A ACK 0x7B ACK 0xFF ACK 0xBF ACK 0x5B ACK 0x5B ACK 0x5B ACK 0xEF ACK 0x0B ACK 0xBF ACK 0x7F ACK 0x7F ACK 0x8B ACK 0x0F ACK 0xFB ACK 0xCF ACK 0xFB ACK 0x0B ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xCF ACK 0x5B ACK 0x5B ACK 0x5B ACK 0x8F ACK 0x0F ACK 0xFB ACK 0xFB ACK 0xEF ACK 0x08 ACK 0xFE ACK 0xFE ACK 0x08 ACK 0xFE ACK 0xFE ACK 0x0F ACK 0x0F ACK 0xFB ACK 0xFB ACK 0xEF ACK 0x0B ACK 0x8F ACK 0x7B ACK 0x7B ACK 0x7B ACK 0x8F ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0x08 ACK 0x6F ACK 0x7B ACK 0x7B ACK 0x8F ACK 0x0F ACK 0xFB ACK 0xFB ACK 0xEF ACK 0x0B ACK 0x0B ACK 0xBF ACK 0x7F ACK 0x7F ACK 0x8B ACK 0x8F ACK 0x7B ACK 0x7B ACK 0x7B ACK 0x8F ACK 0xFD ACK 0xFE ACK 0xEE ACK 0x09 ACK 0xEF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xBF ACK 0x5B ACK 0x5B ACK 0x5B ACK 0xEF ACK 0xFF ACK 0x7F ACK 0x0A ACK 0x7B ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xBD ACK 0x7E ACK 0x7E ACK 0x7E ACK 0x89 ACK 0x89 ACK 0x6E ACK 0x6E ACK 0x6E ACK 0x08 ACK 0x09 ACK 0xEE ACK 0xEE ACK 0xEE ACK 0x09 ACK 0x03 ACK 0xBD ACK 0x7E ACK 0x7E ACK 0x7E ACK 0x89 ACK 0x89 ACK 0x6E ACK 0x6E ACK 0x6E ACK 0x08 ACK 0x09 ACK 0xEE ACK 0xEE ACK 0xEE ACK 0x09 ACK 0x0F ACK 0x0F ACK 0xFB ACK 0xCF ACK 0xFB ACK 0x0B ACK 0x8F ACK 0x7B ACK 0x7B ACK 0x7B ACK 0x8F ACK 0xBF ACK 0x7B ACK 0x7B ACK 0x7B ACK 0x8F ACK 0xFF ACK 0xFF ACK 0x3F ACK 0x3F ACK 0xFF ACK 0xCF ACK 0x5B ACK 0x5B ACK 0x5B ACK 0x8F ACK 0x89 ACK 0x5D ACK 0x5D ACK 0x5D ACK 0xEB ACK 0x0F ACK 0xFB ACK 0xFB ACK 0xEF ACK 0x0B ACK 0x0B ACK 0xBF ACK 0x7F ACK 0x7F ACK 0x8B ACK 0x8F ACK 0x7B ACK 0x7B ACK 0x7B ACK 0x8F ACK 0x7F ACK 0x7F ACK 0x7F ACK 0x7F ACK 0x08 ACK 0xBF ACK 0x7B ACK 0x7B ACK 0x7B ACK 0x8F ACK 0xFF ACK 0x7F ACK 0x0A ACK 0x7B ACK 0xFF ACK 0xBF ACK 0x5B ACK 0x5B ACK 0x5B ACK 0xEF ACK 0x0B ACK 0xBF ACK 0x7F ACK 0x7F ACK 0x8B ACK 0x08 ACK 0xFD ACK 0xEB ACK 0xFD ACK 0x08 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00
It wasn't obvious to me what these bytes represented, so off to google to see what I could find out about spinning LEDs. I learned that most spinning LED devices store text as bits which map to the LEDs. So looking at the bytes wasn't going to help all that much. Taking all these hex characters and converting them to binary was the next step.
I'm going to skip the part where I was pulling my hair out trying to arrange the bits to make letters. It turns out the first 2 bytes represent the number of total groups and the size of the first group (respectively). So if we omit them, it starts to come together.
Let's look at the next 10 bytes after the first 2: FDFEEE09EF8F7B7B7B8F
Not that revealing and certainly not obvious what they represent. So let's convert this hex string to binary.
11111101111111101110111000001001111011111000111101111011011110110111101110001111
Also not that revealing. So let's make an assumption about these bytes. Let's assume that whatever is interpreting this data is dealing with it a byte at a time. So then we get this:
11111101
11111110
11101110
00001001
11101111
10001111
01111011
01111011
01111011
10001111
It looks like the 1's are empty space and the 0's make up the characters.
(Note the empty space (1's) on bit 5 of each byte. If you look at the fan, it only has 7 leds, so one of the bits is always 1)
Ok, so there are 2 characters, 'o' and 'f'. Rotate each block -90 degrees and mirror it, you can see the characters. So, each character is represented by 5 bytes. That led me to decode the EEPROM contents:
Code: [Select]
04 //Total Groups
0C //Size of first group (# of letters)
FDFEEE09EF //f
8F7B7B7B8F //o
FFFFFFFFFF //
BF7B7B7B8F //c
FF7F0A7BFF //i
BF5B5B5BEF //s
0BBF7F7F8B //u
0FFBCFFB0B //m
FFFFFFFFFF //
CF5B5B5B8F //e
0FFBFBEF08 //h
FEFE08FEFE //T
0F //Size of the next group
0FFBFBEF0B //n
8F7B7B7B8F //o
FFFFFFFFFF //
086F7B7B8F //d
0FFBFBEF0B //n
0BBF7F7F8B //u
8F7B7B7B8F //o
FDFEEE09EF //f
FFFFFFFFFF //
BF5B5B5BEF //s
FF7F0A7BFF //i
FFFFFFFFFF //
BD7E7E7E89 //C
896E6E6E08 //B
09EEEEEE09 //A
03 //Size of the next group
BD7E7E7E89 //C
896E6E6E08 //B
09EEEEEE09 //A
0F //Size of the final group.
0FFBCFFB0B //m
8F7B7B7B8F //o
BF7B7B7B8F //c
FFFF3F3FFF //.
CF5B5B5B8F //e
895D5D5DEB //g
0FFBFBEF0B //n
0BBF7F7F8B //u
8F7B7B7B8F //o
7F7F7F7F08 //l
BF7B7B7B8F //c
FF7F0A7BFF //i
BF5B5B5BEF //s
0BBF7F7F8B //u
08FDEBFD08 //M
0000000000
0000000000
0000000000
0000000000
0000000000
00
There in the EEPROM was the messages I saw scrolling across the fan! Next, I wrote a little program to encode/decode the hex stream based on my analysis above.

(5 Bytes which represent the letter 's')
I used the existing letters but I also needed an r and p, so I had to invent those myself.
Ultimately I came up with the following to rewrite to the first 12 characters (62 bytes including 2 byte header).
040CFFFFFF
FFFFFFFF28
28FFCF5B5B
5B8FFFEF09
EFFF09EEEE
EE09EFFBFB
09FFFF7F0A
7BFFF9EEEE
08FFFFFFFF
FFFFBF5B5B
5BEF0BBF7F
7F8B896E6E
6E08
I wrote the bytes back 8 at a time using the following format:
Code: [Select]
I2C>[0xa0 0 0x04 0x0C 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF]
I2C START BIT
WRITE: 0xA0 ACK
WRITE: 0x00 ACK
WRITE: 0x04 ACK
WRITE: 0x0C ACK
WRITE: 0xFF ACK
WRITE: 0xFF ACK
WRITE: 0xFF ACK
WRITE: 0xFF ACK
WRITE: 0xFF ACK
WRITE: 0xFF ACK
I2C STOP BIT
I2C>
Where 0xa0 is the write command, 0x00 is the address, and the rest are 8 bytes to write starting at 0x00. I did this for all the data. The datasheet for the EEPROM says that a paged write must start at a multiple of 8 and contain 8 bytes of data. So I had to combine all the bytes and break them into groups of 8.
A dump of the first 62 characters shows my write was a success:
Code: [Select]
I2C>[0xa0 0 [0xa1 r:62]
I2C START BIT
WRITE: 0xA0 ACK
WRITE: 0x00 ACK
I2C START BIT
WRITE: 0xA1 ACK
READ: 0x04 0x0C 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0x28
ACK 0x28 ACK 0xFF ACK 0xCF ACK 0x5B ACK 0x5B ACK 0x5B ACK 0x8F ACK 0xFF
ACK 0xEF ACK 0x09 ACK 0xEF ACK 0xFF ACK 0x09 ACK 0xEE ACK 0xEE ACK 0xEE
ACK 0x09 ACK 0xEF ACK 0xFB ACK 0xFB ACK 0x09 ACK 0xFF ACK 0xFF ACK 0x7F
ACK 0x0A ACK 0x7B ACK 0xFF ACK 0xF9 ACK 0xEE ACK 0xEE ACK 0x08 ACK 0xFF
ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xBF ACK 0x5B ACK 0x5B
ACK 0x5B ACK 0xEF ACK 0x0B ACK 0xBF ACK 0x7F ACK 0x7F ACK 0x8B ACK 0x89
ACK 0x6E ACK 0x6E ACK 0x6E ACK 0x08
Once the device was re-assembled, the fan displayed the new message!