985
|
1 /**
|
|
2 ******************************************************************************
|
|
3 * @copyright heinrichs weikamp
|
|
4 * @file externLogbookFlash.c
|
|
5 * @author heinrichs weikamp gmbh
|
|
6 * @date 07-Aug-2014
|
|
7 * @version V0.0.4
|
|
8 * @since 29-Sept-2015
|
|
9 * @brief Main File to access the new 1.8 Volt Spansion S25FS256S 256 Mbit (32 Mbyte)
|
|
10 * @bug
|
|
11 * @warning
|
|
12 *
|
|
13 @verbatim
|
|
14 ==============================================================================
|
|
15 ##### Logbook Header (TOC) #####
|
|
16 ==============================================================================
|
|
17 [..] Memory useage:
|
|
18 NEW: Spansion S25FS-S256S
|
|
19
|
|
20 only 8x 4KB and 1x 32KB, remaining is 64KB or 256KB
|
|
21 Sector Size (kbyte) Sector Count Sector Range Address Range (Byte Address) Notes
|
|
22 4 8 SA00 00000000h-00000FFFh
|
|
23 : :
|
|
24 SA07 00007000h-00007FFFh
|
|
25
|
|
26 32 1 SA08 00008000h-0000FFFFh
|
|
27
|
|
28 64 511 SA09 00010000h-0001FFFFh
|
|
29 : :
|
|
30 SA519 01FF0000h-01FFFFFFh
|
|
31 OLD:
|
|
32 1kB each header
|
|
33 with predive header at beginning
|
|
34 and postdive header with 0x400 HEADER2OFFSET
|
|
35 4kB (one erase) has two dives with 4 headers total
|
|
36 total of 512 kB (with 256 header ids (8 bit))
|
|
37 Size is 280 Byte (as of 25.Nov. 2014)
|
|
38
|
|
39 [..] Output to PC / UART is postdive header
|
|
40
|
|
41 [..] Block Protection Lock-Down is to erase logbook only
|
|
42
|
|
43 [..] Timing (see page 137 of LOGBOOK_V3_S25FS-S_00-271247.pdf
|
|
44 bulk erase is 2 minutes typ., 6 minutes max.
|
|
45
|
|
46 ==============================================================================
|
|
47 ##### DEMOMODE #####
|
|
48 ==============================================================================
|
|
49 151215: ext_flash_write_settings() is DISABLED!
|
|
50
|
|
51 ==============================================================================
|
|
52 ##### bug fixes #####
|
|
53 ==============================================================================
|
|
54 150917: end in header and length of sample was one byte too long
|
|
55 as stated by Jef Driesen email 15.09.2015
|
|
56
|
|
57 @endverbatim
|
|
58 ******************************************************************************
|
|
59 * @attention
|
|
60 *
|
|
61 * <h2><center>© COPYRIGHT(c) 2015 heinrichs weikamp</center></h2>
|
|
62 *
|
|
63 ******************************************************************************
|
|
64 */
|
|
65
|
|
66 /* Includes ------------------------------------------------------------------*/
|
|
67 #include "stm32f4xx_hal.h"
|
|
68 #include "externLogbookFlash.h"
|
|
69 #include "ostc.h"
|
|
70 #include "settings.h"
|
|
71 #include "gfx_engine.h"
|
|
72
|
|
73 /* Private types -------------------------------------------------------------*/
|
|
74 #define FLASHSTART 0x000000
|
|
75 //#define FLASHSTOP 0x01FFFFFF all 32 MB with 4byte addressing
|
|
76 #define FLASHSTOP 0x00FFFFFF
|
|
77 //#define FLASHSTOP 0x3FFFFF
|
|
78 #define RELEASE 1
|
|
79 #define HOLDCS 0
|
|
80
|
|
81 #define HEADER2OFFSET 0x400
|
|
82
|
|
83 typedef enum{
|
|
84 EF_HEADER,
|
|
85 EF_SAMPLE,
|
|
86 EF_DEVICEDATA,
|
|
87 EF_VPMDATA,
|
|
88 EF_SETTINGS,
|
|
89 EF_FIRMWARE,
|
|
90 EF_FIRMWARE2,
|
|
91 }which_ring_enum;
|
|
92
|
|
93
|
|
94 typedef struct{
|
|
95 uint8_t IsBusy:1;
|
|
96 uint8_t IsWriteEnabled:1;
|
|
97 uint8_t BlockProtect0:1;
|
|
98 uint8_t BlockProtect1:1;
|
|
99 uint8_t BlockProtect2:1;
|
|
100 uint8_t BlockProtect3:1;
|
|
101 uint8_t IsAutoAddressIncMode:1;
|
|
102 uint8_t BlockProtectL:1;
|
|
103 } extFlashStatusUbit8_t;
|
|
104
|
|
105 typedef union{
|
|
106 extFlashStatusUbit8_t ub;
|
|
107 uint8_t uw;
|
|
108 } extFlashStatusBit8_Type;
|
|
109
|
|
110
|
|
111 /* Exported variables --------------------------------------------------------*/
|
|
112
|
|
113 /* Private variables ---------------------------------------------------------*/
|
|
114
|
|
115 static uint32_t actualAddress = 0;
|
|
116 static uint32_t preparedPageAddress = 0;
|
|
117 static uint32_t closeSectorAddress = 0;
|
|
118 static uint32_t actualPointerHeader = 0;
|
|
119 static uint32_t actualPointerSample = 0;
|
|
120 static uint32_t actualPointerDevicedata = DDSTART;
|
|
121 static uint32_t actualPointerVPM = 0;
|
|
122 static uint32_t actualPointerSettings = SETTINGSSTART;
|
|
123 static uint32_t actualPointerFirmware = 0;
|
|
124 static uint32_t actualPointerFirmware2 = 0;
|
|
125
|
|
126 /* Private function prototypes -----------------------------------------------*/
|
|
127 static void chip_unselect(void);
|
|
128 static void chip_select(void);
|
|
129 static void write_spi(uint8_t data, uint8_t unselect_CS_afterwards);
|
|
130 static uint8_t read_spi(uint8_t unselect_CS_afterwards);
|
|
131 static void write_address(uint8_t unselect_CS_afterwards);
|
|
132 static void Error_Handler_extflash(void);
|
|
133 static void wait_chip_not_busy(void);
|
|
134 static void ext_flash_incf_address(uint8_t type);
|
|
135 //void ext_flash_incf_address_ring(void);
|
|
136
|
|
137 static void ext_flash_erase4kB(void);
|
|
138 static void ext_flash_erase32kB(void);
|
|
139 static void ext_flash_erase64kB(void);
|
|
140 static uint8_t ext_flash_erase_if_on_page_start(void);
|
|
141
|
|
142 static void ef_write_block(uint8_t * sendByte, uint32_t length, uint8_t type, uint8_t do_not_erase);
|
|
143
|
|
144 static void ext_flash_read_block(uint8_t *getByte, uint8_t type);
|
|
145 static void ext_flash_read_block_multi(void *getByte, uint32_t size, uint8_t type);
|
|
146 static void ext_flash_read_block_stop(void);
|
|
147
|
|
148 static void ef_hw_rough_delay_us(uint32_t delayUs);
|
|
149 static void ef_erase_64K(uint32_t blocks);
|
|
150
|
|
151
|
|
152 /* Exported functions --------------------------------------------------------*/
|
|
153
|
|
154 void ext_flash_write_firmware(uint8_t *pSample1, uint32_t length1)//, uint8_t *pSample2, uint32_t length2)
|
|
155 {
|
|
156 general32to8_Type lengthTransform;
|
|
157
|
|
158 lengthTransform.u32 = length1;
|
|
159
|
|
160 actualPointerFirmware = FWSTART;
|
|
161 ef_write_block(lengthTransform.u8,4, EF_FIRMWARE, 1);
|
|
162 ef_write_block(pSample1,length1, EF_FIRMWARE, 1);
|
|
163
|
|
164 // if(length2)
|
|
165 // ef_write_block(pSample2,length2, EF_FIRMWARE, 1);
|
|
166 }
|
|
167
|
|
168 uint8_t ext_flash_read_firmware_version(char *text)
|
|
169 {
|
|
170 uint32_t backup = actualAddress;
|
|
171 uint8_t buffer[4];
|
|
172
|
|
173 // + 4 for length data, see ext_flash_write_firmware
|
|
174 actualAddress = FWSTART + 4 + 0x10000;
|
|
175 ext_flash_read_block_start();
|
|
176 ext_flash_read_block(&buffer[0], EF_FIRMWARE);
|
|
177 ext_flash_read_block(&buffer[1], EF_FIRMWARE);
|
|
178 ext_flash_read_block(&buffer[2], EF_FIRMWARE);
|
|
179 ext_flash_read_block(&buffer[3], EF_FIRMWARE);
|
|
180
|
|
181 ext_flash_read_block_stop();
|
|
182 actualAddress = backup;
|
|
183
|
|
184 uint8_t ptr = 0;
|
|
185 text[ptr++] = 'V';
|
|
186 ptr += gfx_number_to_string(2,0,&text[ptr],buffer[0] & 0x3F);
|
|
187 text[ptr++] = '.';
|
|
188 ptr += gfx_number_to_string(2,0,&text[ptr],buffer[1] & 0x3F);
|
|
189 text[ptr++] = '.';
|
|
190 ptr += gfx_number_to_string(2,0,&text[ptr],buffer[2] & 0x3F);
|
|
191 text[ptr++] = ' ';
|
|
192 if(buffer[3])
|
|
193 {
|
|
194 text[ptr++] = 'b';
|
|
195 text[ptr++] = 'e';
|
|
196 text[ptr++] = 't';
|
|
197 text[ptr++] = 'a';
|
|
198 text[ptr++] = ' ';
|
|
199 }
|
|
200 return ptr;
|
|
201 }
|
|
202
|
|
203
|
|
204 uint32_t ext_flash_read_firmware(uint8_t *pSample1, uint32_t max_length, uint8_t *magicByte)
|
|
205 {
|
|
206 uint32_t backup = actualAddress;
|
|
207 general32to8_Type lengthTransform;
|
|
208
|
|
209 actualAddress = FWSTART;
|
|
210 ext_flash_read_block_start();
|
|
211
|
|
212 ext_flash_read_block(&lengthTransform.u8[0], EF_FIRMWARE);
|
|
213 ext_flash_read_block(&lengthTransform.u8[1], EF_FIRMWARE);
|
|
214 ext_flash_read_block(&lengthTransform.u8[2], EF_FIRMWARE);
|
|
215 ext_flash_read_block(&lengthTransform.u8[3], EF_FIRMWARE);
|
|
216
|
|
217
|
|
218 if(lengthTransform.u32 == 0xFFFFFFFF)
|
|
219 {
|
|
220 lengthTransform.u32 = 0xFFFFFFFF;
|
|
221 }
|
|
222 else
|
|
223 if(lengthTransform.u32 > max_length)
|
|
224 {
|
|
225 lengthTransform.u32 = 0xFF000000;
|
|
226 }
|
|
227 else
|
|
228 {
|
|
229 for(uint32_t i = 0; i<lengthTransform.u32; i++)
|
|
230 {
|
|
231 ext_flash_read_block(&pSample1[i], EF_FIRMWARE);
|
|
232 }
|
|
233
|
|
234 }
|
|
235
|
|
236 ext_flash_read_block_stop();
|
|
237
|
|
238 if(magicByte)
|
|
239 {
|
|
240 *magicByte = pSample1[0x10000 + 0x3E]; // 0x3E == 62
|
|
241 }
|
|
242
|
|
243 actualAddress = backup;
|
|
244 return lengthTransform.u32;
|
|
245 }
|
|
246
|
|
247
|
|
248 void ext_flash_write_firmware2(uint32_t offset, uint8_t *pSample1, uint32_t length1, uint8_t *pSample2, uint32_t length2)
|
|
249 {
|
|
250 general32to8_Type lengthTransform, offsetTransform;
|
|
251
|
|
252 lengthTransform.u32 = length1 + length2;
|
|
253 offsetTransform.u32 = offset;
|
|
254
|
|
255 actualPointerFirmware2 = FWSTART2;
|
|
256 ef_write_block(lengthTransform.u8,4, EF_FIRMWARE2, 1);
|
|
257 ef_write_block(offsetTransform.u8,4, EF_FIRMWARE2, 1);
|
|
258 ef_write_block(pSample1,length1, EF_FIRMWARE2, 1);
|
|
259 if(length2)
|
|
260 ef_write_block(pSample2,length2, EF_FIRMWARE2, 1);
|
|
261 }
|
|
262
|
|
263
|
|
264 uint32_t ext_flash_read_firmware2(uint32_t *offset, uint8_t *pSample1, uint32_t max_length1, uint8_t *pSample2, uint32_t max_length2)
|
|
265 {
|
|
266 uint32_t backup = actualAddress;
|
|
267 uint32_t length1, length2;
|
|
268 general32to8_Type lengthTransform, offsetTransform;
|
|
269
|
|
270 actualAddress = FWSTART2;
|
|
271 ext_flash_read_block_start();
|
|
272
|
|
273 ext_flash_read_block(&lengthTransform.u8[0], EF_FIRMWARE2);
|
|
274 ext_flash_read_block(&lengthTransform.u8[1], EF_FIRMWARE2);
|
|
275 ext_flash_read_block(&lengthTransform.u8[2], EF_FIRMWARE2);
|
|
276 ext_flash_read_block(&lengthTransform.u8[3], EF_FIRMWARE2);
|
|
277
|
|
278 ext_flash_read_block(&offsetTransform.u8[0], EF_FIRMWARE2);
|
|
279 ext_flash_read_block(&offsetTransform.u8[1], EF_FIRMWARE2);
|
|
280 ext_flash_read_block(&offsetTransform.u8[2], EF_FIRMWARE2);
|
|
281 ext_flash_read_block(&offsetTransform.u8[3], EF_FIRMWARE2);
|
|
282
|
|
283 *offset = offsetTransform.u32;
|
|
284
|
|
285 if(lengthTransform.u32 == 0xFFFFFFFF)
|
|
286 {
|
|
287 lengthTransform.u32 = 0xFFFFFFFF;
|
|
288 }
|
|
289 else
|
|
290 if(lengthTransform.u32 > max_length1 + max_length2)
|
|
291 {
|
|
292 lengthTransform.u32 = 0xFF000000;
|
|
293 }
|
|
294 else
|
|
295 {
|
|
296 if(lengthTransform.u32 < max_length1)
|
|
297 {
|
|
298 length1 = lengthTransform.u32;
|
|
299 length2 = 0;
|
|
300 }
|
|
301 else
|
|
302 {
|
|
303 length1 = max_length1;
|
|
304 length2 = lengthTransform.u32 - max_length1;
|
|
305 }
|
|
306
|
|
307 if(pSample1)
|
|
308 {
|
|
309 for(uint32_t i = 0; i<length1; i++)
|
|
310 {
|
|
311 ext_flash_read_block(&pSample1[i], EF_FIRMWARE2);
|
|
312 }
|
|
313 if(pSample2)
|
|
314 {
|
|
315 for(uint32_t i = 0; i<length2; i++)
|
|
316 {
|
|
317 ext_flash_read_block(&pSample2[i], EF_FIRMWARE2);
|
|
318 }
|
|
319 }
|
|
320 }
|
|
321 else if(pSample2)
|
|
322 {
|
|
323 actualAddress += length1;
|
|
324 for(uint32_t i = 0; i<length2; i++)
|
|
325 {
|
|
326 ext_flash_read_block(&pSample2[i], EF_FIRMWARE2);
|
|
327 }
|
|
328 }
|
|
329 }
|
|
330 ext_flash_read_block_stop();
|
|
331 actualAddress = backup;
|
|
332 return lengthTransform.u32;
|
|
333 }
|
|
334
|
|
335
|
|
336 void ext_flash_read_fixed_16_devicedata_blocks_formated_128byte_total(uint8_t *buffer)
|
|
337 {
|
|
338 SDeviceLine data[16];
|
|
339 uint8_t tempLengthIngnore;
|
|
340 uint16_t count;
|
|
341 uint8_t transfer;
|
|
342
|
|
343 RTC_DateTypeDef Sdate;
|
|
344 RTC_TimeTypeDef Stime;
|
|
345
|
|
346 actualAddress = DDSTART;
|
|
347
|
|
348 ext_flash_read_block_start();
|
|
349 ext_flash_read_block(&tempLengthIngnore, EF_DEVICEDATA);
|
|
350 ext_flash_read_block(&tempLengthIngnore, EF_DEVICEDATA);
|
|
351
|
|
352 ext_flash_read_block_multi((uint8_t *)data,16*3*4, EF_DEVICEDATA);
|
|
353 ext_flash_read_block_stop();
|
|
354
|
|
355 count = 0;
|
|
356 for(int i=0;i<16;i++)
|
|
357 {
|
|
358 transfer = (data[i].value_int32 >> 24) & 0xFF;
|
|
359 buffer[count++] = transfer;
|
|
360 transfer = (data[i].value_int32 >> 16) & 0xFF;
|
|
361 buffer[count++] = transfer;
|
|
362 transfer = (data[i].value_int32 >> 8) & 0xFF;
|
|
363 buffer[count++] = transfer;
|
|
364 transfer = (data[i].value_int32) & 0xFF;
|
|
365 buffer[count++] = transfer;
|
|
366
|
|
367 translateDate(data[i].date_rtc_dr, &Sdate);
|
|
368 translateTime(data[i].time_rtc_tr, &Stime);
|
|
369 buffer[count++] = Sdate.Year;
|
|
370 buffer[count++] = Sdate.Month;
|
|
371 buffer[count++] = Sdate.Date;
|
|
372 buffer[count++] = Stime.Hours;
|
|
373 }
|
|
374 }
|
|
375
|
|
376 void ext_flash_erase_firmware(void)
|
|
377 {
|
|
378 uint32_t size, blocks_64k;
|
|
379
|
|
380 actualAddress = FWSTART;
|
|
381 size = 1 + FWSTOP - FWSTART;
|
|
382 blocks_64k = size / 0x10000;
|
|
383 ef_erase_64K(blocks_64k);
|
|
384 }
|
|
385
|
|
386 void ext_flash_erase_firmware2(void)
|
|
387 {
|
|
388 uint32_t size, blocks_64k;
|
|
389
|
|
390 actualAddress = FWSTART2;
|
|
391 size = 1 + FWSTOP2 - FWSTART2;
|
|
392 blocks_64k = size / 0x10000;
|
|
393 ef_erase_64K(blocks_64k);
|
|
394 }
|
|
395
|
|
396
|
|
397
|
|
398 static void ext_flash_erase4kB(void)
|
|
399 {
|
|
400 wait_chip_not_busy();
|
|
401 write_spi(0x06,RELEASE);/* WREN */
|
|
402 write_spi(0x20,HOLDCS);/* sector erase cmd */
|
|
403 write_address(RELEASE);
|
|
404 }
|
|
405
|
|
406 /* be careful - might not work with entire family and other products
|
|
407 * see page 14 of LOGBOOK_V3_S25FS-S_00-271247.pdf
|
|
408 */
|
|
409 static void ext_flash_erase32kB(void)
|
|
410 {
|
|
411 uint32_t actualAddress_backup;
|
|
412
|
|
413 actualAddress_backup = actualAddress;
|
|
414 actualAddress = 0;
|
|
415 wait_chip_not_busy();
|
|
416 write_spi(0x06,RELEASE);/* WREN */
|
|
417 write_spi(0xD8,HOLDCS);/* sector erase cmd */
|
|
418 write_address(RELEASE);
|
|
419 actualAddress = actualAddress_backup;
|
|
420 }
|
|
421
|
|
422
|
|
423 static void ext_flash_erase64kB(void)
|
|
424 {
|
|
425 wait_chip_not_busy();
|
|
426 write_spi(0x06,RELEASE);/* WREN */
|
|
427 write_spi(0xD8,HOLDCS);/* sector erase cmd */
|
|
428 write_address(RELEASE);
|
|
429 }
|
|
430
|
|
431
|
|
432 void ext_flash_read_block_start(void)
|
|
433 {
|
|
434 wait_chip_not_busy();
|
|
435 write_spi(0x03,HOLDCS); /* WREN */
|
|
436 write_address(HOLDCS);
|
|
437 }
|
|
438
|
|
439 /* 4KB, 32KB, 64 KB, not the upper 16 MB with 4 Byte address at the moment */
|
|
440 static uint8_t ext_flash_erase_if_on_page_start(void)
|
|
441 {
|
|
442 if(actualAddress < 0x00008000)
|
|
443 {
|
|
444 /* 4K Byte is 0x1000 */
|
|
445 if((actualAddress & 0xFFF) == 0)
|
|
446 {
|
|
447 ext_flash_erase4kB();
|
|
448 return 1;
|
|
449 }
|
|
450 }
|
|
451 else
|
|
452 if(actualAddress < 0x00010000)
|
|
453 {
|
|
454 /* 32K Byte is only one page */
|
|
455 if(actualAddress == 0x00010000)
|
|
456 {
|
|
457 ext_flash_erase32kB();
|
|
458 return 1;
|
|
459 }
|
|
460 }
|
|
461 else
|
|
462 {
|
|
463 /* 64K Byte is 0x10000 */
|
|
464 if((actualAddress & 0xFFFF) == 0)
|
|
465 {
|
|
466 if(preparedPageAddress == actualAddress) /* has page already been prepared before? (at the moment for samples only) */
|
|
467 {
|
|
468 preparedPageAddress = 0;
|
|
469
|
|
470 }
|
|
471 else
|
|
472 {
|
|
473 ext_flash_erase64kB();
|
|
474 }
|
|
475 return 1;
|
|
476 }
|
|
477 }
|
|
478
|
|
479 return 0;
|
|
480 }
|
|
481
|
|
482
|
|
483 static void ext_flash_read_block(uint8_t *getByte, uint8_t type)
|
|
484 {
|
|
485 *getByte = read_spi(HOLDCS);/* read data */
|
|
486 ext_flash_incf_address(type);
|
|
487 }
|
|
488
|
|
489
|
|
490 static void ext_flash_read_block_multi(void *getByte, uint32_t size, uint8_t type)
|
|
491 {
|
|
492 uint8_t *data;
|
|
493 data = getByte;
|
|
494
|
|
495 for(uint32_t i=0;i<size;i++)
|
|
496 {
|
|
497 data[i] = read_spi(HOLDCS);/* read data */
|
|
498 ext_flash_incf_address(type);
|
|
499 }
|
|
500 }
|
|
501
|
|
502
|
|
503 static void ext_flash_read_block_stop(void)
|
|
504 {
|
|
505 chip_unselect();
|
|
506 }
|
|
507
|
|
508
|
|
509 /* Private functions ---------------------------------------------------------*/
|
|
510
|
|
511 static void ef_write_block(uint8_t * sendByte, uint32_t length, uint8_t type, uint8_t do_not_erase)
|
|
512 {
|
|
513 uint32_t remaining_page_size, remaining_length, remaining_space_to_ring_end;
|
|
514 uint32_t i=0;
|
|
515
|
|
516 if(!length)
|
|
517 return;
|
|
518
|
|
519 uint32_t ringStart, ringStop;
|
|
520
|
|
521 switch(type)
|
|
522 {
|
|
523 case EF_HEADER:
|
|
524 actualAddress = actualPointerHeader;
|
|
525 ringStart = HEADERSTART;
|
|
526 ringStop = HEADERSTOP;
|
|
527 break;
|
|
528 case EF_SAMPLE:
|
|
529 actualAddress = actualPointerSample;
|
|
530 ringStart = SAMPLESTART;
|
|
531 ringStop = SAMPLESTOP;
|
|
532 break;
|
|
533 case EF_DEVICEDATA:
|
|
534 actualAddress = actualPointerDevicedata;
|
|
535 ringStart = DDSTART;
|
|
536 ringStop = DDSTOP;
|
|
537 break;
|
|
538 case EF_VPMDATA:
|
|
539 actualAddress = actualPointerVPM;
|
|
540 ringStart = VPMSTART;
|
|
541 ringStop = VPMSTOP;
|
|
542 break;
|
|
543 case EF_SETTINGS:
|
|
544 actualAddress = actualPointerSettings;
|
|
545 ringStart = SETTINGSSTART;
|
|
546 ringStop = SETTINGSSTOP;
|
|
547 break;
|
|
548 case EF_FIRMWARE:
|
|
549 actualAddress = actualPointerFirmware;
|
|
550 ringStart = FWSTART;
|
|
551 ringStop = FWSTOP;
|
|
552 break;
|
|
553 case EF_FIRMWARE2:
|
|
554 actualAddress = actualPointerFirmware2;
|
|
555 ringStart = FWSTART2;
|
|
556 ringStop = FWSTOP2;
|
|
557 break;
|
|
558 default:
|
|
559 ringStart = FLASHSTART;
|
|
560 ringStop = FLASHSTOP;
|
|
561 break;
|
|
562 }
|
|
563 /* safety */
|
|
564 if(actualAddress < ringStart)
|
|
565 actualAddress = ringStart;
|
|
566
|
|
567 if(do_not_erase == 0)
|
|
568 {
|
|
569 ext_flash_erase_if_on_page_start();
|
|
570 }
|
|
571
|
|
572 while( i<length)
|
|
573 {
|
|
574 ef_hw_rough_delay_us(5);
|
|
575 wait_chip_not_busy();
|
|
576 write_spi(0x06,RELEASE); /* WREN */
|
|
577 write_spi(0x02,HOLDCS); /* write cmd */
|
|
578 write_address(HOLDCS);
|
|
579
|
|
580 remaining_length = length - i;
|
|
581 remaining_page_size = 0xFF - (uint8_t)(actualAddress & 0xFF) +1;
|
|
582 remaining_space_to_ring_end = ringStop - actualAddress;
|
|
583
|
|
584 if(remaining_length >= 256)
|
|
585 {
|
|
586 remaining_length = 255; /* up to 256 bytes may be written in one burst. Last byte is written with release */
|
|
587 }
|
|
588 else
|
|
589 {
|
|
590 remaining_length--; /* last byte needed for release */
|
|
591 }
|
|
592 if(remaining_length >= (remaining_page_size) ) /* use 256 byte page and calculate number of bytes left */
|
|
593 {
|
|
594 remaining_length = remaining_page_size - 1;
|
|
595 }
|
|
596 if( (remaining_space_to_ring_end >= 256))
|
|
597 {
|
|
598 for(int j=0; j<remaining_length; j++)
|
|
599 {
|
|
600 write_spi(sendByte[i],HOLDCS);/* write data */
|
|
601 actualAddress++;
|
|
602 i++;
|
|
603 }
|
|
604 }
|
|
605 /* byte with RELEASE */
|
|
606 write_spi(sendByte[i],RELEASE);/* write data */
|
|
607 actualAddress++;
|
|
608 i++;
|
|
609
|
|
610 if(actualAddress > ringStop)
|
|
611 actualAddress = ringStart;
|
|
612
|
|
613 if(do_not_erase == 0)
|
|
614 ext_flash_erase_if_on_page_start();
|
|
615 }
|
|
616 switch(type)
|
|
617 {
|
|
618 case EF_HEADER:
|
|
619 actualPointerHeader = actualAddress;
|
|
620 break;
|
|
621 case EF_SAMPLE:
|
|
622 actualPointerSample = actualAddress;
|
|
623 break;
|
|
624 case EF_DEVICEDATA:
|
|
625 actualPointerDevicedata = actualAddress;
|
|
626 break;
|
|
627 case EF_VPMDATA:
|
|
628 actualPointerVPM = actualAddress;
|
|
629 break;
|
|
630 case EF_SETTINGS:
|
|
631 actualPointerSettings = actualAddress;
|
|
632 break;
|
|
633 case EF_FIRMWARE:
|
|
634 actualPointerFirmware = actualAddress;
|
|
635 break;
|
|
636 case EF_FIRMWARE2:
|
|
637 actualPointerFirmware2 = actualAddress;
|
|
638 break;
|
|
639 default:
|
|
640 break;
|
|
641 }
|
|
642 }
|
|
643
|
|
644
|
|
645 static void ef_erase_64K(uint32_t blocks)
|
|
646 {
|
|
647 for(uint32_t i = 0; i < blocks; i++)
|
|
648 {
|
|
649 wait_chip_not_busy();
|
|
650 write_spi(0x06,RELEASE);/* WREN */
|
|
651 write_spi(0xD8,HOLDCS);/* 64k erase cmd */
|
|
652 write_address(RELEASE);
|
|
653 actualAddress += 0x10000;
|
|
654 HAL_Delay(25);
|
|
655 }
|
|
656 }
|
|
657
|
|
658 static void chip_unselect(void)
|
|
659 {
|
|
660 HAL_GPIO_WritePin(EXTFLASH_CSB_GPIO_PORT,EXTFLASH_CSB_PIN,GPIO_PIN_SET); // chip select
|
|
661 }
|
|
662
|
|
663 static void chip_select(void)
|
|
664 {
|
|
665 HAL_GPIO_WritePin(EXTFLASH_CSB_GPIO_PORT,EXTFLASH_CSB_PIN,GPIO_PIN_RESET); // chip select
|
|
666 }
|
|
667
|
|
668 static uint8_t read_spi(uint8_t unselect_CS_afterwards)
|
|
669 {
|
|
670 uint8_t byte;
|
|
671
|
|
672 chip_select();
|
|
673
|
|
674 if(HAL_SPI_Receive(&hspiDisplay, &byte, 1, 10000) != HAL_OK)
|
|
675 Error_Handler_extflash();
|
|
676
|
|
677 while (HAL_SPI_GetState(&hspiDisplay) != HAL_SPI_STATE_READY)
|
|
678 {
|
|
679 }
|
|
680 if(unselect_CS_afterwards)
|
|
681 chip_unselect();
|
|
682
|
|
683 return byte;
|
|
684 }
|
|
685
|
|
686
|
|
687 static void write_spi(uint8_t data, uint8_t unselect_CS_afterwards)
|
|
688 {
|
|
689 chip_select();
|
|
690
|
|
691 if(HAL_SPI_Transmit(&hspiDisplay, &data, 1, 10000) != HAL_OK)
|
|
692 Error_Handler_extflash();
|
|
693
|
|
694 while (HAL_SPI_GetState(&hspiDisplay) != HAL_SPI_STATE_READY)
|
|
695 {
|
|
696 }
|
|
697 if(unselect_CS_afterwards)
|
|
698 chip_unselect();
|
|
699 }
|
|
700
|
|
701
|
|
702 static void write_address(uint8_t unselect_CS_afterwards)
|
|
703 {
|
|
704 uint8_t hi, med ,lo;
|
|
705
|
|
706 hi = (actualAddress >> 16) & 0xFF;
|
|
707 med = (actualAddress >> 8) & 0xFF;
|
|
708 lo = actualAddress & 0xFF;
|
|
709
|
|
710 write_spi(hi, HOLDCS);
|
|
711 write_spi(med, HOLDCS);
|
|
712 write_spi(lo, unselect_CS_afterwards);
|
|
713 }
|
|
714
|
|
715
|
|
716 static void wait_chip_not_busy(void)
|
|
717 {
|
|
718 uint8_t status;
|
|
719
|
|
720 chip_unselect();
|
|
721
|
|
722 write_spi(0x05,HOLDCS); /* RDSR */
|
|
723 status = read_spi(HOLDCS);/* read status */
|
|
724 while(status & 0x01)
|
|
725 {
|
|
726 HAL_Delay(1);
|
|
727 status = read_spi(HOLDCS);/* read status */
|
|
728 }
|
|
729 chip_unselect();
|
|
730 }
|
|
731
|
|
732
|
|
733 static void ext_flash_incf_address(uint8_t type)
|
|
734 {
|
|
735 uint32_t ringStart, ringStop;
|
|
736
|
|
737 actualAddress += 1;
|
|
738
|
|
739 switch(type)
|
|
740 {
|
|
741 case EF_HEADER:
|
|
742 ringStart = HEADERSTART;
|
|
743 ringStop = HEADERSTOP;
|
|
744 break;
|
|
745 case EF_SAMPLE:
|
|
746 ringStart = SAMPLESTART;
|
|
747 ringStop = SAMPLESTOP;
|
|
748 break;
|
|
749 case EF_DEVICEDATA:
|
|
750 ringStart = DDSTART;
|
|
751 ringStop = DDSTOP;
|
|
752 break;
|
|
753 case EF_VPMDATA:
|
|
754 ringStart = VPMSTART;
|
|
755 ringStop = VPMSTOP;
|
|
756 break;
|
|
757 case EF_SETTINGS:
|
|
758 ringStart = SETTINGSSTART;
|
|
759 ringStop = SETTINGSSTOP;
|
|
760 break;
|
|
761 case EF_FIRMWARE:
|
|
762 ringStart = FWSTART;
|
|
763 ringStop = FWSTOP;
|
|
764 break;
|
|
765 case EF_FIRMWARE2:
|
|
766 ringStart = FWSTART2;
|
|
767 ringStop = FWSTOP2;
|
|
768 break;
|
|
769 default:
|
|
770 ringStart = FLASHSTART;
|
|
771 ringStop = FLASHSTOP;
|
|
772 break;
|
|
773 }
|
|
774
|
|
775 if((actualAddress < ringStart) || (actualAddress > ringStop))
|
|
776 actualAddress = ringStart;
|
|
777 }
|
|
778
|
|
779 static void ef_hw_rough_delay_us(uint32_t delayUs)
|
|
780 {
|
|
781 if(!delayUs)
|
|
782 return;
|
|
783 delayUs*= 12;
|
|
784 while(delayUs--);
|
|
785 return;
|
|
786 }
|
|
787
|
|
788 static void Error_Handler_extflash(void)
|
|
789 {
|
|
790 while(1)
|
|
791 {
|
|
792 }
|
|
793 }
|
|
794
|
|
795 void ext_flash_CloseSector(void)
|
|
796 {
|
|
797 uint32_t actualAddressBackup = actualAddress;
|
|
798 int i=0;
|
|
799
|
|
800 if(closeSectorAddress != 0)
|
|
801 {
|
|
802 /* write some dummy bytes to the sector which is currently used for storing samples. This is done to "hide" problem if function is calles again */
|
|
803 actualAddress = closeSectorAddress;
|
|
804
|
|
805 wait_chip_not_busy();
|
|
806 write_spi(0x06,RELEASE); /* WREN */
|
|
807 write_spi(0x02,HOLDCS); /* write cmd */
|
|
808 write_address(HOLDCS);
|
|
809 for(i = 0; i<8; i++)
|
|
810 {
|
|
811 write_spi(0xA5,HOLDCS);/* write data */
|
|
812 actualAddress++;
|
|
813 }
|
|
814 /* byte with RELEASE */
|
|
815 write_spi(0xA5,RELEASE);/* write data */
|
|
816 actualAddress = actualAddressBackup;
|
|
817 closeSectorAddress = 0;
|
|
818 }
|
|
819 }
|
|
820
|
|
821
|
|
822 uint8_t ext_flash_erase_firmware_if_not_empty(void)
|
|
823 {
|
|
824 const uint8_t TESTSIZE_FW = 4;
|
|
825
|
|
826 uint8_t data[TESTSIZE_FW];
|
|
827 uint8_t notEmpty = 0;
|
|
828
|
|
829 actualAddress = FWSTART;
|
|
830 ext_flash_read_block_start();
|
|
831 for(int i = 0; i < TESTSIZE_FW; i++)
|
|
832 {
|
|
833 ext_flash_read_block(&data[i], EF_FIRMWARE);
|
|
834 if(data[i] != 0xFF)
|
|
835 notEmpty = 1;
|
|
836 }
|
|
837 ext_flash_read_block_stop();
|
|
838
|
|
839 if(notEmpty)
|
|
840 {
|
|
841 ext_flash_erase_firmware();
|
|
842 return 1;
|
|
843 }
|
|
844 else
|
|
845 return 0;
|
|
846 }
|
|
847
|
|
848 uint8_t ext_flash_erase_firmware2_if_not_empty(void)
|
|
849 {
|
|
850 const uint8_t TESTSIZE_FW = 4;
|
|
851
|
|
852 uint8_t data[TESTSIZE_FW];
|
|
853 uint8_t notEmpty = 0;
|
|
854
|
|
855 actualAddress = FWSTART2;
|
|
856 ext_flash_read_block_start();
|
|
857 for(int i = 0; i < TESTSIZE_FW; i++)
|
|
858 {
|
|
859 ext_flash_read_block(&data[i], EF_FIRMWARE2);
|
|
860 if(data[i] != 0xFF)
|
|
861 notEmpty = 1;
|
|
862 }
|
|
863 ext_flash_read_block_stop();
|
|
864
|
|
865 if(notEmpty)
|
|
866 {
|
|
867 ext_flash_erase_firmware2();
|
|
868 return 1;
|
|
869 }
|
|
870 else
|
|
871 return 0;
|
|
872 }
|