EFM32 Zero Gecko Software Documentation  efm32zg-doc-4.2.1
norflash.c
Go to the documentation of this file.
1 /***************************************************************************/
20 #include "em_common.h"
21 #include "em_ebi.h"
22 #include "norflash.h"
23 
26 static volatile uint16_t *flashBase;
27 static bool flashInitialized = false;
28 static NORFLASH_Info_TypeDef flashInfo;
29 
30 static int flashInterrogate(void);
31 static int flashPoll(uint32_t addr, uint16_t data);
32 static void flashReset(void);
33 static void flashUnlockCmd(void);
34 static int flashWriteBuffer(uint32_t sectorAddr, uint32_t addr,
35  uint16_t *data, uint32_t count);
36 
39 /***************************************************************************/
49 bool NORFLASH_AddressValid(uint32_t addr)
50 {
51  if (!flashInitialized)
52  {
53  if (flashInterrogate() != NORFLASH_STATUS_OK)
54  return false;
55  }
56 
57  if ((addr >= flashInfo.baseAddress) &&
58  (addr < (flashInfo.baseAddress + flashInfo.deviceSize)))
59  return true;
60 
61  return false;
62 }
63 
64 /***************************************************************************/
75 {
76  if (!flashInitialized)
77  {
78  if (flashInterrogate() != NORFLASH_STATUS_OK)
79  return NULL;
80  }
81 
82  return &flashInfo;
83 }
84 
85 /***************************************************************************/
94 {
95  int status;
96 
97  if (!flashInitialized)
98  {
99  status = flashInterrogate();
100 
101  if (status != NORFLASH_STATUS_OK)
102  return status;
103  }
104 
105  flashUnlockCmd();
106 
107  flashBase[0x555] = 0x80;
108  flashBase[0x555] = 0xAA;
109  flashBase[0x2AA] = 0x55;
110  flashBase[0x555] = 0x10;
111 
112  return flashPoll(flashInfo.baseAddress, 0xFFFF);
113 }
114 
115 /***************************************************************************/
126 int NORFLASH_EraseSector(uint32_t addr)
127 {
128  int status;
129 
130  if (!flashInitialized)
131  {
132  status = flashInterrogate();
133 
134  if (status != NORFLASH_STATUS_OK)
135  return status;
136  }
137 
138  if (!NORFLASH_AddressValid(addr))
139  {
140  EFM_ASSERT(false);
142  }
143 
144  /* Mask off LSB's according to sectorsize to get sector start address */
145  addr = addr & ~(flashInfo.sectorSize - 1);
146 
147  flashUnlockCmd();
148 
149  flashBase[0x555] = 0x80;
150  flashBase[0x555] = 0xAA;
151  flashBase[0x2AA] = 0x55;
152 
153  *(volatile uint16_t*) addr = 0x30;
154 
155  return flashPoll(addr, 0xFFFF);
156 }
157 
158 /***************************************************************************/
170 int NORFLASH_Init(void)
171 {
172  return flashInterrogate();
173 }
174 
175 /***************************************************************************/
195 int NORFLASH_Program(uint32_t addr, uint8_t *data, uint32_t count)
196 {
197  int status;
198  uint32_t sectorAddress, burst;
199 
200  if (!flashInitialized)
201  {
202  status = flashInterrogate();
203 
204  if (status != NORFLASH_STATUS_OK)
205  return status;
206  }
207 
208  if (!NORFLASH_AddressValid(addr) ||
209  !NORFLASH_AddressValid(addr + count - 1))
210  {
211  EFM_ASSERT(false);
213  }
214 
215  /* Check if odd byte aligned */
216  if (addr & 1)
217  {
218  status = NORFLASH_ProgramByte(addr, *data);
219 
220  if (status != NORFLASH_STATUS_OK)
221  return status;
222 
223  addr++;
224  data++;
225  count--;
226  }
227 
228  while (count >= 2)
229  {
230 #if 0 /* Traditional write method, write one word at a time */
231  status = NORFLASH_ProgramWord16(addr, (*(data + 1) << 8) | *data);
232 
233  if (status != NORFLASH_STATUS_OK)
234  return status;
235 
236  addr += 2;
237  data += 2;
238  count -= 2;
239 
240 #else /* "Write Buffer" write method */
241  sectorAddress = addr & ~(flashInfo.sectorSize - 1);
242 
243  /* Max 32 "words" at a time, must not cross sector boundary */
244  burst = EFM32_MIN(64U, sectorAddress + flashInfo.sectorSize - addr);
245  burst = EFM32_MIN(burst, count & 0xFFFFFFFE);
246 
247  status = flashWriteBuffer(sectorAddress, addr, (uint16_t*) data, burst);
248 
249  if (status != NORFLASH_STATUS_OK)
250  return status;
251 
252  addr += burst;
253  data += burst;
254  count -= burst;
255 #endif
256 
257  }
258 
259  /* Check if a trailing odd byte aligned value must be programmed */
260  if (count)
261  {
262  status = NORFLASH_ProgramByte(addr, *data);
263  }
264 
265  return status;
266 }
267 
268 /***************************************************************************/
285 int NORFLASH_ProgramByte(uint32_t addr, uint8_t data)
286 {
287  uint16_t tmp;
288 
289  tmp = *(volatile uint16_t*)(addr & 0xFFFFFFFE);
290  if (addr & 1)
291  {
292  tmp = (tmp & 0xFF) | (data << 8);
293  }
294  else
295  {
296  tmp = (tmp & 0xFF00) | data;
297  }
298 
299  return NORFLASH_ProgramWord16(addr & 0xFFFFFFFE, tmp);
300 }
301 
302 /***************************************************************************/
319 int NORFLASH_ProgramWord16(uint32_t addr, uint16_t data)
320 {
321  int status;
322 
323  if (!flashInitialized)
324  {
325  status = flashInterrogate();
326 
327  if (status != NORFLASH_STATUS_OK)
328  return status;
329  }
330 
331  if (!NORFLASH_AddressValid(addr) ||
332  !NORFLASH_AddressValid(addr + 1))
333  {
334  EFM_ASSERT(false);
336  }
337 
338  if (addr & 1)
340 
341  flashUnlockCmd();
342  flashBase[0x555] = 0xA0;
343 
344  *(volatile uint16_t*) addr = data;
345 
346  return flashPoll(addr, data);
347 }
348 
349 /***************************************************************************/
366 int NORFLASH_ProgramWord32(uint32_t addr, uint32_t data)
367 {
368  int status;
369 
370  if (addr & 3)
372 
373  status = NORFLASH_ProgramWord16(addr, data & 0xFFFF);
374 
375  if (status == NORFLASH_STATUS_OK)
376  {
377  addr += 2;
378  status = NORFLASH_ProgramWord16(addr, data >> 16);
379  }
380 
381  return status;
382 }
383 
386 /***************************************************************************/
395 static int flashInterrogate(void)
396 {
397  flashInfo.baseAddress = EBI_BankAddress(EBI_BANK3);
398  flashBase = (volatile uint16_t*) flashInfo.baseAddress;
399 
400  flashReset();
401 
402  flashUnlockCmd();
403  flashBase[0x555] = 0x90; /* Autoselect command */
404 
405  /* Read device info */
406  flashInfo.manufacturerId = flashBase[0x00];
407  flashInfo.deviceId = (flashBase[0x01] & 0xFF) << 16;
408  flashInfo.deviceId |= (flashBase[0x0E] & 0xFF) << 8;
409  flashInfo.deviceId |= flashBase[0x0F] & 0xFF;
410 
411  flashReset();
412 
413  flashBase[0x55] = 0x98; /* CFI query command */
414 
415  /* Check for CFI compliant device */
416  if ((flashBase[0x10] != 'Q') ||
417  (flashBase[0x11] != 'R') ||
418  (flashBase[0x12] != 'Y'))
419  {
420  flashReset();
422  }
423 
424  /* Get device geometry info, flash sector region count */
425  if (flashBase[0x2C] != 1)
426  {
427  flashReset();
429  }
430 
431  flashInfo.deviceSize = flashBase[0x27];
432  flashInfo.deviceSize = 1 << flashInfo.deviceSize;
433  flashInfo.sectorCount = flashBase[0x2D];
434  flashInfo.sectorCount |= (flashBase[0x2E] << 8) & 0xFF00;
435  flashInfo.sectorSize = flashBase[0x2F];
436  flashInfo.sectorSize |= (flashBase[0x30] << 8) & 0xFF00;
437 
438  flashInfo.sectorCount += 1;
439  flashInfo.sectorSize *= 256;
440 
441  flashReset();
442 
443  flashInitialized = true;
444 
445  return NORFLASH_STATUS_OK;
446 }
447 
448 /***************************************************************************/
469 static int flashPoll(uint32_t addr, uint16_t data)
470 {
471  #define TOGGLE_BIT 0x40
472  #define TIMEOUT_BIT 0x20
473 
474  int i = 0;
475  uint16_t flashData1, flashData2, flashData3;
476 
477  if ((flashData1 = *(volatile uint16_t*) addr) == data)
478  return NORFLASH_STATUS_OK;
479 
480  if ((flashData2 = *(volatile uint16_t*) addr) == data)
481  return NORFLASH_STATUS_OK;
482 
483  while (1)
484  {
485  if ((flashData3 = *(volatile uint16_t*) addr) == data)
486  return NORFLASH_STATUS_OK;
487 
488  if ((((flashData1 ^ flashData2) & TOGGLE_BIT) == TOGGLE_BIT) &&
489  (((flashData2 ^ flashData3) & TOGGLE_BIT) == TOGGLE_BIT) &&
490  ((flashData1 & TIMEOUT_BIT) == TIMEOUT_BIT))
491  {
492  /* DQ6 is still toggling and DQ5 (timeout) is set */
493  flashReset();
494  return NORFLASH_WRITE_TIMEOUT;
495  }
496 
497  if ((((flashData1 ^ flashData2) & TOGGLE_BIT) != TOGGLE_BIT) ||
498  (((flashData2 ^ flashData3) & TOGGLE_BIT) != TOGGLE_BIT))
499  {
500  /* DQ6 has stopped toggling */
501  if (*(volatile uint16_t*) addr == data)
502  return NORFLASH_STATUS_OK;
503 
504  /* Code will typically end here if attempting to program a 0 to a 1 */
505  flashReset();
506  return NORFLASH_WRITE_FAILURE;
507  }
508 
509  flashData1 = flashData2;
510  flashData2 = flashData3;
511  i++;
512  }
513  #undef TOGGLE_BIT
514  #undef TIMEOUT_BIT
515 }
516 
517 /***************************************************************************/
521 static void flashReset(void)
522 {
523  flashBase[0] = 0xF0;
524 }
525 
526 /***************************************************************************/
530 static void flashUnlockCmd(void)
531 {
532  flashBase[0x555] = 0xAA;
533  flashBase[0x2AA] = 0x55;
534 }
535 
536 /***************************************************************************/
556 static int flashWriteBuffer(uint32_t sectorAddr,
557  uint32_t addr,
558  uint16_t *data,
559  uint32_t count)
560 {
561  uint32_t i;
562  volatile uint16_t *pDst;
563 
564  pDst = (volatile uint16_t*) addr;
565  count = (count / 2) - 1;
566 
567  flashUnlockCmd();
568  *(volatile uint16_t*) sectorAddr = 0x25; /* Write buffer command */
569  *(volatile uint16_t*) sectorAddr = count; /* Word16count - 1 */
570  for (i = 0; i <= count; i++)
571  {
572  *pDst++ = *data++;
573  }
574  *(volatile uint16_t*) sectorAddr = 0x29; /* Write confirm */
575 
576  pDst--;
577  data--;
578  return flashPoll((uint32_t) pDst, *data);
579 }
580 
#define EFM32_MIN(a, b)
Definition: em_common.h:79
int NORFLASH_EraseDevice(void)
Erase entire flash device.
Definition: norflash.c:93
Definitions for the NORFLASH driver for Spansion S29GL128P90FFIR13.
uint32_t sectorCount
Definition: norflash.h:56
int NORFLASH_ProgramWord16(uint32_t addr, uint16_t data)
Program a word (16bit) in the flash device.
Definition: norflash.c:319
bool NORFLASH_AddressValid(uint32_t addr)
Check if an address is valid for the flash device.
Definition: norflash.c:49
int NORFLASH_Init(void)
Initialize the NORFLASH module.
Definition: norflash.c:170
Emlib general purpose utilities.
uint32_t deviceSize
Definition: norflash.h:55
NORFLASH_Info_TypeDef * NORFLASH_DeviceInfo(void)
Return a pointer to a NORFLASH_Info_TypeDef, which contain vital flash device information.
Definition: norflash.c:74
int NORFLASH_ProgramByte(uint32_t addr, uint8_t data)
Program a single byte in the flash device.
Definition: norflash.c:285
External Bus Iterface (EBI) peripheral API.
uint32_t sectorSize
Definition: norflash.h:57
int NORFLASH_EraseSector(uint32_t addr)
Erase a sector in the flash device.
Definition: norflash.c:126
NORFLASH device information struct.
Definition: norflash.h:51
int NORFLASH_ProgramWord32(uint32_t addr, uint32_t data)
Program a word (32bit) in the flash device.
Definition: norflash.c:366
uint32_t baseAddress
Definition: norflash.h:53
uint16_t manufacturerId
Definition: norflash.h:58
int NORFLASH_Program(uint32_t addr, uint8_t *data, uint32_t count)
Program the flash device.
Definition: norflash.c:195