EFM32 Gecko Software Documentation  efm32g-doc-5.1.2
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 = SL_MIN(64U, sectorAddress + flashInfo.sectorSize - addr);
245  burst = SL_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 {
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  uint16_t flashData1, flashData2, flashData3;
475 
476  flashData1 = *(volatile uint16_t*) addr;
477  flashData2 = *(volatile uint16_t*) addr;
478 
479  if ((flashData1 == data)
480  && (flashData2 == data))
481  {
482  return NORFLASH_STATUS_OK;
483  }
484 
485  while (1)
486  {
487  flashData3 = *(volatile uint16_t*) addr;
488 
489  if ((((flashData1 ^ flashData2) & TOGGLE_BIT) == TOGGLE_BIT) &&
490  (((flashData2 ^ flashData3) & TOGGLE_BIT) == TOGGLE_BIT) &&
491  ((flashData1 & TIMEOUT_BIT) == TIMEOUT_BIT))
492  {
493  /* DQ6 is still toggling and DQ5 (timeout) is set */
494  flashReset();
495  return NORFLASH_WRITE_TIMEOUT;
496  }
497 
498  if ((((flashData1 ^ flashData2) & TOGGLE_BIT) != TOGGLE_BIT) ||
499  (((flashData2 ^ flashData3) & TOGGLE_BIT) != TOGGLE_BIT))
500  {
501  /* DQ6 has stopped toggling, do at least two reads. */
502  *(volatile uint16_t*) addr;
503  if (*(volatile uint16_t*) addr == data)
504  {
505  return NORFLASH_STATUS_OK;
506  }
507 
508  /* Code will typically end here if attempting to program a 0 to a 1 */
509  flashReset();
510  return NORFLASH_WRITE_FAILURE;
511  }
512 
513  flashData1 = flashData2;
514  flashData2 = flashData3;
515  }
516  #undef TOGGLE_BIT
517  #undef TIMEOUT_BIT
518 }
519 
520 /***************************************************************************/
524 static void flashReset(void)
525 {
526  flashBase[0] = 0xF0;
527 }
528 
529 /***************************************************************************/
533 static void flashUnlockCmd(void)
534 {
535  flashBase[0x555] = 0xAA;
536  flashBase[0x2AA] = 0x55;
537 }
538 
539 /***************************************************************************/
559 static int flashWriteBuffer(uint32_t sectorAddr,
560  uint32_t addr,
561  uint16_t *data,
562  uint32_t count)
563 {
564  uint32_t i;
565  volatile uint16_t *pDst;
566 
567  pDst = (volatile uint16_t*) addr;
568  count = (count / 2) - 1;
569 
570  flashUnlockCmd();
571  *(volatile uint16_t*) sectorAddr = 0x25; /* Write buffer command */
572  *(volatile uint16_t*) sectorAddr = count; /* Word16count - 1 */
573  for (i = 0; i <= count; i++)
574  {
575  *pDst++ = *data++;
576  }
577  *(volatile uint16_t*) sectorAddr = 0x29; /* Write confirm */
578 
579  pDst--;
580  data--;
581  return flashPoll((uint32_t) pDst, *data);
582 }
583 
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
uint32_t EBI_BankAddress(uint32_t bank)
Return base address of EBI bank.
Definition: em_ebi.c:330
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
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
#define EBI_BANK3
Definition: em_ebi.h:78
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
#define SL_MIN(a, b)
Macro for getting minimum value. No sideeffects, a and b are evaluated once only. ...
Definition: em_common.h:137
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