Skip to content

Commit f57b6d2

Browse files
committed
Primary commit
0 parents  commit f57b6d2

2 files changed

Lines changed: 325 additions & 0 deletions

File tree

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
_This manual is released by the author into the public domain._
2+
3+
#T24C02A EEPROM set-up:
4+
Connect Arduino GND to EEPROM GND.
5+
Connect Arduino SDA to EEPROM SDA.
6+
Connect Arduino SCL to EEPROM SCL.
7+
Connect Arduino 5V to EEPROM Vcc.
8+
9+
#Arduino set-up:
10+
Open the Arduino IDE.
11+
Connect Arduino (I used USB).
12+
Choose correct board and serial port in Arduino IDE.
13+
Upload code to Arduino using the IDE.
14+
Open serial console (Ctrl+Shift+M).
15+
The board waits 4 seconds after Arduino reset (end of upload).
16+
Then it promps for I²C address.
17+
If you miss this prompt, just enter the address, or if you don't know the address, enter the character 'P'.
18+
19+
#Getting started:
20+
If you opened the serial console soon enough, you'll be prompted for an I²C address or a 'P'.
21+
If you did not open the serial console within four seconds after the Arduino reset, you will not see the prompt, but the Arduino will still patiently wait for your input.
22+
Enter the address, or the character 'P'.
23+
##The address:
24+
The Arduino wire library works with 7-bit adresses.
25+
The Arduino Serial library can easily parse decimal values, not hex codes.
26+
Therefore the default T24C02A address 0xA0 is rendered thus:
27+
Shift right one bit to get 7-bit address: 0xA0 >> 1 → 0x50
28+
Convert to decimal: 0x50 → 5×16 + 0 = 80
29+
##Polling:
30+
If you entered the character 'P', the Arduino will poll all 128 possible addresses on the I²C bus.
31+
It wil show you the address + answer of the devices that answered.
32+
If you have successfully entered the address, you will be in the main shell menu.
33+
34+
#The main menu:
35+
You will be asked for a command char:
36+
R — Read
37+
W — Write
38+
S — Set I²C address
39+
useful if you set it wrong, have multiple EEPROMs or have a T24C04A, T24C08A or T24C16A IC.
40+
P — Re-poll the I²C bus.
41+
##Reading:
42+
Follow the instruction:
43+
Enter the start address for the read.
44+
Enter the number of bytes to be read.
45+
The device will print all characters on a single line.
46+
Followed by a line of statistics.
47+
Optionally followed by a line indicating an error.
48+
##Writing:
49+
Follow the instruction:
50+
Enter the start address for the write.
51+
Enter the string to be written.
52+
Escape numerical ASCII representations of characters by prefixing them with an '@'.
53+
@64 is the @ character itself.
54+
The device will print each character submitted to the device.
55+
The device will print a human readable error message for each unsuccessful write.
56+
The device will retransmit (including reprint of) the character up to NUM_TRIES times.
57+
NUM_TRIES is set to 10 by default in the code.
58+
After ten failed tries the device:
59+
Will print an error message indication.
60+
It will skip this address.
61+
It will continue to write the next character to the next location in the EEPROM.
62+
##Setting the I²C address:
63+
The same procedure as detailed in the section "Getting Started", see above.
64+
##Polling:
65+
The same procedure as detailed in the section "Getting Started", see above.
66+
This polling is not done as part of a change of address.
67+
The device will give information on the polled devices, and return to the menu.

eeprom_edit.ino

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
/** This code is released by the author into the public domain.
2+
3+
This program can run on an Arduino connected to a T24C02A EEPROM on the I²C bus.
4+
The Arduino offers an interactive shell on the serial interface that can be used to read and write the EEPROM. (Hardware write protection must be removed manually of course)
5+
6+
Designed using an Arduino Leonardo, but should work with any Arduino that has an I²C interface.
7+
8+
This work is based on this datasheet for the T24C02A IC: http://www.ic-jiazhi.com/upload/PDF/T24C02A_E.pdf
9+
Currently writing to pages of T24C04A, T24C08A and T24C16A ICs requires setting the I²C address' three least significant bytes to account for the page number, as detailed in the datasheet.
10+
Other sources for this work are: http://blog.opensecurityresearch.com/2012/10/hacking-usb-webkeys.html
11+
And of course lots of reading : http://arduino.cc/en/Reference/HomePage mainly for the specifics on the Wire library. It is a fairly abstracted library, and careful reading is required to understand how to send the START, STOP, ACK and NACK messages correctly.
12+
**/
13+
#include <Wire.h>
14+
15+
void setup() {
16+
Wire.begin();
17+
Serial.begin(9600);
18+
//Wait, so the user can open the serial interface.
19+
delay(4000);
20+
}
21+
22+
void loop()
23+
{
24+
//Start interactive shell
25+
EEPROM_I2C_interactive(EEPROM_I2C_setAddress());
26+
}
27+
28+
//Prompt the user for an address on the EEPROM to read from, and the amount of bytes to read from there.
29+
void EEPROM_I2C_read(byte I2C_ADDRESS)
30+
{
31+
Serial.println("Enter EEPROM address (decimal) to read from:");
32+
while(!Serial.available());
33+
int address = Serial.parseInt();
34+
Serial.println("Enter number of bytes to read.");
35+
while(!Serial.available());
36+
byte amount = Serial.parseInt();
37+
Serial.print("Reading ");
38+
Serial.print(amount);
39+
Serial.print(" bytes starting at EEPROM address ");
40+
Serial.print(address);
41+
Serial.println(":");
42+
/*
43+
This part is a bit weird, because the chip only returns up to 32 bytes.
44+
Thus we try to read [amount-readcount] bytes from EEPROM address [address+readcount] and increment readcount for each received byte.
45+
The while loop ensures that as long as we haven't received the full amount of bytes, we'll read the next batch of up to 32 bytes.
46+
*/
47+
48+
//Count received bytes in this variable.
49+
int readcount = 0;
50+
while (readcount < amount)
51+
{
52+
//Begin a transmission to the I2C device.
53+
Wire.beginTransmission(I2C_ADDRESS);
54+
//Write the address offset by the amount of bytes we've already read.
55+
Wire.write(address + readcount);
56+
//Write the buffered transmission, send a restart instead of a stop byte. (see T24C02A datasheet: Random read and Sequential read)
57+
char result = Wire.endTransmission(false);
58+
//Check return code, normally reads always succeed.
59+
if (result > 0)
60+
//Print human readable error message if applicable.
61+
EEPROM_I2C_printreturncode(result);
62+
//Request amount-readcount bytes of data from the I2C device (the EEPROM). It will return up to 32 bytes.
63+
Wire.requestFrom(int(I2C_ADDRESS),amount-readcount);
64+
//Read the data available on the I2C bus.
65+
while(Wire.available())
66+
{
67+
//Receive a byte, cast it to char, print it.
68+
Serial.print(char(Wire.read()));
69+
//Increment readcount, this is important, because the function relies on accurate counting of the received number of bytes.
70+
readcount++;
71+
}
72+
}
73+
//Write newline and the stats about the read.
74+
Serial.println();
75+
Serial.print("Received ");
76+
Serial.print(readcount);
77+
Serial.print(" of ");
78+
Serial.print(amount);
79+
Serial.println(" bytes");
80+
//NOTE: Artifacts, error lines may in fact never be reached. Did not check thoroughly.
81+
//Write error messages if no data was received, or if less than the expected amount of bytes was received.
82+
if (readcount == 0)
83+
Serial.println("No bytes received, please check address, connection and power.");
84+
else if (readcount < amount)
85+
Serial.println("Received less than target amount of bytes!");
86+
}
87+
88+
void EEPROM_I2C_write(byte I2C_ADDRESS)
89+
{
90+
//Constant for the number of tries. With 10 you're fine, I never had 10 write failures in succession.
91+
const char NUM_TRIES = 10;
92+
//Promt user for EEPROM address to start write.
93+
Serial.println("Enter EEPROM startaddress to write to:");
94+
//Wait for user input.
95+
while(!Serial.available());
96+
int address = Serial.parseInt();
97+
//Prompt user for string to write to the EEPROM, this is explained to the user fairly well.
98+
Serial.print("Enter string to write to ");
99+
Serial.print(address);
100+
Serial.println(".");
101+
Serial.println("Any ASCII value can be entered by sending its decimal representation prefixed by an '@' character.");
102+
Serial.println("To write and actual '@', write @64 since 64 is the ASCII value for the @ character.");
103+
//Wait for user input.
104+
while(!Serial.available());
105+
Serial.print("Writing: ");
106+
//Write each received byte, and increment the address after the write operation, so the next byte is written to the next address.
107+
for (; Serial.available(); address++)
108+
{
109+
//Grab one byte from the Serial buffer.
110+
char received = Serial.read();
111+
//Check whether it's an '@' followed by some data. This is the escape code for decimal input of character values (e.g. for non-printable characters).
112+
if (received == '@' && Serial.available())
113+
//Parse the number that follows the '@'. This will mess up if people send an '@' followed by a non-numerical character. The user should be sensible and not do that, otherwise it will write something else than intended.
114+
received = Serial.parseInt();
115+
//Initialise [tries] counter to zero.
116+
char tries = 0;
117+
//Start with resultcode 4 (other error), loop as long as it isn't zero (success) and [tries] < [NUM_TRIES] constant (see start of function). Increment [tries] for each attempt.
118+
for (char result = 4; result > 0 && tries < NUM_TRIES; tries++)
119+
{
120+
//Begin a transmission to the I²C device (the EEPROM).
121+
Wire.beginTransmission(I2C_ADDRESS);
122+
//Write the EEPROM address to the I²C bus, this sets the start address of the write operation.
123+
Wire.write(address);
124+
//Write the byte grabbed from the I²C bus.
125+
Wire.write(received);
126+
//Write the byte back to the serial line as well, to visually confirm to the user that it has been written.
127+
Serial.print(received);
128+
//Execute the buffered I²C transmission and store the result code.
129+
result = Wire.endTransmission();
130+
//Check for error codes (0 is success, higher is error, lower should not exist).
131+
if (result > 0)
132+
//Print error message in human readable format.
133+
EEPROM_I2C_printreturncode(result);
134+
//Note: If the returned error code is not zero at this point, The enclosing for loop will cause a retransmission attempt up to NUM_TRIES times.
135+
}
136+
//If the maximum amount of tries has been reached, the write has not succeeded.
137+
if (tries == NUM_TRIES)
138+
{
139+
//Notify the user of the failed write.
140+
Serial.print(int(NUM_TRIES));
141+
Serial.print(" failed attempts to write ");
142+
Serial.print(received);
143+
Serial.print(" to address ");
144+
Serial.println(address);
145+
//NOTE: The function does not abort at this point, it will acknowledge the failure to write to this address, and continue with the next address and the next string character.
146+
}
147+
}
148+
//Print a newline to ensure that the next message is not printed on the same line as the function output.
149+
Serial.println();
150+
}
151+
152+
byte EEPROM_I2C_setAddress()
153+
{
154+
while(true)
155+
{
156+
//Prompt the user for input. Either an address or a P to poll the I²C bus.
157+
Serial.println("Enter I2C 7-bit address of the EEPROM in decimal:");
158+
Serial.println("Enter P to poll the entire I2C bus for compatible devices:");
159+
//Wait for user input.
160+
while(!Serial.available());
161+
//If the data in the Serial buffer is the carachter 'P', run the poll function.
162+
if (Serial.peek() == 'P')
163+
{
164+
//Read the 'P' out of the buffer, otherwise the program will continue polling perpetually.
165+
Serial.read();
166+
EEPROM_I2C_pollbus();
167+
}
168+
else //No characer 'P' is in the Serial buffer, read the data as an integer address.
169+
{
170+
//Parse integer address from the Serial.
171+
int address = Serial.parseInt();
172+
//Check whether the address is in the valid range.
173+
if (address >= 0 && address < 128)
174+
{
175+
//Show the user that the address has been set.
176+
Serial.print("I2C address of EEPROM set to: ");
177+
Serial.println(address);
178+
//Return the address.
179+
return address;
180+
}
181+
//Show error message to the user.
182+
Serial.println("Invalid address. Address must be between 0 and 127 inclusive.");
183+
}
184+
}
185+
}
186+
187+
void EEPROM_I2C_interactive(char I2C_ADDRESS)
188+
{
189+
//Loop forever
190+
while(true)
191+
{
192+
//Prompt the user for an action. (No Oxford comma there, I'm normally quite fond of it, but I think the text is unambiguous enough, and the extra comma looks weird.
193+
Serial.println("Enter P, R, S or W.");
194+
Serial.println("S - Set I2C 7-bit address of EEPROM");
195+
Serial.println("R - Read data from EEPROM");
196+
Serial.println("W - Write data to EEPROM");
197+
Serial.println("P - Poll the I2C bus.");
198+
//Wait for user input.
199+
while(!Serial.available());
200+
//Retrieve a single command character from the serial buffer.
201+
//Note: Since only one character is read, users can queue subsequent commands.
202+
//For example: W24Test@255@ will write to address 24 of the EEPROM, the string "Test" followed by ASCII character 255, followed by an actual '@' character.
203+
// R11 17 will read seventeen bytes starting from EEPROM address 11.
204+
char command = Serial.read();
205+
if (command == 'W')
206+
//Start the write function if the command character was a 'W'.
207+
EEPROM_I2C_write(I2C_ADDRESS);
208+
else if (command == 'R')
209+
//Start the read function if the command character was an 'R'.
210+
EEPROM_I2C_read(I2C_ADDRESS);
211+
else if (command == 'S')
212+
//Start the setAddress funtion if the command character was an 'S'.
213+
EEPROM_I2C_setAddress();
214+
else if (command == 'P')
215+
//Start the function that polls the I2C bus.
216+
EEPROM_I2C_pollbus();
217+
else
218+
{
219+
//Print an error message for any other command character.
220+
Serial.print("Unknown command: ");
221+
Serial.println(command);
222+
}
223+
}
224+
}
225+
226+
void EEPROM_I2C_pollbus()
227+
{
228+
//Loop trough the available 7-bit addresses of the I²C bus.
229+
for (int address = 0; address < 128; address++)
230+
{
231+
//Print the address to the user.
232+
//Request up to 32 characters from this address on the I²C bus.
233+
Wire.requestFrom(address, 32);
234+
//If there's an answer, tell the user so, and read the answer.
235+
if (Wire.available())
236+
{
237+
Serial.print("Answer from ");
238+
Serial.print(address);
239+
Serial.print(": ");
240+
//Try to read up to 32 characters from the I²C bus.
241+
for (byte readcount = 0; Wire.available() && readcount < 32; readcount++)
242+
//Print each received byte as a character.
243+
Serial.print(char(Wire.read()));
244+
//Print a newline.
245+
Serial.println();
246+
}
247+
}
248+
//Note: The user can now skim the output and decide where on the bus the device is located, by looking for addresses where data was received.
249+
}
250+
251+
void EEPROM_I2C_printreturncode(char code)
252+
{
253+
String returncodes[5] = {"SUCCESS","DATA TOO LONG","NACKED ADDRESS", "NACKED DATA"};
254+
//Print a newline character to ensure that the error isn't lost at the end of a long line of text.
255+
Serial.println();
256+
//Print the returncode from Wire.endTransmission in a human readable format.
257+
Serial.println(returncodes[code]);
258+
}

0 commit comments

Comments
 (0)