-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathMEEPROMMERfirmware.ino
More file actions
317 lines (281 loc) · 8.66 KB
/
MEEPROMMERfirmware.ino
File metadata and controls
317 lines (281 loc) · 8.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
/**
* ** project Arduino EEPROM programmer **
*
* This sketch can be used to read and write data to a
* AT28C64 or AT28C256 parallel EEPROM
*
* $Author: mario, edited by Zack $
* $Date: 2013/05/05 11:01:54 $
* $Revision: 1.3 $
*
* This software is freeware and can be modified, reused or thrown away without any restrictions.
*
* Use this code at your own risk. I'm not responsible for any bad effect or damages caused by this software!!!
*
**/
#define VERSIONSTRING "MEEPROMMER $Revision: 1.3 $ $Date: 12/18/2013 15:56:00 $, CMD:R,r,w,W,V, u"
// shiftOut part
#define PORTC_DS 0
#define PORTC_LATCH 1
#define PORTC_CLOCK 2
// eeprom IO lines:D0-D7 = pins2-9
// IO lines for the eeprom control
#define PORTC_CE 3
#define PORTC_OE 4
#define PORTC_WE 5
//a buffer for bytes to burn
#define BUFFERSIZE 1024
byte buffer[BUFFERSIZE];
//command buffer for parsing commands
#define COMMANDSIZE 16
char cmdbuf[COMMANDSIZE];
unsigned int startAddress,endAddress;
unsigned int lineLength,dataLength;
//define COMMANDS
#define NOCOMMAND 0
#define VERSION 1
#define READ_HEX 10
#define READ_BIN 11
#define WRITE_PAGE 20
#define WRITE_BIN 21
#define UNLOCK 30
/*****************************************************************
*
* CONTROL and DATA functions
*
****************************************************************/
void data_bus_input(){
DDRD &= 0b00000011;
DDRB &= 0b11111100;
}
void data_bus_output(){
DDRD |= 0b11111100;
DDRB |= 0b00000011;
}
byte read_data_bus(){
return ((PINB<<6)|(PIND>>2));
}
void write_data_bus(byte data){
PORTB &= 0b11111100;
PORTB |= (data>>6);
PORTD &= 0b00000011;
PORTD |= (data<<2);
}
//shift out the given address to the 74hc595 registers
void set_address_bus(unsigned int address){
bitClear(PORTC,PORTC_LATCH); //disable latch line
fastShiftOut(highByte(address)); //shift out highbyte
fastShiftOut(lowByte(address)); //shift out lowbyte
bitSet(PORTC,PORTC_LATCH); //enable latch and set address
}
void fastShiftOut(byte data){
for(int i=7; i>=0; i--){//shift MSB first
//clear data pin after shift to prevent bleed through
bitClear(PORTC,PORTC_DS);
bitClear(PORTC,PORTC_CLOCK);
if(bitRead(data,i))bitSet(PORTC,PORTC_DS);
//register shifts bits on rising clock
bitSet(PORTC,PORTC_CLOCK);
}
bitClear(PORTC,PORTC_CLOCK);
}
byte read_byte(unsigned int address){
data_bus_input(); //set databus for reading
bitClear(PORTC,PORTC_CE); //enable chip select
bitSet(PORTC,PORTC_WE); //disable write
set_address_bus(address); //set address bus
bitClear(PORTC,PORTC_OE); //enable output
//delay 312.5ns @ 16MHz
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
byte data = read_data_bus();
bitSet(PORTC,PORTC_OE); //disable output
bitSet(PORTC,PORTC_CE); //enable chip select
return data;
}
void fast_write(unsigned int address, byte data){
bitSet(PORTC,PORTC_OE); //first disable output
bitSet(PORTC,PORTC_WE); //disable write
set_address_bus(address); //set address bus
data_bus_output(); //set databus to output
write_data_bus(data); //set data bus
bitClear(PORTC,PORTC_CE); //enable chip select
bitClear(PORTC,PORTC_WE); //enable write
__asm__("nop\n\t""nop\n\t"); //delay 125ns @ 16MHz
bitSet(PORTC,PORTC_WE); //disable write
data_bus_input();
bitClear(PORTC,PORTC_OE);
//delay 312.5ns @ 16MHz
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
while(data != read_data_bus()); //poll data
bitSet(PORTC,PORTC_OE);
bitSet(PORTC,PORTC_CE);
}
void write_block_page(unsigned int address, byte* buffer, int len, int page){
address &= ~(page-1); //address must not break page boundaries
bitSet(PORTC,PORTC_WE); //disable write
bitClear(PORTC,PORTC_CE); //enable chip
for(int n=0; n<len/page; n++){
bitSet(PORTC,PORTC_OE);
data_bus_output(); //set databus to output
for(unsigned int i=n*page; i<(n+1)*page; i++){
bitSet(PORTC,PORTC_WE); //disable write
set_address_bus(address+i); //set address bus
write_data_bus(buffer[i]); //set data bus
bitClear(PORTC,PORTC_WE); //enable write
//100ns+ tWP delay caused by for looping
}
bitSet(PORTC,PORTC_WE); //write must be high for tBLC(100us)
data_bus_input();
bitClear(PORTC,PORTC_OE); //enable output
//delay 312.5ns @ 16MHz
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
while(buffer[(n+1)*page-1] != read_data_bus()); //poll data
}
bitSet(PORTC,PORTC_CE);
}
/************************************************
*
* COMMAND and PARSING functions
*
*************************************************/
void readCommand(){
int idx = 0;
do {//read 'til linebreak or buffer is full
if(Serial.available())cmdbuf[idx++] = Serial.read();
} while (cmdbuf[idx-1] != '\n' && idx < COMMANDSIZE);
for(;idx<COMMANDSIZE;idx++)cmdbuf[idx] = 0;//clear the rest of command buffer
}
byte parseCommand(){
//command format:C AAAA DDDD LL
startAddress=hexWord(cmdbuf+2); //A
dataLength=hexWord(cmdbuf+7); //D
lineLength=hexByte(cmdbuf+12); //L
switch(cmdbuf[0]){
case 'R':
return(READ_HEX);
case 'r':
return(READ_BIN);
case 'W':
return(WRITE_PAGE);
case 'w':
return(WRITE_BIN);
case 'V':
return(VERSION);
case 'u':
return(UNLOCK);
default:
return(NOCOMMAND);
}
}
byte hexDigit(char c){ //ascii char to value
if(c >= '0' && c <= '9')return c - '0';
if(c >= 'a' && c <= 'f')return c - 'a' + 10;
if(c >= 'A' && c <= 'F')return c - 'A' + 10;
return 0;// getting here is bad: it means the character was invalid
}
byte hexByte(char* a){ //ascii byte to value
return ((hexDigit(a[0])<<4) | hexDigit(a[1]));
}
//ascii word to value
unsigned int hexWord(char* data){
return ((hexDigit(data[0])<<12)|
(hexDigit(data[1])<<8)|
(hexDigit(data[2])<<4)|
(hexDigit(data[3])));
}
/************************************************
*
* INPUT / OUTPUT Functions
*
*************************************************/
void read_block(unsigned int from, unsigned int to, int linelength){
int outcount = 0;
//loop from "from address" to "to address" (included)
for(unsigned int address = from; address <= to; address++){
if(outcount == 0){
//print out the address at the beginning of the line
Serial.println();
Serial.print("0x");
printAddress(address);
Serial.print(" : ");
}
//print data, separated by a space
printByte(read_byte(address));
Serial.print(" ");
outcount = (++outcount % linelength);
}
Serial.println();
}
void read_binblock(unsigned int from, unsigned int to){
for(unsigned int address = from; address <= to; address++){
Serial.write(read_byte(address));
}
Serial.print('\0');//success return code
}
void write_block(unsigned int address, byte* buffer, int len){
for(unsigned int i = 0; i < len; i++){
fast_write(address+i,buffer[i]);
}
}
void printAddress(unsigned int address){
if(!(address & 0xfff0)) Serial.print("0");
if(!(address & 0xff00)) Serial.print("0");
if(!(address & 0xf000)) Serial.print("0");
Serial.print(address, HEX);
}
void printByte(byte data){
if(!(data & 0xf0)) Serial.print("0");
Serial.print(data, HEX);
}
/************************************************
*
* MAIN
*
*************************************************/
void setup(){
DDRC = 0b00111111; //set EEPROM & shiftOut Pins as output
PORTC = 0b00111000; //set EEPROM Pins high
//Serial.begin(57600); //set speed of serial connection
Serial.begin(115200);
}
void loop(){
int bytes = 0;
readCommand();
switch(parseCommand()){
case READ_HEX:
if(lineLength==0) lineLength=32; //default
endAddress = startAddress + dataLength -1;
read_block(startAddress,endAddress,lineLength);
Serial.println('%');//success return code
break;
case READ_BIN:
endAddress = startAddress + dataLength -1;
read_binblock(startAddress,endAddress);
break;
case WRITE_PAGE:
if(dataLength > 1024) dataLength = 1024;
while(bytes < dataLength)if(Serial.available())buffer[bytes++] = Serial.read();
if(lineLength==0) lineLength=32; //page size
write_block_page(startAddress,buffer,dataLength,lineLength);
Serial.println('%');
break;
case WRITE_BIN:
if(dataLength > 1024) dataLength = 1024; //1024 is max
while(bytes < dataLength)if(Serial.available())buffer[bytes++] = Serial.read();
write_block(startAddress,buffer,dataLength);
Serial.println('%');
break;
case VERSION:
Serial.println(VERSIONSTRING);
break;
case UNLOCK:
fast_write(0x5555,0xAA);
fast_write(0x2AAA,0x55);
fast_write(0x5555,0x80);
fast_write(0x5555,0xAA);
fast_write(0x2AAA,0x55);
fast_write(0x5555,0x20);
Serial.print('%');//success return code
break;
}
}