1 /* 2 Interfacing the Arduino Duemilanove to Am29F010 devices. 3 4 Copyright (C) 2015 Paul Boddie <paul@boddie.org.uk> 5 6 This program is free software; you can redistribute it and/or modify it under 7 the terms of the GNU General Public License as published by the Free Software 8 Foundation; either version 3 of the License, or (at your option) any later 9 version. 10 11 This program is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 PARTICULAR PURPOSE. See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 const int CE = A5, OE = A4, WE = A3, A16 = A2, 20 CS1 = 2, CS2 = 3, 21 DQ0 = 7, DQ1 = 6, DQ2 = 5, DQ3 = 4, 22 DQ4 = 8, DQ5 = 9, DQ6 = 10, DQ7 = 11; 23 24 const int BUFSIZE = 8; 25 char inbuffer[BUFSIZE]; 26 int nread = 0; 27 28 const char ERASE[][8] = { 29 "W5555AA", "W2AAA55", "W555580", "W5555AA", "W2AAA55" 30 }; 31 const char PROGRAM[][8] = { 32 "W5555AA", "W2AAA55", "W5555A0" 33 }; 34 35 int fromHex(char c) 36 { 37 if ((c >= 48) && (c <= 57)) 38 return c - 48; 39 if ((c >= 65) && (c <= 70)) 40 return c - 65 + 10; 41 if ((c >= 97) && (c <= 102)) 42 return c - 97 + 10; 43 return 0; 44 } 45 46 void setDataOut() 47 { 48 pinMode(DQ0, OUTPUT); 49 pinMode(DQ1, OUTPUT); 50 pinMode(DQ2, OUTPUT); 51 pinMode(DQ3, OUTPUT); 52 pinMode(DQ4, OUTPUT); 53 pinMode(DQ5, OUTPUT); 54 pinMode(DQ6, OUTPUT); 55 pinMode(DQ7, OUTPUT); 56 } 57 58 void setDataIn() 59 { 60 pinMode(DQ0, INPUT); 61 pinMode(DQ1, INPUT); 62 pinMode(DQ2, INPUT); 63 pinMode(DQ3, INPUT); 64 pinMode(DQ4, INPUT); 65 pinMode(DQ5, INPUT); 66 pinMode(DQ6, INPUT); 67 pinMode(DQ7, INPUT); 68 } 69 70 int sampleData() 71 { 72 int i = DQ7; 73 int data = 0; 74 75 while (1) 76 { 77 data += digitalRead(i); 78 if (i == DQ0) 79 break; 80 i--; 81 data <<= 1; 82 } 83 84 return data; 85 } 86 87 int readData() 88 { 89 int data = 0; 90 91 setDataIn(); 92 delay(1); 93 data = sampleData(); 94 setDataOut(); 95 return data; 96 } 97 98 void writeData(int data) 99 { 100 int i = DQ0; 101 102 while (1) 103 { 104 digitalWrite(i, data % 2); 105 if (i == DQ7) 106 break; 107 i++; 108 data >>= 1; 109 } 110 } 111 112 void setAddress(int high, int low) 113 { 114 /* The top bit is sent directly. */ 115 116 if (high & 0x100) 117 digitalWrite(A16, HIGH); 118 else 119 digitalWrite(A16, LOW); 120 121 /* The lower 16 bits are sent via the latches. */ 122 123 writeData(high); 124 delayMicroseconds(1); 125 digitalWrite(CS2, HIGH); 126 delayMicroseconds(1); 127 digitalWrite(CS2, LOW); 128 writeData(low); 129 delayMicroseconds(1); 130 digitalWrite(CS1, HIGH); 131 delayMicroseconds(1); 132 digitalWrite(CS1, LOW); 133 } 134 135 int readOp(int high, int low) 136 { 137 int data; 138 139 digitalWrite(CE, LOW); 140 setAddress(high, low); 141 delay(1); 142 digitalWrite(OE, LOW); 143 data = readData(); 144 delay(1); 145 digitalWrite(OE, HIGH); 146 digitalWrite(CE, HIGH); 147 148 return data; 149 } 150 151 void writeOp(int high, int low, int data) 152 { 153 digitalWrite(CE, LOW); 154 setAddress(high, low); 155 delay(1); 156 digitalWrite(WE, LOW); 157 writeData(data); 158 delay(1); 159 digitalWrite(WE, HIGH); 160 digitalWrite(CE, HIGH); 161 } 162 163 int readCommand(const char buffer[]) 164 { 165 int high, low, i; 166 167 if (nread > 5) 168 { 169 high = fromHex(buffer[1]) << 8; 170 i = 2; 171 } 172 else 173 { 174 high = 0; 175 i = 1; 176 } 177 178 high |= (fromHex(buffer[i]) << 4) + (fromHex(buffer[i+1])); 179 low = (fromHex(buffer[i+2]) << 4) + (fromHex(buffer[i+3])); 180 181 return readOp(high, low); 182 } 183 184 bool writeCommand(const char buffer[]) 185 { 186 int high, low, data, i; 187 188 if (nread > 7) 189 { 190 high = fromHex(buffer[1]) << 8; 191 i = 2; 192 } 193 else 194 { 195 high = 0; 196 i = 1; 197 } 198 199 high |= (fromHex(buffer[i]) << 4) + (fromHex(buffer[i+1])); 200 low = (fromHex(buffer[i+2]) << 4) + (fromHex(buffer[i+3])); 201 data = (fromHex(buffer[i+4]) << 4) + (fromHex(buffer[i+5])); 202 203 writeOp(high, low, data); 204 205 return true; 206 } 207 208 bool waitForCompletion(int high, int low, int written) 209 { 210 int data, then = millis(); 211 212 setDataIn(); 213 digitalWrite(CE, LOW); 214 digitalWrite(OE, LOW); 215 216 do 217 { 218 delay(10); 219 data = sampleData(); 220 } while ( 221 ((data & 0x80) != (written & 0x80)) && 222 ((data & 0x20) == 0) && 223 (millis() - then < 2000) 224 ); 225 226 digitalWrite(OE, HIGH); 227 digitalWrite(CE, HIGH); 228 setDataOut(); 229 delay(10); 230 return readOp(high, low) == written; 231 } 232 233 bool chipErase() 234 { 235 for (int i = 0; i < 5; i++) 236 { 237 writeCommand(ERASE[i]); 238 } 239 writeOp(0x55, 0x55, 0x30); 240 return waitForCompletion(0, 0, 0xff); 241 } 242 243 bool sectorErase(const char buffer[]) 244 { 245 int high; 246 247 // 3-bit number shifted to A16...A14. 248 // Thus, only sectors from 0 to 7 are supported. 249 250 high = (fromHex(buffer[1]) << 6) & 0x1ff; 251 252 for (int i = 0; i < 5; i++) 253 { 254 writeCommand(ERASE[i]); 255 } 256 writeOp(high, 0, 0x30); 257 258 // Result of erase if 0xff written to all locations. 259 260 return waitForCompletion(high, 0, 0xff); 261 } 262 263 bool program(const char buffer[]) 264 { 265 int high, low, data, i; 266 267 if (nread > 7) 268 { 269 high = fromHex(buffer[1]) << 8; 270 i = 2; 271 } 272 else 273 { 274 high = 0; 275 i = 1; 276 } 277 278 high |= (fromHex(buffer[i]) << 4) + (fromHex(buffer[i+1])); 279 low = (fromHex(buffer[i+2]) << 4) + (fromHex(buffer[i+3])); 280 data = (fromHex(buffer[i+4]) << 4) + (fromHex(buffer[i+5])); 281 282 for (int i = 0; i < 3; i++) 283 { 284 writeCommand(PROGRAM[i]); 285 } 286 writeOp(high, low, data); 287 288 return waitForCompletion(high, low, data); 289 } 290 291 void setup() 292 { 293 Serial.begin(115200); 294 pinMode(CE, OUTPUT); 295 pinMode(OE, OUTPUT); 296 pinMode(WE, OUTPUT); 297 pinMode(A16, OUTPUT); 298 pinMode(CS1, OUTPUT); 299 pinMode(CS2, OUTPUT); 300 setDataOut(); 301 302 // Initial state for the flash device. 303 304 digitalWrite(CE, HIGH); 305 digitalWrite(OE, HIGH); 306 digitalWrite(WE, HIGH); 307 digitalWrite(A16, LOW); 308 309 // Initial state for the latches. 310 311 digitalWrite(CS1, LOW); 312 digitalWrite(CS2, LOW); 313 314 // Interface loop. 315 316 Serial.println("?"); 317 } 318 319 void loop() 320 { 321 if (nread += Serial.readBytesUntil('\n', inbuffer + nread, BUFSIZE - nread)) 322 { 323 switch (inbuffer[0]) 324 { 325 case 'R': 326 if (nread >= 5) 327 { 328 Serial.println(readCommand(inbuffer), HEX); 329 nread = 0; 330 } 331 break; 332 333 case 'W': 334 if (nread >= 7) 335 { 336 if (writeCommand(inbuffer)) 337 Serial.println("W"); 338 else 339 Serial.println("C"); 340 nread = 0; 341 } 342 break; 343 344 case 'E': 345 if (chipErase()) 346 Serial.println("E"); 347 else 348 Serial.println("C"); 349 nread = 0; 350 break; 351 352 case 'S': 353 if (nread >= 2) 354 { 355 if (sectorErase(inbuffer)) 356 Serial.println("S"); 357 else 358 Serial.println("C"); 359 nread = 0; 360 } 361 break; 362 363 case 'P': 364 if (nread >= 7) 365 { 366 if (program(inbuffer)) 367 Serial.println("P"); 368 else 369 Serial.println("C"); 370 nread = 0; 371 } 372 break; 373 374 default: 375 Serial.println(inbuffer[0]); 376 nread = 0; 377 break; 378 } 379 380 Serial.flush(); 381 } 382 } 383 384 extern "C" void __cxa_pure_virtual(void) { 385 while(1); 386 } 387 388 // tabstop=4 expandtab shiftwidth=4