comparison spiflash.c @ 80:1a4573062b37

Reshuffle in preparation for being able to have a common API for SPI flash and (emulated) EEPROM.
author Daniel O'Connor <darius@dons.net.au>
date Sun, 07 Jul 2013 22:49:02 +0930
parents flash.c@85f16813c730
children 05ba84c7da97
comparison
equal deleted inserted replaced
79:cecb0506f4b8 80:1a4573062b37
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <assert.h>
6
7 #include "stm32f10x.h"
8 #include "spi.h"
9 #include "spiflash.h"
10
11 #define FL_SELECT() GPIO_ResetBits(GPIOA, GPIO_Pin_4)
12 #define FL_DESELECT() GPIO_SetBits(GPIOA, GPIO_Pin_4)
13
14 const char *flstattbl[] = {
15 "BUSY",
16 "WEL",
17 "BP0",
18 "BP1",
19 "BP2",
20 "BP3",
21 "AAI",
22 "BPL"
23 };
24
25 #define RW_IDLE 0
26 #define RW_RUNNING 1
27
28 static int writestate = RW_IDLE;
29 static int readstate = RW_IDLE;
30 #if 0
31 void
32 spiflashcmd(int argc, char **argv) {
33 uint8_t status, tmp, len;
34 uint32_t addr;
35
36 if (argc == 0) {
37 fputs("No command specified\n", stdout);
38 return;
39 }
40
41 if (!strcmp(argv[0], "str")) {
42 status = spiflashreadstatus();
43 fputs("Status = ", stdout);
44 for (unsigned int i = 0; i < sizeof(flstattbl) / sizeof(flstattbl[0]); i++)
45 if (status & 1 << i) {
46 fputs(flstattbl[i], stdout);
47 fputs(" ", stdout);
48 }
49 printf("(0x%02x)\n", status);
50 } else if (!strcmp(argv[0], "stw")) {
51 if (argc != 2) {
52 fputs("Incorrect number of arguments\n", stdout);
53 return;
54 }
55 tmp = atoi(argv[1]);
56 spiflashwritestatus(tmp);
57 status = spiflashreadstatus();
58 printf("Wrote 0x%02x to status, now 0x%02x\n", tmp, status);
59 } else if (!strcmp(argv[0], "er")) {
60 if (argc != 2) {
61 fputs("Incorrect number of arguments\n", stdout);
62 return;
63 }
64 addr = atoi(argv[1]);
65 spiflash4kerase(addr);
66 printf("Erased 0x%x\n", (unsigned int)addr);
67 } else if (!strcmp(argv[0], "rd")) {
68 if (argc < 2) {
69 fputs("Incorrect number of arguments\n", stdout);
70 return;
71 }
72
73 addr = atoi(argv[1]);
74
75 if (argc > 2)
76 len = atoi(argv[2]);
77 else
78 len = 16;
79
80 spiflashstartread(addr);
81
82 for (uint32_t i = 0; i < len; i++)
83 printf("Read 0x%02x from 0x%06x\n", spiflashreadbyte(), (unsigned int)(addr + i));
84 spiflashstopread();
85
86 fputs("\n", stdout);
87 } else if (!strcmp(argv[0], "wr")) {
88 if (argc < 2) {
89 fputs("Incorrect number of arguments\n", stdout);
90 return;
91 }
92
93 addr = atoi(argv[1]);
94
95 if (argc > 2)
96 len = atoi(argv[2]);
97 else
98 len = 16;
99
100 for (int i = 0; i < 16; i += 2) {
101 uint16_t data;
102 data = ((i + 1) << 8) | i;
103 printf("Writing 0x%04x to 0x%06x\n", data, (unsigned int)(addr + i));
104
105 if (i == 0)
106 spiflashstartwrite(addr, data);
107 else
108 spiflashwriteword(data);
109 }
110 spiflashstopwrite();
111 } else if (!strcmp(argv[0], "id")) {
112 printf("Flash ID = 0x%04hx (expect 0xbf41)\n", spiflashreadid());
113 } else {
114 fputs("Unknown sub command\n", stdout);
115 return;
116 }
117 }
118 #endif
119 void
120 spiflash4kerase(uint32_t addr) {
121 spiflashenablewrite(); /* Enable writing */
122
123 FL_SELECT(); /* Select device */
124
125 SPI_WriteByte(FL_4KERASE); /* Send command */
126 SPI_WriteByte(addr >> 16); /* Send address */
127 SPI_WriteByte(addr >> 8);
128 SPI_WriteByte(addr);
129
130 FL_DESELECT();
131
132 //fputs("4k erase ", stdout);
133 spiflashwait();
134 }
135
136 void
137 spiflashwait(void) {
138 uint8_t cnt;
139
140 /* Wait for not BUSY */
141 for (cnt = 0; (spiflashreadstatus() & FL_BUSY) != 0; cnt++)
142 ;
143
144 //printf("cnt = %d\n", cnt);
145 }
146
147 uint16_t
148 spiflashreadid(void) {
149 uint8_t fac, dev;
150
151 FL_SELECT(); /* Select device */
152
153 SPI_WriteByte(FL_RDID); /* Send command */
154 SPI_WriteByte(0x00); /* Send address cycles (ID data starts at 0) */
155 SPI_WriteByte(0x00);
156 SPI_WriteByte(0x00);
157 fac = SPI_WriteByte(0x00); /* Read ID */
158 dev = SPI_WriteByte(0x00);
159
160 FL_DESELECT(); /* De-select device */
161
162 return fac << 8 | dev;
163 }
164
165 void
166 spiflashenablewrite(void) {
167 FL_SELECT(); /* Select device */
168
169 SPI_WriteByte(FL_WREN); /* Send command */
170
171 FL_DESELECT(); /* De-select device */
172 }
173
174 uint8_t
175 spiflashreadstatus(void) {
176 uint8_t status;
177
178 FL_SELECT(); /* Select device */
179
180 SPI_WriteByte(FL_RDSR); /* Send command */
181 SPI_WriteByte(0x00); /* Send dummy byte for address cycle */
182 status = SPI_WriteByte(0x00); /* Read status */
183
184 FL_DESELECT(); /* De-select device */
185
186 return status;
187 }
188
189 void
190 spiflashwritestatus(uint8_t status) {
191 /* Enable status write */
192 FL_SELECT(); /* Select device */
193 SPI_WriteByte(FL_EWSR); /* Send command */
194 SPI_WriteByte(0x00); /* Send data byte */
195 FL_DESELECT();
196
197 /* Actually write status */
198 FL_SELECT(); /* Re-select device for new command */
199 SPI_WriteByte(FL_WRSR); /* Send command */
200 SPI_WriteByte(status); /* Send data byte */
201 FL_DESELECT(); /* De-select device */
202 }
203
204 uint8_t
205 spiflashread(uint32_t addr) {
206 uint8_t data;
207
208 FL_SELECT(); /* Select device */
209
210 SPI_WriteByte(FL_READ); /* Send command */
211 SPI_WriteByte(addr >> 16); /* Send address */
212 SPI_WriteByte(addr >> 8);
213 SPI_WriteByte(addr);
214 data = SPI_WriteByte(0x00); /* Read data */
215
216 FL_DESELECT(); /* De-select device */
217
218 return data;
219 }
220
221 void
222 spiflashwrite(uint32_t addr, uint8_t data) {
223 spiflashwait();
224 spiflashenablewrite(); /* Enable writes */
225
226 FL_SELECT(); /* Select device */
227
228 SPI_WriteByte(FL_BYTEPROG); /* Send command */
229 SPI_WriteByte(addr >> 16); /* Send address */
230 SPI_WriteByte(addr >> 8);
231 SPI_WriteByte(addr);
232 SPI_WriteByte(data); /* Write data */
233
234 FL_DESELECT(); /* De-select device */
235
236 }
237
238 /*
239 * fStream reading looks like so
240 *
241 */
242
243 void
244 spiflashstartread(uint32_t addr) {
245 assert(readstate == RW_IDLE);
246
247 FL_SELECT(); /* Select device */
248
249 SPI_WriteByte(FL_READ); /* Send command */
250 SPI_WriteByte(addr >> 16); /* Send address */
251 SPI_WriteByte(addr >> 8);
252 SPI_WriteByte(addr);
253
254 readstate = RW_RUNNING;
255 }
256
257 uint8_t
258 spiflashreadbyte(void) {
259 assert(readstate == RW_RUNNING);
260 return SPI_WriteByte(0x00); /* Read data */
261 }
262
263 void
264 spiflashstopread(void) {
265 assert(readstate == RW_RUNNING);
266
267 FL_DESELECT();
268
269 readstate = RW_IDLE;
270 }
271
272 /*
273 * Auto increment writing looks like so
274 *
275 * Enable writing CS, WREN, nCS
276 * Send start address & first data word CS, AAI + addr + data, nCS
277 * Send subsequent words wait for nBUSY, CS, AAI + data, nCS
278 * ...
279 * Disable writing CS, WRDI, nCS
280 *
281 * XXX: EBSY command links SO to flash busy state, I don't think the
282 * STM32 could sample it without switching out of SPI mode.
283 */
284 void
285 spiflashstartwrite(uint32_t addr, uint16_t data) {
286 assert(writestate == RW_IDLE);
287
288 spiflashenablewrite(); /* Enable writes */
289
290 FL_SELECT(); /* Select device */
291
292 SPI_WriteByte(FL_AAIWP); /* Send command */
293 SPI_WriteByte(addr >> 16);
294 SPI_WriteByte(addr >> 8);
295 SPI_WriteByte(addr & 0xff); /* Send address */
296
297 SPI_WriteByte(data & 0xff); /* Write LSB */
298 SPI_WriteByte(data >> 8); /* Write MSB */
299
300 FL_DESELECT();
301
302 writestate = RW_RUNNING;
303 }
304
305 void
306 spiflashwriteword(uint16_t data) {
307 assert(writestate == RW_RUNNING);
308
309 //fputs("write word ", stdout);
310 spiflashwait(); /* Wait until not busy */
311
312 FL_SELECT(); /* Select device */
313
314 SPI_WriteByte(FL_AAIWP); /* Send command */
315 SPI_WriteByte(data & 0xff); /* Write LSB */
316 SPI_WriteByte(data >> 8); /* Write MSB */
317
318 FL_DESELECT(); /* De-select device */
319 }
320
321 void
322 spiflashstopwrite(void) {
323 assert(writestate == RW_RUNNING);
324
325 //fputs("flash stop write start ", stdout);
326 spiflashwait(); /* Wait until not busy */
327
328 FL_SELECT(); /* Select device */
329
330 SPI_WriteByte(FL_WRDI); /* Send command */
331
332 FL_DESELECT(); /* Deselect device */
333
334 //fputs("flash stop write end ", stdout);
335 spiflashwait(); /* Wait until not busy */
336
337 writestate = RW_IDLE;
338 }
339
340 int
341 spiflashreadblock(uint32_t addr, uint32_t len, void *_data) {
342 uint8_t *data = _data;
343 uint32_t flashcrc, ramcrc;
344
345 /* Must be a multiple of 4 due to CRC check */
346 assert(len % 4 == 0);
347
348 spiflashstartread(addr);
349 CRC_ResetDR();
350 for (int i = len; i > 0; i--) {
351 *data = spiflashreadbyte();
352 CRC_CalcCRC(*data);
353 data++;
354 }
355
356 flashcrc = spiflashreadbyte();
357 flashcrc |= spiflashreadbyte() << 8;
358 flashcrc |= spiflashreadbyte() << 16;
359 flashcrc |= spiflashreadbyte() << 24;
360
361 spiflashstopread();
362
363 ramcrc = CRC_GetCRC();
364
365 /* printf("RAM CRC 0x%08x Flash CRC 0x%08x\n", (uint)ramcrc, (uint)flashcrc); */
366 if (ramcrc == flashcrc)
367 return 1;
368 else
369 return 0;
370 }
371
372 uint32_t
373 spiflashcrcblock(uint32_t addr, uint32_t len) {
374 assert(len % 4 == 0);
375
376 CRC_ResetDR();
377
378 spiflashstartread(addr);
379 for (int i = len; i > 0; i--)
380 CRC_CalcCRC(spiflashreadbyte());
381
382 spiflashstopread();
383
384 return CRC_GetCRC();
385 }
386
387 int
388 spiflashwriteblock(uint32_t addr, uint32_t len, void *_data) {
389 uint16_t *data = _data;
390 uint32_t crc, vcrc;
391
392 //printf("Writing %u bytes to 0x%06x\n", (uint)len, (uint)addr);
393
394 /* Ensure data is
395 * - 16 bit aligned
396 * - a multiple of 32 bits in length (for CRCs, the flash only need 16 bits)
397 * - not longer than a sector
398 */
399 assert(addr % 2 == 0);
400 assert(len % 4 == 0);
401 assert(len <= 4096);
402
403 /* Disable write protect */
404 spiflashwritestatus(0x00);
405
406 /* Erase sector */
407 spiflash4kerase(addr);
408
409 CRC_ResetDR();
410
411 /* Write data */
412 for (uint i = 0; i < len / 2; i++) {
413 if (i == 0)
414 spiflashstartwrite(addr, *data);
415 else
416 spiflashwriteword(*data);
417 CRC_CalcCRC(*data);
418 data++;
419 }
420
421 /* Calculate CRC */
422 crc = CRC_GetCRC();
423
424 //printf("CRC is 0x%08x\n", (uint)crc);
425
426 /* Write CRC */
427 spiflashwriteword(crc);
428 spiflashwriteword(crc >> 16);
429
430 spiflashstopwrite();
431
432 /* Read back and check CRC */
433 vcrc = spiflashcrcblock(addr, len);
434 if (vcrc != crc)
435 return 1;
436 else
437 return 0;
438 }
439
440 void
441 spiflashprintstatus(uint8_t status, FILE *out) {
442 for (unsigned int i = 0; i < sizeof(flstattbl) / sizeof(flstattbl[0]); i++)
443 if (status & 1 << i) {
444 fputs(flstattbl[i], out);
445 fputs(" ", out);
446 }
447 }