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 i = 1; 174 175 high |= (fromHex(buffer[i]) << 4) + (fromHex(buffer[i+1])); 176 low = (fromHex(buffer[i+2]) << 4) + (fromHex(buffer[i+3])); 177 178 return readOp(high, low); 179 } 180 181 bool writeCommand(const char buffer[]) 182 { 183 int high, low, data, i; 184 185 if (nread > 7) 186 { 187 high = fromHex(buffer[1]) << 8; 188 i = 2; 189 } 190 else 191 i = 1; 192 193 high |= (fromHex(buffer[i]) << 4) + (fromHex(buffer[i+1])); 194 low = (fromHex(buffer[i+2]) << 4) + (fromHex(buffer[i+3])); 195 data = (fromHex(buffer[i+4]) << 4) + (fromHex(buffer[i+5])); 196 197 writeOp(high, low, data); 198 199 return true; 200 } 201 202 bool waitForCompletion(int high, int low, int written) 203 { 204 int data, then = millis(); 205 206 setDataIn(); 207 digitalWrite(CE, LOW); 208 digitalWrite(OE, LOW); 209 210 do 211 { 212 delay(10); 213 data = sampleData(); 214 } while ( 215 ((data & 0x80) != (written & 0x80)) && 216 ((data & 0x20) == 0) && 217 (millis() - then < 2000) 218 ); 219 220 digitalWrite(OE, HIGH); 221 digitalWrite(CE, HIGH); 222 setDataOut(); 223 delay(10); 224 return readOp(high, low) == written; 225 } 226 227 bool chipErase() 228 { 229 for (int i = 0; i < 5; i++) 230 { 231 writeCommand(ERASE[i]); 232 } 233 writeOp(0x55, 0x55, 0x30); 234 return waitForCompletion(0, 0, 0xff); 235 } 236 237 bool sectorErase(const char buffer[]) 238 { 239 int high; 240 241 // 3-bit number shifted to A16...A14 with A16 discarded. 242 // Thus, only sectors from 0 to 3 are supported. 243 244 high = (fromHex(buffer[1]) << 6) & 0xff; 245 246 for (int i = 0; i < 5; i++) 247 { 248 writeCommand(ERASE[i]); 249 } 250 writeOp(high, 0, 0x30); 251 252 // Result of erase if 0xff written to all locations. 253 254 return waitForCompletion(high, 0, 0xff); 255 } 256 257 bool program(const char buffer[]) 258 { 259 int high, low, data; 260 261 high = (fromHex(buffer[1]) << 4) + (fromHex(buffer[2])); 262 low = (fromHex(buffer[3]) << 4) + (fromHex(buffer[4])); 263 data = (fromHex(buffer[5]) << 4) + (fromHex(buffer[6])); 264 265 for (int i = 0; i < 3; i++) 266 { 267 writeCommand(PROGRAM[i]); 268 } 269 writeOp(high, low, data); 270 271 return waitForCompletion(high, low, data); 272 } 273 274 void setup() 275 { 276 Serial.begin(115200); 277 pinMode(CE, OUTPUT); 278 pinMode(OE, OUTPUT); 279 pinMode(WE, OUTPUT); 280 pinMode(A16, OUTPUT); 281 pinMode(CS1, OUTPUT); 282 pinMode(CS2, OUTPUT); 283 setDataOut(); 284 285 // Initial state for the flash device. 286 287 digitalWrite(CE, HIGH); 288 digitalWrite(OE, HIGH); 289 digitalWrite(WE, HIGH); 290 digitalWrite(A16, LOW); 291 292 // Initial state for the latches. 293 294 digitalWrite(CS1, LOW); 295 digitalWrite(CS2, LOW); 296 297 // Interface loop. 298 299 Serial.println("?"); 300 } 301 302 void loop() 303 { 304 if (nread += Serial.readBytesUntil('\n', inbuffer + nread, BUFSIZE - nread)) 305 { 306 switch (inbuffer[0]) 307 { 308 case 'R': 309 if (nread >= 5) 310 { 311 Serial.println(readCommand(inbuffer), HEX); 312 nread = 0; 313 } 314 break; 315 316 case 'W': 317 if (nread >= 7) 318 { 319 if (writeCommand(inbuffer)) 320 Serial.println("W"); 321 else 322 Serial.println("C"); 323 nread = 0; 324 } 325 break; 326 327 case 'E': 328 if (chipErase()) 329 Serial.println("E"); 330 else 331 Serial.println("C"); 332 nread = 0; 333 break; 334 335 case 'S': 336 if (nread >= 2) 337 { 338 if (sectorErase(inbuffer)) 339 Serial.println("S"); 340 else 341 Serial.println("C"); 342 nread = 0; 343 } 344 break; 345 346 case 'P': 347 if (nread >= 7) 348 { 349 if (program(inbuffer)) 350 Serial.println("P"); 351 else 352 Serial.println("C"); 353 nread = 0; 354 } 355 break; 356 357 default: 358 Serial.println(inbuffer[0]); 359 nread = 0; 360 break; 361 } 362 363 Serial.flush(); 364 } 365 } 366 367 extern "C" void __cxa_pure_virtual(void) { 368 while(1); 369 } 370 371 // tabstop=4 expandtab shiftwidth=4