1 /*
2 * Copyright 2022 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7 #include "fsl_eeprom_emulation.h"
8 #include "fsl_debug_console.h"
9
10 /*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.eeprom_emulation"
17 #endif
18
19 /*******************************************************************************
20 * Prototypes
21 ******************************************************************************/
22 static uint32_t EE_PreInitCheck(eeprom_emulation_handle_t *handle);
23 static uint32_t EE_InitAltSector(eeprom_emulation_handle_t *handle, uint8_t *number);
24 static uint32_t EE_InitActiveSector(eeprom_emulation_handle_t *handle, uint8_t number);
25
26 /*******************************************************************************
27 * Variables
28 ******************************************************************************/
29
30 /* Start address of the current active sector */
31 static uint32_t g_currentActiveSector;
32
33 /* The blank address of the current active sector
34 where the next data record is written */
35 static uint32_t g_freeSpaceAddress;
36 static uint32_t g_eeEndAddress;
37 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
38 static uint32_t g_eraseCycles[4];
39 #else
40 static uint32_t g_eraseCycles[2];
41 #endif
42 static eeprom_emulation_data_record_t g_dataRecord;
43
44 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
45 static uint32_t g_addressToMain;
46 static uint32_t g_endAddressToMain;
47 static uint8_t g_numErase = 0x00u;
48 #endif
49
50 /* Flag to keep track of Erase State*/
51 static volatile eeprom_emulation_state_type_t g_eraseStatusFlag;
52
53 #if EE_CALLBACK_ENABLE
54 /* A function pointer to the CallBack function */
55 PEE_FUNCPOINTER g_EECallBack;
56 #endif /* EE_CALLBACK_ENABLE */
57
58 /*******************************************************************************
59 * Code
60 ******************************************************************************/
EE_GetDefaultConfig(eeprom_emulation_config_t * config)61 void EE_GetDefaultConfig(eeprom_emulation_config_t *config)
62 {
63 config->eeRetryMax = 0x02U;
64 config->ftfxPGMCheckSize = 0x04U;
65 config->flashReadMargin = 0x01U;
66 config->flashStartAddress = 0x00U;
67 config->eeSectorActIndOffset = 0x00U;
68 }
69
EE_SetEepromEmulationInfo(eeprom_emulation_handle_t * handle,eeprom_emulation_config_t * config)70 void EE_SetEepromEmulationInfo(eeprom_emulation_handle_t *handle, eeprom_emulation_config_t *config)
71 {
72 /* Number of actual alternative sectors alloted for emulation Eeprom is enough or not */
73 assert(config->eeActualReadySectors >= config->eeMinActualReadySectors);
74
75 /* Flash sector size */
76 handle->flashSectorSize = config->flashSectorSize;
77 /* Start address for emulated eeprom */
78 handle->eeStartAddress = config->eeStartAddress;
79 /* Program size for ftfx module */
80 handle->ftfxProgramSize = config->ftfxProgramSize;
81 /* Data value size in one record */
82 handle->eeDataValueSize = config->eeDataValueSize;
83 /* Sector size for emulated eeprom */
84 handle->eeSectorSize = config->eeSectorSize;
85 /* The total raw data user wants to emulate in byte */
86 handle->eeMemorySize = config->eeMemorySize;
87 /* Active ready sector numbers */
88 handle->eeActualReadySectors = config->eeActualReadySectors;
89 /* Extra ready sector numbers */
90 handle->eeExtraReadySectors = config->eeExtraReadySectors;
91 /* Extra active sector numbers */
92 handle->eeExtraActiveSectors = config->eeExtraActiveSectors;
93 /* Number of retry if failed to program sector indicator or erase sector */
94 handle->eeRetryMax = config->eeRetryMax;
95 /* Program size for program check function */
96 handle->ftfxPGMCheckSize = config->ftfxPGMCheckSize;
97 /* Read one sector size for ftfx module */
98 handle->ftfxRD1SECSize = config->ftfxRD1SECSize;
99 /* Read margin */
100 handle->flashReadMargin = config->flashReadMargin;
101
102 /* Calculate complement size */
103 if (config->eccSize == 0x02U)
104 {
105 handle->complementSize = handle->ftfxProgramSize;
106 }
107 else
108 {
109 handle->complementSize = 0;
110 }
111
112 /* Calculate eeprom emulation sector header size */
113 handle->eeSectorHeaderSize = (0x03U * handle->ftfxProgramSize) + handle->complementSize;
114
115 /* number of bit to make programable size */
116 if (FTFx_LONGWORD_SIZE == handle->ftfxProgramSize)
117 {
118 handle->ftfxBitNumber = 0x02U;
119 handle->ftfxProgramCommand = 0x06U;
120 }
121 else if (FTFx_PHRASE_SIZE == handle->ftfxProgramSize)
122 {
123 handle->ftfxBitNumber = 0x03U;
124 handle->ftfxProgramCommand = 0x07U;
125 }
126 else
127 {
128 /* Should not be here */
129 }
130
131 /* Calculate eeprom emulation sector record length */
132 if (0x00U != GET_MOD(handle->eeDataValueSize, handle->ftfxProgramSize))
133 {
134 handle->eeSectorRecordLength =
135 (((handle->eeDataValueSize >> handle->ftfxBitNumber) + 0x01U) << handle->ftfxBitNumber) +
136 (2U * handle->ftfxProgramSize) + handle->complementSize;
137 }
138 else
139 {
140 handle->eeSectorRecordLength =
141 handle->eeDataValueSize + (2U * handle->ftfxProgramSize) + handle->complementSize;
142 }
143
144 /* Calculate active indecator, dead indicator and erase cycle offset */
145 handle->eeSectorActIndOffset = config->eeSectorActIndOffset;
146 handle->eeSectorDeadIndOffset = handle->ftfxProgramSize;
147 handle->eeSectorEraseCycleOffset = handle->ftfxProgramSize << 0x01U;
148
149 /* Calculate record ID and record status offset */
150 handle->eeRecordIDOffset = handle->eeSectorRecordLength - EE_RECORD_ID_SIZE - handle->complementSize;
151 if (FTFx_PHRASE_SIZE == handle->ftfxProgramSize)
152 {
153 handle->eeGapSize = 0x04U;
154 handle->eeRecordStatusOffset =
155 handle->eeSectorRecordLength - FTFx_LONGWORD_SIZE - EE_RECORD_STATUS_SIZE - handle->complementSize;
156 }
157 else if (FTFx_DPHRASE_SIZE == handle->ftfxProgramSize)
158 {
159 handle->eeGapSize = handle->ftfxProgramSize; /* The gap between ID with STATUS. */
160 handle->eeRecordStatusOffset =
161 handle->eeSectorRecordLength - handle->ftfxProgramSize - EE_RECORD_STATUS_SIZE - handle->complementSize;
162 }
163 else
164 {
165 handle->eeGapSize = 0x02U;
166 handle->eeRecordStatusOffset = handle->eeSectorRecordLength - handle->ftfxProgramSize - handle->complementSize;
167 }
168
169 /* Calculate eeprom emulation sector waste size */
170 handle->eeSectorWaste = (handle->eeSectorSize - handle->eeSectorHeaderSize) % handle->eeSectorRecordLength;
171
172 /* Calculate ready sectors number*/
173 handle->eeReadySectors = handle->eeActualReadySectors + handle->eeExtraReadySectors;
174
175 /* Number of Data Records is calculated if we know the total Data Size */
176 if (0x00U != GET_MOD(handle->eeMemorySize, handle->eeDataValueSize))
177 {
178 handle->eeMaxRecordNumber = (uint16_t)(GET_INT(handle->eeMemorySize, handle->eeDataValueSize) + 0x01u);
179 }
180 else
181 {
182 handle->eeMaxRecordNumber = (uint16_t)(GET_INT(handle->eeMemorySize, handle->eeDataValueSize));
183 }
184
185 /* Calculate capacity */
186 handle->eeSectorCapacity = GET_INT(handle->eeSectorSize - handle->eeSectorHeaderSize, handle->eeSectorRecordLength);
187
188 /* Calculate required active sector */
189 if (0x00U != GET_MOD(((uint32_t)handle->eeMaxRecordNumber + 0x01u), handle->eeSectorCapacity))
190 {
191 handle->eeActiveSectorRequired =
192 (GET_INT(((uint32_t)handle->eeMaxRecordNumber + 0x01u), handle->eeSectorCapacity) + 0x01u);
193 }
194 else
195 {
196 handle->eeActiveSectorRequired =
197 GET_INT(((uint32_t)handle->eeMaxRecordNumber + 0x01u), handle->eeSectorCapacity);
198 }
199
200 /* Total number of active sectors alloted */
201 handle->eeActiveSectors = handle->eeExtraActiveSectors + handle->eeActiveSectorRequired;
202
203 /* Total number of sectors alloted will also include some 'alternative sectors' */
204 handle->eeAllotedSectors = handle->eeActiveSectors + handle->eeReadySectors;
205
206 /* End address of eeprom emulation from Flash */
207 handle->eeEndAddress = handle->eeStartAddress + handle->eeAllotedSectors * handle->eeSectorSize;
208 }
209
210 /*******************************************************************************
211 *
212 * Function Name : CheckErrorCode
213 * Description : Check error bit of each flash command.
214 * Purpose : to optimize code size since this function is called multiple times.
215 * Arguments : N/A
216 * Return Value :
217 * - EE_OK if successful
218 * - EE_NOT_OK if failed
219 *
220 *******************************************************************************/
EE_FlashCheckErrorCode(void)221 uint32_t EE_FlashCheckErrorCode(void)
222 {
223 uint32_t returnCode;
224 returnCode = EE_OK;
225 /* checking all errors */
226 if (0u != FMU_CHECK_ERR)
227 {
228 returnCode = EE_NOT_OK;
229 }
230 return (returnCode);
231 }
232
233 /*******************************************************************************
234 *
235 * Function Name : EE_FlashEraseAll
236 * Description : Erase one EE sector in Flash with synchronous model and verify as well
237 * Arguments :
238 * - destination: the offset address to flash base
239 * Return Value :
240 * - EE_OK if successful
241 * - EE_NOT_OK if failed
242 *
243 *******************************************************************************/
AT_QUICKACCESS_SECTION_CODE(uint32_t EE_FlashEraseAll (eeprom_emulation_handle_t * handle))244 AT_QUICKACCESS_SECTION_CODE(uint32_t EE_FlashEraseAll(eeprom_emulation_handle_t *handle))
245 {
246 uint32_t result = EE_OK;
247
248 /* load FCCOB registers */
249 FMU0->FCCOB[0] = ERSALL;
250
251 /* Check if previous command complete, wait for CCIF set */
252 while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
253 {
254 }
255
256 /* clear CMDABT & ACCERR & PVIOL flag in flash status register */
257 FMU0->FSTAT = (FLASH_FSTAT_CMDABT_MASK | FLASH_FSTAT_ACCERR_MASK | FLASH_FSTAT_PVIOL_MASK);
258
259 FMU0->FSTAT = FLASH_FSTAT_CCIF_MASK;
260 while (0x00U != (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
261 {
262 }
263
264 while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
265 {
266 }
267
268 /* Check for errors */
269 if (0x00U != (FMU0->FSTAT & FMU_FSTAT_FAIL_MASK))
270 {
271 result = EE_NOT_OK;
272 }
273
274 return result;
275 }
276
277 /*******************************************************************************
278 *
279 * Function Name : EE_SyncFlashErase
280 * Description : Erase one EE sector in Flash with synchronous model and verify as well
281 * Arguments :
282 * - destination: the offset address to flash base
283 * Return Value :
284 * - EE_OK if successful
285 * - EE_NOT_OK if failed
286 *
287 *******************************************************************************/
AT_QUICKACCESS_SECTION_CODE(uint32_t EE_SyncFlashErase (eeprom_emulation_handle_t * handle,uint32_t destination))288 AT_QUICKACCESS_SECTION_CODE(uint32_t EE_SyncFlashErase(eeprom_emulation_handle_t *handle, uint32_t destination))
289 {
290 uint32_t dest = destination;
291 uint32_t result = EE_OK;
292 uint32_t i;
293
294 destination -= handle->flashStartAddress;
295
296 while (dest < (destination + handle->eeSectorSize))
297 {
298 /*Clear status*/
299 FMU0->FSTAT = FMU_FSTAT_ACCERR_MASK | FMU_FSTAT_PVIOL_MASK | FMU_FSTAT_CMDABT_MASK;
300
301 /* load FCCOB registers */
302 FMU0->FCCOB[0] = ERSSCR;
303 FMU0->FCCOB[1] = 0x00U;
304
305 /*Clear CCIF to launch the command*/
306 FMU0->FSTAT = FMU_FSTAT_CCIF_MASK;
307
308 /*wait for writes to get enabled*/
309 while (0x00U == (FMU0->FSTAT & FMU_FSTAT_PEWEN_MASK))
310 {
311 }
312
313 /* writing 4 consecutive words to flash. */
314 for (i = 0; i < 4U; i++)
315 {
316 *((uint32_t *)(dest + i * 4U)) = 0x00U;
317 }
318
319 while (0x00U == (FMU0->FSTAT & FMU_FSTAT_PERDY_MASK))
320 {
321 }
322
323 /* Clear PERDY status */
324 FMU0->FSTAT = FMU_FSTAT_PERDY_MASK;
325
326 /* wait until command complete */
327 while (0x00U == (FMU0->FSTAT & FMU_FSTAT_CCIF_MASK))
328 {
329 }
330
331 /*check for errors*/
332 if (0x00U != (FMU0->FSTAT & FMU_FSTAT_FAIL_MASK))
333 {
334 result = EE_NOT_OK;
335 break;
336 }
337
338 dest += handle->flashSectorSize;
339 }
340
341 /* need to verify section here */
342 if (result != EE_NOT_OK)
343 {
344 result = EE_FlashEraseVerifySection(handle, destination + handle->flashStartAddress,
345 (uint16_t)(handle->eeSectorSize / handle->ftfxRD1SECSize),
346 handle->flashReadMargin);
347 }
348
349 return result;
350 }
351
352 /*******************************************************************************
353 *
354 * Function Name : EE_AsyncFlashErase
355 * Description : Erase one EE sector in Flash with synchronous model and verify as well
356 * Arguments :
357 * - destination: the offset address to flash base
358 * Return Value : N/A
359 *
360 *******************************************************************************/
361 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
EE_AsyncFlashErase(eeprom_emulation_handle_t * handle,uint32_t destination)362 void EE_AsyncFlashErase(eeprom_emulation_handle_t *handle, uint32_t destination)
363 {
364 destination -= handle->flashStartAddress;
365 /* load FCCOB registers */
366 REG_WRITE(FTFx_FCCOB0, FTFx_ERASE_SECTOR);
367 REG_WRITE(FTFx_FCCOB1, (uint8_t)(destination >> 16u));
368 REG_WRITE(FTFx_FCCOB2, (uint8_t)((destination >> 8u) & 0xFFu));
369 REG_WRITE(FTFx_FCCOB3, (uint8_t)(destination & 0xFFu));
370
371 /* Update erase status */
372 g_eraseStatusFlag = BUSY;
373 /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
374 /* it is impossible to launch command if any error bit set */
375 REG_WRITE(FTFx_FSTAT, FTFx_FSTAT_CLEAR_ERR);
376 /* clear CCIF bit to start command */
377 REG_WRITE(FTFx_FSTAT, FTFx_FSTAT_CCIF);
378 /* Enable command complete interrupt */
379 REG_BIT_SET(FTFx_FCNFG, FTFx_FCNFG_CCIE);
380 }
381 #endif /* of EE_USE_ASYNCHRONOUS_MODEL*/
382
383 /*******************************************************************************
384 *
385 * Function Name : EE_FlashEraseVerifySection
386 * Description : Erase verify Number*FTFx_RD1SEC_SIZE bytes in Flash
387 * Arguments :
388 * - destination: offset address to pflash base
389 * - number: number of verify section aligned unit
390 * - marginLevel: margin level used to verify
391 * Return Value :
392 * - EE_OK if successful
393 * - EE_NOT_OK if failed
394 *
395 *******************************************************************************/
AT_QUICKACCESS_SECTION_CODE(uint32_t EE_FlashEraseVerifySection (eeprom_emulation_handle_t * handle,uint32_t destination,uint16_t Number,uint8_t marginLevel))396 AT_QUICKACCESS_SECTION_CODE(uint32_t EE_FlashEraseVerifySection(
397 eeprom_emulation_handle_t *handle, uint32_t destination, uint16_t Number, uint8_t marginLevel))
398 {
399 uint32_t result = EE_OK;
400 uint32_t dest = destination;
401 uint32_t margin = marginLevel;
402
403 /* load FCCOB registers */
404 FMU0->FCCOB[0] = RD1SCR;
405 FMU0->FCCOB[1] = margin;
406 FMU0->FCCOB[2] = dest;
407
408 /*Check if previous command complete, wait for CCIF set */
409 while (0U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
410 {
411 }
412
413 /*Clear status*/
414 FMU0->FSTAT = FMU_FSTAT_ACCERR_MASK | FMU_FSTAT_PVIOL_MASK | FMU_FSTAT_CMDABT_MASK;
415
416 /*Clear CCIF to launch the command*/
417 FMU0->FSTAT = FMU_FSTAT_CCIF_MASK;
418 while (0U != (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
419 {
420 }
421
422 /* wait until command complete */
423 while (0U == (FMU0->FSTAT & FMU_FSTAT_CCIF_MASK))
424 {
425 }
426
427 /*check for errors*/
428 if (0U != (FMU0->FSTAT & FMU_FSTAT_FAIL_MASK))
429 {
430 result = EE_NOT_OK;
431 }
432
433 return result;
434 }
435
436 /*******************************************************************************
437 *
438 * Function Name : EE_SingleProgram
439 * Description : Program 1 programmable size to Flash
440 * Arguments :
441 * - destination: offset address to flash block base
442 * - pData: pointer to point to data to be programmed.
443 * Return Value :
444 * - EE_OK if successful
445 * - EE_NOT_OK if failed
446 *
447 *******************************************************************************/
AT_QUICKACCESS_SECTION_CODE(uint32_t EE_SingleProgram (eeprom_emulation_handle_t * handle,uint32_t destination,uint8_t * pData))448 AT_QUICKACCESS_SECTION_CODE(uint32_t EE_SingleProgram(eeprom_emulation_handle_t *handle,
449 uint32_t destination,
450 uint8_t *pData))
451 {
452 assert(handle != NULL);
453
454 uint32_t i;
455 uint32_t const *src = (uint32_t const *)(void const *)pData;
456 uint32_t result = EE_OK;
457
458 destination -= handle->flashStartAddress;
459
460 /*Load Program PHR command*/
461 FMU0->FCCOB[0] = PGMPHR;
462
463 /* Check if previous command complete, wait for CCIF set*/
464 while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
465 {
466 }
467
468 /* clear CMDABT & ACCERR & PVIOL flag in flash status register */
469 FMU0->FSTAT = (FLASH_FSTAT_CMDABT_MASK | FLASH_FSTAT_ACCERR_MASK | FLASH_FSTAT_PVIOL_MASK);
470
471 /* clear ccif */
472 FMU0->FSTAT = FLASH_FSTAT_CCIF_MASK;
473 while (0x00U != (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
474 {
475 }
476
477 /* program */
478 while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_PEWEN_MASK))
479 {
480 }
481
482 /* Must be write 4 consecutive words */
483 for (i = 0; i < 4U; i++)
484 {
485 *((uint32_t *)(destination + i * 4U)) = src[i];
486 }
487
488 while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_PERDY_MASK))
489 {
490 }
491
492 FMU0->FSTAT = FLASH_FSTAT_PERDY_MASK;
493 while (0x00U != (FMU0->FSTAT & FLASH_FSTAT_PERDY_MASK))
494 {
495 }
496
497 /* wait for command complete */
498 while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
499 {
500 }
501
502 /*check for errors*/
503 if (0x00U != (FMU0->FSTAT & FMU_FSTAT_FAIL_MASK))
504 {
505 result = EE_NOT_OK;
506 }
507
508 return result;
509 }
510
511 /*******************************************************************************
512 *
513 * Function Name : EE_SingleProgramCheck
514 * Description : Program check for 1 program check size in PFlash
515 * Arguments :
516 * - destination: offset address to pflash block base
517 * - pExpectedData: expected data to be verified
518 * - margin level: margin level to be verified.
519 * Return Value :
520 * - EE_OK if successful
521 * - EE_NOT_OK if failed
522 *
523 *******************************************************************************/
EE_SingleProgramCheck(eeprom_emulation_handle_t * handle,uint32_t destination,uint8_t * pExpectedData,uint8_t marginLevel)524 uint32_t EE_SingleProgramCheck(eeprom_emulation_handle_t *handle,
525 uint32_t destination,
526 uint8_t *pExpectedData,
527 uint8_t marginLevel)
528 {
529 assert(handle != NULL);
530 assert(pExpectedData != NULL);
531
532 uint32_t result = EE_OK;
533 uint32_t tmp;
534
535 destination -= handle->flashStartAddress;
536
537 tmp = *((uint32_t *)(void *)pExpectedData);
538
539 if (READ32(destination) != tmp)
540 {
541 result = EE_NOT_OK;
542 }
543
544 return result;
545 }
546
547 /* Disable cache within flash controller */
FLASH_CACHE_Disable(void)548 void FLASH_CACHE_Disable(void)
549 {
550 SMSCM->OCMDR0 = (SMSCM->OCMDR0 & (~SMSCM_CACHE_CLEAR_MASK)) | SMSCM_CACHE_CLEAR(0x1);
551 SMSCM->OCMDR0 = (SMSCM->OCMDR0 & (~SMSCM_CACHE_CLEAR_MASK)) | SMSCM_CACHE_CLEAR(0x8);
552 SMSCM->OCMDR0 = (SMSCM->OCMDR0 & (~SMSCM_SPECULATION_DISABLE_MASK)) | SMSCM_SPECULATION_DISABLE_MASK;
553 __ISB();
554 __DSB();
555 }
556
557 /*middle*/
558 /*******************************************************************************
559 *
560 * Function Name : EE_NextSector
561 * Description : This function is used to get address of the next sector in
562 * the round-robin sequence
563 * Arguments :
564 * - addr: address of the current sector
565 * Return Value :
566 * - address of the next sector
567 *
568 *******************************************************************************/
EE_NextSector(eeprom_emulation_handle_t * handle,uint32_t addr)569 uint32_t EE_NextSector(eeprom_emulation_handle_t *handle, uint32_t addr)
570 {
571 uint32_t nextSectorAddr;
572
573 if (addr == (g_eeEndAddress - (uint32_t)handle->eeSectorSize))
574 {
575 nextSectorAddr = handle->eeStartAddress;
576 }
577 else
578 {
579 nextSectorAddr = addr + (uint32_t)handle->eeSectorSize;
580 }
581
582 return nextSectorAddr;
583 }
584
585 /*******************************************************************************
586 *
587 * Function Name : EE_PrevSector
588 * Description : This function is used to get address of the previous
589 * sector in the round-robin sequence
590 * Arguments :
591 * - addr: address of the current sector
592 * Return Value :
593 * - address of the next sector
594 *
595 *******************************************************************************/
EE_PrevSector(eeprom_emulation_handle_t * handle,uint32_t addr)596 uint32_t EE_PrevSector(eeprom_emulation_handle_t *handle, uint32_t addr)
597 {
598 uint32_t prevSectorAddr;
599
600 if (addr == handle->eeStartAddress)
601 {
602 prevSectorAddr = g_eeEndAddress - handle->eeSectorSize;
603 }
604 else
605 {
606 prevSectorAddr = addr - handle->eeSectorSize;
607 }
608
609 return prevSectorAddr;
610 }
611
612 /*******************************************************************************
613 *
614 * Function Name : EE_VerifyRecordStatus
615 * Description : This function is to verify the record status.
616 * Arguments :
617 * - dest: destination point to record status.
618 * - expData: the expected data at record status location.
619 * Return Value :
620 * - EE_OK if successful
621 * - EE_NOT_OK if failed
622 *
623 *******************************************************************************/
EE_VerifyRecordStatus(eeprom_emulation_handle_t * handle,uint32_t dest,uint32_t expData)624 uint32_t EE_VerifyRecordStatus(eeprom_emulation_handle_t *handle, uint32_t dest, uint32_t expData)
625 {
626 uint32_t programCheckSize = handle->ftfxPGMCheckSize;
627
628 if (handle->ftfxProgramSize != FTFx_LONGWORD_SIZE)
629 {
630 dest = (dest / programCheckSize) * programCheckSize;
631 return (EE_SingleProgramCheck(handle, dest, (uint8_t *)&expData, handle->flashReadMargin));
632 }
633 else
634 {
635 uint32_t returnCode = EE_OK;
636 if ((uint16_t)(expData >> 16u) != READ16(dest))
637 {
638 returnCode = EE_NOT_OK;
639 }
640 return (returnCode);
641 }
642 }
643
644 /*******************************************************************************
645 *
646 * Function Name : EE_VerifySectorHeader
647 * Description : This function is to verify the data in sector header.
648 * Arguments :
649 * - dest: destination need to verify.
650 * - expData: the expected data at destination.
651 * Return Value :
652 * - EE_OK if successful
653 * - EE_NOT_OK if failed
654 *
655 *******************************************************************************/
EE_VerifySectorHeader(eeprom_emulation_handle_t * handle,uint32_t dest,uint32_t expData)656 uint32_t EE_VerifySectorHeader(eeprom_emulation_handle_t *handle, uint32_t dest, uint32_t expData)
657 {
658 return (EE_SingleProgramCheck(handle, dest, (uint8_t *)&expData, handle->flashReadMargin));
659 }
660
661 /*******************************************************************************
662 *
663 * Function Name : EE_MultiProgram
664 * Description : This function will program a range of contiguous Flash
665 * locations (multiple programmable size) and verify them.
666 * Arguments :
667 * - dest: destination to program
668 * - size: size to be programmed
669 * - pData: source data
670 * Return Value :
671 * - EE_OK if successful
672 * - EE_NOT_OK if failed
673 *
674 *******************************************************************************/
EE_MultiProgram(eeprom_emulation_handle_t * handle,uint32_t dest,uint32_t size,uint8_t * pData)675 uint32_t EE_MultiProgram(eeprom_emulation_handle_t *handle, uint32_t dest, uint32_t size, uint8_t *pData)
676 {
677 /* Declaration of the local variables */
678 uint32_t returnCode = EE_OK;
679 uint32_t programSize = handle->ftfxProgramSize;
680 uint8_t *pPtr;
681 pPtr = pData;
682
683 while ((size > 0x00u) && (returnCode == EE_OK))
684 {
685 /* PFlashProgram function called */
686 returnCode = EE_SingleProgram(handle, dest, pPtr);
687
688 dest += programSize;
689 size -= programSize;
690 pPtr += programSize;
691 }
692 return (returnCode);
693 }
694
695 /*******************************************************************************
696 *
697 * Function Name : EE_CopyRecord
698 * Description : writes user data into Flash in a record format to
699 * g_freeSpaceAddress.
700 * Arguments :
701 * - dataRecord: store record addr and record ID need to be
702 * copied.
703 * - remainData: the buffer to store remaining data in case
704 * of writing new record. In case swapping, this input
705 * must be 0xFFFFFFFF.
706 * Return Value :
707 * - EE_OK if successful
708 * - EE_NOT_OK if failed
709 *
710 *******************************************************************************/
EE_CopyRecord(eeprom_emulation_handle_t * handle,eeprom_emulation_data_record_t dataRecord,uint8_t remainData[])711 uint32_t EE_CopyRecord(eeprom_emulation_handle_t *handle,
712 eeprom_emulation_data_record_t dataRecord,
713 uint8_t remainData[])
714 {
715 uint32_t returnCode = EE_OK;
716 uint32_t alginedSize;
717 uint32_t remainingSize;
718 uint32_t address = dataRecord.dataAddr;
719
720 /*Calculate data value aligned part and remaining part */
721 alginedSize = handle->eeDataValueSize - (handle->eeDataValueSize % handle->ftfxProgramSize);
722 remainingSize = handle->eeSectorRecordLength - alginedSize - handle->ftfxProgramSize - handle->complementSize;
723
724 /* when writing new data, source data is in ram, so it is word address */
725 if (remainData == (uint8_t *)0xFFFFFFFFu) /* copy data */
726 {
727 alginedSize = handle->eeSectorRecordLength;
728 /* when copy data, source address is in flash, so it is byte address */
729 address = dataRecord.dataAddr;
730 }
731 /* for swapping, entire record is written within EE_MultiProgram*/
732 /* for writing new data, need to write aligned part first, and then write remaining data, and then write status*/
733 returnCode = EE_MultiProgram(handle, g_freeSpaceAddress, alginedSize, (uint8_t *)address);
734 if (remainData != (uint8_t *)0xFFFFFFFFu) /* write new data, need to program ID and over-program status*/
735 {
736 /* remaining data including ID*/
737 if (returnCode == EE_OK)
738 {
739 returnCode = EE_MultiProgram(handle, g_freeSpaceAddress + alginedSize + handle->ftfxProgramSize,
740 handle->ftfxProgramSize, remainData);
741 }
742
743 /* 0xFF setting. */
744 remainData[(uint8_t)remainingSize - 0x01U] = 0xFF;
745 remainData[(uint8_t)remainingSize - 0x02U] = 0xFF;
746
747 /*and then program status*/
748 if (returnCode == EE_OK)
749 {
750 remainData[(uint8_t)remainingSize - 0x02u] = (uint8_t)((uint16_t)EE_RECORD_STATUS_VALID & 0x00FFu);
751 remainData[(uint8_t)remainingSize - 0x01u] = (uint8_t)((uint16_t)EE_RECORD_STATUS_VALID >> 0x08u);
752 returnCode = EE_MultiProgram(handle, g_freeSpaceAddress + alginedSize, handle->ftfxProgramSize, remainData);
753 }
754 }
755 #if EE_CACHETABLE_ENABLE
756 if (returnCode == EE_OK)
757 {
758 /* this record is written successful, so update cache table */
759 /* Check if the ID is a cache table entry */
760 if (EE_CACHETABLE_MAX_ENTRY >= dataRecord.dataID)
761 {
762 /* Update the cache table item with new value */
763 WRITE32(EE_CACHETABLE_ITEM_ADDR(dataRecord.dataID), g_freeSpaceAddress);
764 }
765 }
766 #endif
767 g_freeSpaceAddress += handle->eeSectorRecordLength;
768 return (returnCode);
769 }
770
771 /*******************************************************************************
772 *
773 * Function Name : EE_SwapSector
774 * Description : Swaps the contents of the oldest active sector to
775 the new sector
776 * Arguments : N/A
777 * Return Value :
778 * - EE_OK if successful
779 * - EE_NOT_OK if failed in erase oldest active sector
780 * - EE_ERR_UPDATE fail when copy records swapping
781 *
782 *******************************************************************************/
EE_SwapSector(eeprom_emulation_handle_t * handle)783 uint32_t EE_SwapSector(eeprom_emulation_handle_t *handle)
784 {
785 eeprom_emulation_data_record_t dataRecord;
786 uint32_t oldSectorAddress;
787 uint32_t newActSectorAddr;
788 uint32_t bk_currentActiveSector;
789 uint32_t recordAddress;
790 uint32_t recFoundAddress;
791 const uint32_t dataSource = 0xFFFFFFFFu; /* Used to indicate swapping while copying data */
792 uint32_t returnCode = EE_OK;
793 uint32_t blankCheck;
794 uint32_t aliveCheck;
795 uint16_t dataID;
796
797 /* backup current active sector for later usage*/
798 bk_currentActiveSector = g_currentActiveSector;
799 newActSectorAddr = g_currentActiveSector;
800
801 /* The first Alternative or ready sector after the current active sector is the sector
802 used for update. At this time, next sector can be Dead, ready or alternative only.
803 So, need to check if next sector is not DEAD, it means this sector is ready or alternative*/
804 do
805 {
806 newActSectorAddr = EE_NextSector(handle, newActSectorAddr);
807 blankCheck = EE_VerifySectorHeader(handle, newActSectorAddr + handle->eeSectorDeadIndOffset,
808 (uint32_t)EE_DATA_STATUS_BLANK);
809 aliveCheck = EE_VerifySectorHeader(handle, newActSectorAddr + handle->eeSectorDeadIndOffset,
810 (uint32_t)EE_DATA_STATUS_ALIVE);
811 } while ((EE_OK != blankCheck) && (EE_OK != aliveCheck));
812
813 g_freeSpaceAddress = newActSectorAddr + (uint32_t)handle->eeSectorHeaderSize;
814 /* At this time, sure new sector is active one, so need to update g_currentActiveSector to this sector */
815 g_currentActiveSector = newActSectorAddr;
816
817 /* find the oldest active sector */
818 oldSectorAddress = EE_FindActSector(handle, handle->eeStartAddress, false, false);
819 /* point to last record in oldest active sector */
820 recordAddress = oldSectorAddress + handle->eeSectorSize - handle->eeSectorWaste - handle->eeSectorRecordLength;
821
822 /* Decrement copy */
823 while (recordAddress >= (oldSectorAddress + handle->eeSectorHeaderSize))
824 {
825 /* only read record ID if record status is VALID*/
826 if (EE_OK == EE_VerifyRecordStatus(handle, recordAddress + handle->eeRecordStatusOffset,
827 (((uint32_t)(EE_RECORD_STATUS_VALID) << 16u) | 0x0000FFFFu)))
828 {
829 dataID = READ16(recordAddress + handle->eeRecordIDOffset);
830
831 /* search this ID in all active sectors from bottom up and from newest to oldest one */
832 recFoundAddress = EE_SearchLoop(handle, dataID);
833 /* Means this is latest ID, which is only one in all sectors, and no rewrite it
834 again with new data at this same daia-id , and need to copy it */
835 if (recFoundAddress == recordAddress)
836 {
837 /* copy this ID to new sector */
838 dataRecord.dataID = dataID;
839 dataRecord.dataAddr = recFoundAddress;
840 /* Means This unique data-ID is the same as the data-ID to be written, ignore rewrite */
841 if (dataRecord.dataID == g_dataRecord.dataID)
842 {
843 recordAddress -= handle->eeSectorRecordLength;
844 continue;
845 }
846
847 returnCode = EE_CopyRecord(handle, dataRecord, (uint8_t *)dataSource);
848 if (returnCode != EE_OK)
849 {
850 returnCode = EE_ERR_UPDATE;
851 break;
852 }
853 }
854 }
855 /* point to next record */
856 recordAddress -= handle->eeSectorRecordLength;
857 }
858
859 /* finish copying */
860 /* make new sector as active */
861 if (returnCode == EE_OK)
862 {
863 returnCode = EE_ValidateActIndicator(handle, newActSectorAddr);
864 if (returnCode != EE_OK)
865 {
866 returnCode = EE_ERR_UPDATE;
867 }
868 }
869 else
870 {
871 g_currentActiveSector = bk_currentActiveSector;
872 g_freeSpaceAddress = g_currentActiveSector + handle->eeSectorSize - handle->eeSectorWaste;
873 /* update cache table to restore the address of all ID like before copying */
874 #if (EE_CACHETABLE_ENABLE == true)
875 EE_UpdateCacheTable(handle);
876 #endif
877 }
878
879 if (returnCode == EE_OK)
880 {
881 /* At this time, new sector is already be active successfully*/
882 /* backup erase cycle of old active sector */
883 g_eraseCycles[0] = READ32(oldSectorAddress + handle->eeSectorEraseCycleOffset);
884 if (g_eraseCycles[0] != (uint32_t)EE_MAX_ERASING_CYCLE_VALUE)
885 {
886 /* increase erase cycle if it is not maximum value */
887 g_eraseCycles[0]++;
888 }
889 /* synchronous model */
890 #if (EE_USE_ASYNCHRONOUS_MODEL != true)
891 /* erase the old active sector. */
892 returnCode = EE_ReEraseEeprom(handle, oldSectorAddress);
893 if (returnCode == EE_OK)
894 {
895 /* only program erase cycle if validate sector successfully and this is not dead sector */
896 returnCode = EE_ValidateEraseCycle(handle, oldSectorAddress, (uint8_t *)&g_eraseCycles);
897 if (returnCode != EE_OK)
898 {
899 returnCode = EE_CheckAvailabilityStatus(handle);
900 }
901 }
902 if (returnCode == EE_MAKEDEAD_OK)
903 {
904 returnCode = EE_CheckAvailabilityStatus(handle);
905 }
906
907 #else /* asynchronous model */
908 g_addressToMain = oldSectorAddress; /* initialize g_addressToMain variable */
909 g_endAddressToMain = oldSectorAddress + handle->eeSectorSize;
910 EE_AsyncFlashErase(handle, g_addressToMain);
911 #endif
912 }
913 return (returnCode);
914 }
915
916 /*******************************************************************************
917 *
918 * Function Name : EE_SearchInSector
919 * Description : Searches the latest record in given sector.
920 * Arguments :
921 * - dataID: expected ID to search
922 * - sectorAddress: start address of sector to be searched
923 * Return Value :
924 * - address of found record
925 * - 0xFFFFFFFF If not found
926 *
927 *******************************************************************************/
EE_SearchInSector(eeprom_emulation_handle_t * handle,uint16_t expID,uint32_t sectorAddress)928 uint32_t EE_SearchInSector(eeprom_emulation_handle_t *handle, uint16_t expID, uint32_t sectorAddress)
929 {
930 uint32_t returnCode = 0xFFFFFFFFu;
931 uint32_t recordAddress;
932 #if EE_CALLBACK_ENABLE
933 uint32_t counter = 0x00u;
934 #endif
935
936 if (sectorAddress == g_currentActiveSector)
937 {
938 /* point to last record of current active sector */
939 recordAddress = g_freeSpaceAddress;
940 }
941 else
942 {
943 /* point to end of sector if this is not current active sector because it is full of data */
944 recordAddress = sectorAddress + handle->eeSectorSize - handle->eeSectorWaste;
945 }
946 /* point to beginning of the first record */
947 sectorAddress += handle->eeSectorHeaderSize;
948 /* Search all the records of the sector */
949 do
950 {
951 /* Decrement recordAddress by EE_RECORD_LENGTH to point to next record*/
952 recordAddress -= handle->eeSectorRecordLength;
953 /* verify if record status is valid */
954 if (EE_OK == EE_VerifyRecordStatus(handle, recordAddress + handle->eeRecordStatusOffset,
955 (((uint32_t)(EE_RECORD_STATUS_VALID) << 16u) | 0x0000FFFFu)))
956 {
957 /* read record ID */
958 if (expID == READ16(recordAddress + handle->eeRecordIDOffset))
959 {
960 returnCode = recordAddress;
961 break;
962 }
963 }
964 /* If CallBack is enabled, then serve callback function if counter reaches limitation */
965 #if EE_CALLBACK_ENABLE
966 /* Check if need to serve callback function */
967 counter++;
968 if (counter >= (uint32_t)EE_CALLBACK_COUNTER)
969 {
970 g_EECallBack();
971 /* Reset counter */
972 counter = 0x00u;
973 }
974 #endif
975 } while (recordAddress > sectorAddress);
976 return (returnCode);
977 }
978
979 /*******************************************************************************
980 *
981 * Function Name : EE_SearchBlankSpace
982 * Description : To find blank space for each sector
983 * Arguments :
984 * - sectorAddress: start address of sector to find blank space.
985 * Return Value :
986 * - blank space of this sector
987 *
988 *******************************************************************************/
EE_SearchBlankSpace(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)989 uint32_t EE_SearchBlankSpace(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
990 {
991 uint32_t searchAddress;
992 #if EE_CALLBACK_ENABLE
993 uint32_t counter = 0x00u;
994 #endif
995 /* flag to indicate this record is blank or not */
996 bool blankFlag;
997 /* backup blank flag. Initilize it as true to handle with the first search is non blanked record */
998 bool bkBlankFlag = true;
999
1000 /* point to the beginning of each record. Start with the last record within each sector */
1001 searchAddress = sectorAddress + handle->eeSectorSize - handle->eeSectorWaste;
1002 /* point to beginning of the first record */
1003 sectorAddress += (uint32_t)handle->eeSectorHeaderSize;
1004 /* Search all the records of the sector */
1005 do
1006 {
1007 /* Decrement searchAddress by EE_RECORD_LENGTH */
1008 searchAddress -= handle->eeSectorRecordLength;
1009 /* Do blank check for every record length from bottom up*/
1010 if (EE_OK == EE_BlankCheck(handle, searchAddress, handle->eeSectorRecordLength))
1011 {
1012 blankFlag = true; /* this record is blanked */
1013 }
1014 else /* this record is not blank */
1015 {
1016 if (bkBlankFlag == true) /* and the next record is blank */
1017 {
1018 /* point to blank space */
1019 searchAddress = searchAddress + handle->eeSectorRecordLength;
1020 break;
1021 }
1022 }
1023
1024 /* backup dataID for the next search */
1025 bkBlankFlag = blankFlag;
1026
1027 /* If CallBack is enabled, then serve callback function if counter reaches limitation */
1028 #if EE_CALLBACK_ENABLE
1029 /* Check if need to serve callback function */
1030 counter++;
1031
1032 if (counter >= (uint32_t)EE_CALLBACK_COUNTER)
1033 {
1034 g_EECallBack();
1035 /* Reset counter */
1036 counter = 0x00u;
1037 }
1038 #endif
1039 } while (searchAddress > sectorAddress);
1040
1041 return (searchAddress);
1042 }
1043
1044 /*******************************************************************************
1045 *
1046 * Function Name : EE_SearchInCache
1047 * Description : Searches record with a specific record ID in cache table
1048 * Arguments :
1049 * - dataID: the ID required to search
1050 * Return Value :
1051 * - address of found record
1052 * - 0xFFFFFFFF If not found
1053 *
1054 *******************************************************************************/
1055 #if EE_CACHETABLE_ENABLE
EE_SearchInCache(uint16_t dataID)1056 uint32_t EE_SearchInCache(uint16_t dataID)
1057 {
1058 uint32_t returnCode = 0xFFFFFFFFu;
1059 /* Check if the DataID is in the cache table */
1060 if (EE_CACHETABLE_MAX_ENTRY >= dataID)
1061 {
1062 returnCode = READ32(EE_CACHETABLE_ITEM_ADDR(dataID));
1063 }
1064 return (returnCode); /* not found return 0xFFFFFFFFu */
1065 }
1066 #endif
1067
1068 /*******************************************************************************
1069 *
1070 * Function Name : EE_SearchInAllActive
1071 * Description : Searches record with a specific record ID in all
1072 * active sector from bottom up and from newest to oldest
1073 * active sector. Don't search in cache table.
1074 * Arguments :
1075 * - dataID is the expected ID to be searched.
1076 * Return Value :
1077 * - address of found record
1078 * - 0xFFFFFFFF If not found
1079 *
1080 *******************************************************************************/
EE_SearchInAllActives(eeprom_emulation_handle_t * handle,uint16_t dataID)1081 uint32_t EE_SearchInAllActives(eeprom_emulation_handle_t *handle, uint16_t dataID)
1082 {
1083 uint32_t sectorAddress = g_currentActiveSector;
1084 uint32_t recordAddress;
1085 uint32_t returnCode = 0xFFFFFFFFu;
1086 uint8_t actNum;
1087 actNum = (uint8_t)handle->eeActiveSectors;
1088 /* Search in the ACTIVE sectors only. Start with current active sector */
1089 do
1090 {
1091 /* only search in the active sector, ignore alt, ready and dead sectors */
1092 if (EE_SECTOR_ACTIVE == EE_GetSectorStatus(handle, sectorAddress))
1093 {
1094 actNum--;
1095 recordAddress = EE_SearchInSector(handle, dataID, sectorAddress);
1096 if (recordAddress != 0xFFFFFFFFu)
1097 {
1098 /* break if found the expected ID */
1099 returnCode = recordAddress;
1100 break;
1101 }
1102 }
1103 /* search the previous sector */
1104 sectorAddress = EE_PrevSector(handle, sectorAddress);
1105 } while (actNum > 0x00u);
1106 return (returnCode); /* not found return 0xFFFFFFFFu */
1107 }
1108
1109 /*******************************************************************************
1110 *
1111 * Function Name : EE_SearchLoop
1112 * Description : Searches record with a specific record ID in cache table
1113 * first. If not found in cache, continue to search in all
1114 * active sectors from newest to oldest and from bottom to
1115 * top.
1116 * Arguments :
1117 * - dataID: required ID to be searched.
1118 * Return Value :
1119 * - address of found record
1120 * - 0xFFFFFFFF If not found
1121 *
1122 *******************************************************************************/
EE_SearchLoop(eeprom_emulation_handle_t * handle,uint16_t dataID)1123 uint32_t EE_SearchLoop(eeprom_emulation_handle_t *handle, uint16_t dataID)
1124 {
1125 uint32_t recordAddress = 0xFFFFFFFFu;
1126 /* Check if cache table is enabled and data is in valid range of cache, search in cache first */
1127 #if EE_CACHETABLE_ENABLE
1128 if (dataID <= (uint16_t)EE_CACHETABLE_MAX_ENTRY)
1129 {
1130 recordAddress = EE_SearchInCache(dataID);
1131 return recordAddress;
1132 }
1133 #endif
1134
1135 #if EE_CACHETABLE_ENABLE
1136 if (dataID > (uint16_t)EE_CACHETABLE_MAX_ENTRY)
1137 {
1138 #endif
1139 /* ID is not in the cache table, need to search in all active sectors */
1140 recordAddress = EE_SearchInAllActives(handle, dataID);
1141 #if EE_CACHETABLE_ENABLE
1142 }
1143 #endif
1144
1145 return recordAddress;
1146 }
1147
1148 /*******************************************************************************
1149 *
1150 * Function Name : EE_BlankCheck
1151 * Description : Do blank check for a specific flash range.
1152 * Arguments :
1153 * - address: address needs to do blank check.
1154 * - size: size to do blank check.
1155 * Return Value :
1156 * - EE_OK if successful
1157 * - EE_NOT_OK if failed
1158 *
1159 *******************************************************************************/
EE_BlankCheck(eeprom_emulation_handle_t * handle,uint32_t address,uint32_t size)1160 uint32_t EE_BlankCheck(eeprom_emulation_handle_t *handle, uint32_t address, uint32_t size)
1161 {
1162 uint32_t returnCode = EE_OK;
1163 uint32_t read1SectorSize = handle->ftfxRD1SECSize;
1164
1165 while ((size > 0x00u) && (returnCode == EE_OK))
1166 {
1167 if ((GET_MOD(address, read1SectorSize) != 0x00u) || (size < read1SectorSize))
1168 {
1169 /* blank check by READ32 if address is not aligned or size < FTFx_RD1SEC_SIZE*/
1170 returnCode = EE_VerifySectorHeader(handle, address, 0xFFFFFFFFu);
1171 if (returnCode == EE_OK)
1172 {
1173 address += FTFx_LONGWORD_SIZE;
1174 size -= FTFx_LONGWORD_SIZE;
1175 }
1176 else
1177 {
1178 returnCode = EE_NOT_OK;
1179 }
1180 }
1181 else
1182 {
1183 /* blank check by verify section if address is aligned
1184 and size is larger than 1 RD1PHR aligned size*/
1185 returnCode = EE_FlashEraseVerifySection(handle, address, (uint16_t)(size / read1SectorSize),
1186 handle->flashReadMargin);
1187 if (returnCode == EE_OK)
1188 {
1189 /* if erase verify section returns OK, mean entire sector is blank*/
1190 address += (size / read1SectorSize) * read1SectorSize;
1191 size -= (size / read1SectorSize) * read1SectorSize;
1192 }
1193 else
1194 {
1195 returnCode = EE_NOT_OK;
1196 }
1197 }
1198 }
1199 return (returnCode);
1200 }
1201
1202 /*******************************************************************************
1203 *
1204 * Function Name : EE_GetSectorStatus
1205 * Description : This function returns the status of the sector by ignoring
1206 * the validation of erase cycle value.
1207 * Arguments :
1208 * - sectorAddress: start address of sector
1209 * Return Value :
1210 * - status of sector
1211 *
1212 *******************************************************************************/
EE_GetSectorStatus(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)1213 uint8_t EE_GetSectorStatus(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
1214 {
1215 uint8_t returnCode = 0x00u;
1216 uint32_t deadIndValue = 0x00u; /* data in dead indicator */
1217 uint32_t actIndValue = 0x00u; /* data in active indicator */
1218
1219 if (EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorDeadIndOffset, EE_DATA_STATUS_BLANK) == EE_OK)
1220 {
1221 deadIndValue = (uint32_t)EE_DATA_STATUS_BLANK;
1222 }
1223 if (EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorActIndOffset, EE_DATA_STATUS_BLANK) == EE_OK)
1224 {
1225 actIndValue = (uint32_t)EE_DATA_STATUS_BLANK;
1226 }
1227
1228 if (deadIndValue != (uint32_t)EE_DATA_STATUS_BLANK)
1229 {
1230 /* if dead indicator is not blank or alive, this is dead sector */
1231 returnCode = EE_SECTOR_DEAD;
1232 }
1233 if (returnCode != EE_SECTOR_DEAD)
1234 {
1235 if (actIndValue != EE_DATA_STATUS_BLANK)
1236 {
1237 if (EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset, 0xFFFFFFFFu) != EE_OK)
1238 {
1239 returnCode = EE_SECTOR_ACTIVE;
1240 }
1241 else
1242 {
1243 returnCode = EE_SECTOR_INVALID;
1244 }
1245 }
1246 else
1247 {
1248 /* From now on, active indicator is blank,
1249 dead indicator is blank or alive,
1250 sector area exclusive sector header is blank.*/
1251 if (EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset, 0xFFFFFFFFu) != EE_OK)
1252 {
1253 if (EE_BlankCheck(handle, sectorAddress + (uint32_t)handle->eeSectorHeaderSize,
1254 handle->eeSectorSize - handle->eeSectorHeaderSize) == EE_OK)
1255 {
1256 /* at this time, have data in erase cycle location, active indicator is blank
1257 dead indicator is blank or alive*/
1258 /* if dead indicator is blank, this sector is alternative */
1259 returnCode = EE_SECTOR_ALTERNATIVE;
1260 }
1261 else
1262 {
1263 returnCode = EE_SECTOR_INVALID;
1264 }
1265 }
1266 /*At this time, active indicator is blank,
1267 dead indicator is blank or alive,
1268 no data in erase cycle,
1269 sector area exclusive sector header is blank*/
1270 else
1271 {
1272 if (EE_BlankCheck(handle, sectorAddress + (uint32_t)handle->eeSectorHeaderSize,
1273 handle->eeSectorSize - handle->eeSectorHeaderSize) == EE_OK)
1274 {
1275 /* at this time, have data in erase cycle location, active indicator is blank
1276 dead indicator is blank or alive*/
1277 /* if dead indicator is blank, this sector is alternative */
1278 returnCode = EE_SECTOR_BLANK;
1279 }
1280 else
1281 {
1282 returnCode = EE_SECTOR_INVALID;
1283 }
1284 }
1285 }
1286 }
1287
1288 return (returnCode);
1289 }
1290
1291 /*******************************************************************************
1292 *
1293 * Function Name : EE_FindActSector
1294 * Description : This function will find the oldest/newest or active
1295 * sectors according to closestFlag flag.
1296 * Arguments : - sectorAddress: current sector address.
1297 * - closestFlag: flag to find the closest (true) active
1298 * sector or most far (false) sector.
1299 * - nextFlag: flag to find the active sector in the
1300 * right (true) or in the left (false).
1301 * Return Value :
1302 * - address of found record
1303 * - 0xFFFFFFFF If not found
1304 *
1305 *******************************************************************************/
EE_FindActSector(eeprom_emulation_handle_t * handle,uint32_t sectorAddress,bool closestFlag,bool nextFlag)1306 uint32_t EE_FindActSector(eeprom_emulation_handle_t *handle, uint32_t sectorAddress, bool closestFlag, bool nextFlag)
1307 {
1308 uint32_t returnCode = 0xFFFFFFFFu;
1309 uint32_t i;
1310 uint8_t sectorStatus;
1311
1312 for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1313 {
1314 if (nextFlag == true)
1315 {
1316 sectorAddress = EE_NextSector(handle, sectorAddress);
1317 }
1318 else
1319 {
1320 sectorAddress = EE_PrevSector(handle, sectorAddress);
1321 }
1322 sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1323 if ((EE_SECTOR_ACTIVE == sectorStatus) ||
1324 ((EE_SECTOR_ALTERNATIVE == sectorStatus) && (returnCode != 0xFFFFFFFFu)))
1325 {
1326 if (closestFlag == true)
1327 {
1328 returnCode = sectorAddress;
1329 }
1330 else
1331 {
1332 if (EE_SECTOR_ACTIVE == sectorStatus)
1333 {
1334 returnCode = sectorAddress;
1335 }
1336 else
1337 {
1338 i = handle->eeAllotedSectors;
1339 }
1340 }
1341 }
1342 }
1343 return (returnCode);
1344 }
1345
1346 /*******************************************************************************
1347 *
1348 * Function Name : EE_GetSectorNumber
1349 * Description : This function will calculate sector number based on its
1350 * state.
1351 * Arguments :
1352 * - expStatus: expected status to accumulate sector number
1353 * Return Value :
1354 * - total number of sector for expected status
1355 *
1356 *******************************************************************************/
EE_GetSectorNumber(eeprom_emulation_handle_t * handle,uint8_t expStatus)1357 uint8_t EE_GetSectorNumber(eeprom_emulation_handle_t *handle, uint8_t expStatus)
1358 {
1359 uint32_t sectorAddress;
1360 uint8_t sectorStatus;
1361 uint8_t cnt = 0x00u;
1362 uint8_t i;
1363 /* initialize value for pNum*/
1364 sectorAddress = handle->eeStartAddress;
1365 for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1366 {
1367 sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1368 if (sectorStatus == expStatus)
1369 {
1370 cnt++;
1371 }
1372 /* sectorAddress += handle->eeSectorSize */
1373 sectorAddress = EE_NextSector(handle, sectorAddress);
1374 }
1375 return (cnt);
1376 }
1377
1378 /*******************************************************************************
1379 *
1380 * Function Name : EE_ValidateDeadIndicator
1381 * Description : This function is to make a sector as DEAD
1382 * Arguments :
1383 * - sectorAddress: address of sector
1384 * Return Value :
1385 * - EE_OK if successful
1386 * - EE_NOT_OK if failed
1387 *
1388 *******************************************************************************/
EE_ValidateDeadIndicator(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)1389 uint32_t EE_ValidateDeadIndicator(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
1390 {
1391 uint32_t returnCode = EE_OK;
1392 uint32_t data[2];
1393 uint8_t num = 0x00u;
1394 data[0] = (uint32_t)EE_DATA_STATUS_DEAD;
1395 if (handle->ftfxProgramSize > FTFx_LONGWORD_SIZE)
1396 {
1397 data[1] = 0xFFFFFFFFu;
1398 }
1399 sectorAddress += (uint32_t)handle->eeSectorDeadIndOffset;
1400 do
1401 {
1402 returnCode = EE_MultiProgram(handle, sectorAddress, handle->ftfxProgramSize, (uint8_t *)&data);
1403 /* verify again */
1404 /* point to dead indicator address */
1405 if (EE_OK == EE_VerifySectorHeader(handle, sectorAddress, (uint32_t)EE_DATA_STATUS_BLANK))
1406 {
1407 num++;
1408 /* if after making this as DEAD but the data is still BLANK or ALIVE
1409 it means validate fails*/
1410 if (num > handle->eeRetryMax)
1411 {
1412 returnCode = EE_NOT_OK;
1413 }
1414 }
1415 else
1416 {
1417 returnCode = EE_OK;
1418 }
1419 } while ((returnCode != EE_OK) && (num <= handle->eeRetryMax));
1420 return (returnCode);
1421 }
1422 /*******************************************************************************
1423 *
1424 * Function Name : EE_ValidateEraseCycle
1425 * Description : This function will program erase cycle.
1426 * If possible, it will make this sector as DEAD if fails in
1427 * programming.
1428 * Arguments :
1429 * - sectorAddress: address of invalid sector
1430 * - pData: pointer for expected erase cycle value
1431 * Return Value :
1432 * - EE_OK if successful
1433 * - EE_NOT_OK if failed
1434 *
1435 *******************************************************************************/
EE_ValidateEraseCycle(eeprom_emulation_handle_t * handle,uint32_t sectorAddress,uint8_t * pData)1436 uint32_t EE_ValidateEraseCycle(eeprom_emulation_handle_t *handle, uint32_t sectorAddress, uint8_t *pData)
1437 {
1438 uint32_t returnCode = EE_OK;
1439 uint32_t ret = EE_OK;
1440 uint8_t num = 0x00u;
1441
1442 do
1443 {
1444 returnCode =
1445 EE_MultiProgram(handle, sectorAddress + handle->eeSectorEraseCycleOffset, handle->ftfxProgramSize, pData);
1446 if (returnCode != EE_OK)
1447 {
1448 ret = EE_ReEraseEeprom(handle, sectorAddress);
1449 if (ret != EE_OK)
1450 {
1451 returnCode = ret;
1452 break;
1453 }
1454 else
1455 {
1456 num++;
1457 if (num > handle->eeRetryMax)
1458 {
1459 returnCode = EE_ValidateDeadIndicator(handle, sectorAddress);
1460 if (returnCode == EE_OK)
1461 {
1462 returnCode = EE_MAKEDEAD_OK;
1463 }
1464 }
1465 }
1466 }
1467 } while ((returnCode != EE_OK) && (num <= handle->eeRetryMax));
1468 return (returnCode);
1469 }
1470 /*******************************************************************************
1471 *
1472 * Function Name : EE_ValidateActIndicator
1473 * Description : This function will program data to active indicator.
1474 * If possible, it will make this sector as DEAD if fails in
1475 * programming.
1476 * Arguments :
1477 * - sectorAddress: address sector
1478 * - deadNum: current number of dead sector
1479 * Return Value :
1480 * - EE_OK if successful
1481 * - EE_NOT_OK if failed
1482 *
1483 *******************************************************************************/
EE_ValidateActIndicator(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)1484 uint32_t EE_ValidateActIndicator(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
1485 {
1486 uint32_t returnCode = EE_OK;
1487 uint32_t ret = EE_OK;
1488 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1489 uint32_t data[4];
1490 #else
1491 uint32_t data[2];
1492 #endif
1493 uint8_t num = 0x00u;
1494
1495 data[0] = (uint32_t)EE_DATA_STATUS_ACTIVE;
1496 if (handle->ftfxProgramSize > FTFx_LONGWORD_SIZE)
1497 {
1498 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1499 data[1] = 0xFFFFFFFFu;
1500 data[2] = 0xFFFFFFFFu;
1501 data[3] = 0xFFFFFFFFu;
1502 #else
1503 data[1] = 0xFFFFFFFFu;
1504 #endif
1505 }
1506 do
1507 {
1508 ret = EE_MultiProgram(handle, sectorAddress + (uint32_t)handle->eeSectorActIndOffset, handle->ftfxProgramSize,
1509 (uint8_t *)&data);
1510 ret = EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorActIndOffset, EE_DATA_STATUS_BLANK);
1511 if (ret != EE_OK)
1512 {
1513 break;
1514 }
1515 else
1516 {
1517 num++;
1518 if (num > handle->eeRetryMax)
1519 {
1520 returnCode = EE_ValidateDeadIndicator(handle, sectorAddress);
1521 if (returnCode == EE_OK)
1522 {
1523 returnCode = EE_MAKEDEAD_OK;
1524 }
1525 }
1526 }
1527 } while (num <= handle->eeRetryMax);
1528
1529 return (returnCode);
1530 }
1531
1532 /*******************************************************************************
1533 *
1534 * Function Name : EE_ReEraseEeprom
1535 * Description : This function will re-erase 1 sector with several times
1536 * Arguments :
1537 * - sectorAddress: the address of sector need to re-erase
1538 * Return Value :
1539 * - EE_OK if successful
1540 * - EE_NOT_OK if re-erase fail and make DEAD fail
1541 * - EE_MAKEDEAD_OK if re-erase fail and make DEAD successful
1542 *
1543 *******************************************************************************/
EE_ReEraseEeprom(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)1544 uint32_t EE_ReEraseEeprom(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
1545 {
1546 uint32_t returnCode = EE_OK;
1547 uint8_t num = 0x00u;
1548
1549 do
1550 {
1551 /* if re-erase sector fail, re-erase several times before make it to DEAD sector */
1552 returnCode = EE_SyncFlashErase(handle, sectorAddress);
1553 if (returnCode != EE_OK)
1554 {
1555 num++;
1556 if (num > handle->eeRetryMax)
1557 {
1558 returnCode = EE_ValidateDeadIndicator(handle, sectorAddress);
1559 if (returnCode == EE_OK)
1560 {
1561 returnCode = EE_MAKEDEAD_OK;
1562 }
1563 }
1564 }
1565 } while ((returnCode != EE_OK) && (num <= handle->eeRetryMax));
1566 return (returnCode);
1567 }
1568
1569 /*******************************************************************************
1570 *
1571 * Function Name : EE_ReEraseEeprom
1572 * Description : This function will re-erase 1 sector with several times
1573 * Arguments : N/A
1574 * Return Value :
1575 * - EE_OK if enough sector for working sequence
1576 * - EE_NOT_OK if not enough sector for working sequence
1577 *
1578 *******************************************************************************/
EE_CheckAvailabilityStatus(eeprom_emulation_handle_t * handle)1579 uint32_t EE_CheckAvailabilityStatus(eeprom_emulation_handle_t *handle)
1580 {
1581 uint32_t returnCode = EE_OK;
1582 uint32_t sectorAddress;
1583 uint32_t sectorStatus;
1584 uint8_t totalAliveSector = 0x00u;
1585 uint8_t i;
1586 sectorAddress = handle->eeStartAddress;
1587 for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1588 {
1589 sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1590 if ((sectorStatus == EE_SECTOR_BLANK) || (sectorStatus == EE_SECTOR_ALTERNATIVE))
1591 {
1592 totalAliveSector++;
1593 }
1594 /* sectorAddress += handle->eeSectorSize */
1595 sectorAddress = EE_NextSector(handle, sectorAddress);
1596 }
1597 if (totalAliveSector < handle->eeActualReadySectors)
1598 {
1599 returnCode = EE_NOT_OK;
1600 }
1601 return (returnCode);
1602 }
1603 /*******************************************************************************
1604 *
1605 * Function Name : EE_UpdateCacheTable
1606 * Description : This function will update the cache table
1607 * Arguments : N/A
1608 * Return Value : N/A
1609 *
1610 *******************************************************************************/
1611 /* Initialize the cache table with all the values, if it is enabled */
1612 #if EE_CACHETABLE_ENABLE
EE_UpdateCacheTable(eeprom_emulation_handle_t * handle)1613 void EE_UpdateCacheTable(eeprom_emulation_handle_t *handle)
1614 {
1615 uint32_t tableAddress;
1616 uint32_t recordAddress;
1617 uint16_t dataID;
1618
1619 /* Hold the start address of cache table */
1620 tableAddress = EE_CACHETABLE_START_ADDRESS;
1621 /* Loop through the data ID that should be written to the Cache Table */
1622 for (dataID = 1u; dataID <= EE_CACHETABLE_MAX_ENTRY; dataID++)
1623 {
1624 /* Search all the ACTIVE sectors */
1625 recordAddress = EE_SearchInAllActives(handle, dataID);
1626 WRITE32(tableAddress, recordAddress);
1627
1628 tableAddress += (uint32_t)EE_CACHETABLE_ITEM_SIZE;
1629 }
1630 }
1631 #endif
1632
1633 /*******************************************************************************
1634 *
1635 * Function Name : EE_ISRHandler
1636 * Description : Interrupt service routine for Command Complete.
1637 * Arguments : N/A
1638 * Return Value : N/A
1639 *
1640 *******************************************************************************/
1641 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
1642 #ifdef DSC_CORE
1643 #pragma interrupt
1644 #endif
EE_ISRHandler(void)1645 void INTERRUPT EE_ISRHandler(void) /* Flash interrupt service function */
1646 {
1647 /* Disable command complete interrupt */
1648 REG_BIT_CLEAR(FTFx_FCNFG, FTFx_FCNFG_CCIE);
1649
1650 /* checking error */
1651 if (0x00u != (REG_READ(FTFx_FSTAT) & FTFx_FSTAT_CHECK_ERR))
1652 {
1653 g_eraseStatusFlag = FAIL;
1654 }
1655 else
1656 {
1657 g_eraseStatusFlag = DONE;
1658 }
1659 }
1660 #endif
1661
1662 /* High level functions */
1663
EE_PreInitCheck(eeprom_emulation_handle_t * handle)1664 static uint32_t EE_PreInitCheck(eeprom_emulation_handle_t *handle)
1665 {
1666 uint32_t returnCode = EE_OK; /* variable return EE_InitEeprom() function state.*/
1667 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1668 uint32_t expErsCycValue[4]; /* buffer to store erase cycle, which is written to erase cycle address.*/
1669 #else
1670 uint32_t expErsCycValue[2]; /* buffer to store erase cycle, which is written to erase cycle address.*/
1671 #endif
1672 uint32_t sectorAddress; /* variable help we know the address is activated at that time.*/
1673 uint32_t currentActsectorAddress = 0x00u;
1674 uint8_t i;
1675
1676 /***********
1677 STEP 1: Check for the first time initialization
1678 This step will find and erase oldest active sector if it has more than number expected active sector .
1679 If erasing oldest active sector is fail, it will re-erase this sector several times before make this
1680 to dead sector. If make dead sector fail return EE_NOT_OK error.It will check total dead sector and
1681 return EE_NOT_OK error if break sequence because of not enough alive sector.
1682 ***********/
1683
1684 if (EE_GetSectorNumber(handle, EE_SECTOR_ACTIVE) >
1685 (uint8_t)handle->eeActiveSectors) /* check if more than expected active sectors */
1686 {
1687 /* find oldest active sector and erase it */
1688 sectorAddress = EE_FindActSector(handle, handle->eeStartAddress, false, false);
1689 returnCode = EE_ReEraseEeprom(handle, sectorAddress);
1690 if (returnCode != EE_NOT_OK)
1691 {
1692 returnCode = EE_CheckAvailabilityStatus(handle);
1693 }
1694 }
1695 /***********
1696 STEP 2: Check for other cases - isn't the first time initialization
1697 This step will find and erase all invalid sector. If erasing all invalid sectors is fail, it will re-erase
1698 all these sector several times before make them to dead sectors. If make dead sector fail return EE_NOT_OK
1699 error. It will check total dead sector and return EE_NOT_OK error if break sequence because of not enough alive
1700 sector
1701 ***********/
1702 else
1703 {
1704 /* find all invalid sector and erase it */
1705 sectorAddress = (uint32_t)handle->eeStartAddress;
1706 for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1707 {
1708 if (EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_INVALID)
1709 {
1710 returnCode = EE_ReEraseEeprom(handle, sectorAddress);
1711 if (returnCode != EE_NOT_OK)
1712 {
1713 returnCode = EE_CheckAvailabilityStatus(handle);
1714 }
1715 }
1716 if (returnCode == EE_NOT_OK)
1717 {
1718 break;
1719 }
1720 sectorAddress += (uint32_t)handle->eeSectorSize;
1721 }
1722 }
1723
1724 if (returnCode == EE_OK)
1725 {
1726 sectorAddress = EE_FindActSector(handle, handle->eeStartAddress, false, false);
1727 /* it isn't the first time initialization because it has active sector*/
1728 if (sectorAddress != 0xFFFFFFFFu)
1729 {
1730 expErsCycValue[0] = READ32(sectorAddress + handle->eeSectorEraseCycleOffset);
1731 currentActsectorAddress = sectorAddress;
1732 /* find the ALT sector before ACT sector that have invalid erase cycle and erase it */
1733 do
1734 {
1735 sectorAddress = EE_PrevSector(handle, sectorAddress);
1736 /* erase all alternate sector have invalid sector before oldest active sector */
1737 if ((EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_ALTERNATIVE) &&
1738 ((sectorAddress >= handle->eeStartAddress) && (sectorAddress < currentActsectorAddress)))
1739 {
1740 if (EE_OK != EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset,
1741 expErsCycValue[0] + 0x01u))
1742 {
1743 returnCode = EE_ReEraseEeprom(handle, sectorAddress);
1744 if (returnCode != EE_NOT_OK)
1745 {
1746 returnCode = EE_CheckAvailabilityStatus(handle);
1747 }
1748 }
1749 }
1750 /* erase all alternate sector have invalid sector behind oldest active sector */
1751 if ((EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_ALTERNATIVE) &&
1752 (sectorAddress > currentActsectorAddress) &&
1753 (sectorAddress <= (g_eeEndAddress - handle->eeSectorSize)))
1754 {
1755 if (EE_OK != EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset,
1756 expErsCycValue[0]))
1757 {
1758 returnCode = EE_ReEraseEeprom(handle, sectorAddress);
1759 if (returnCode != EE_NOT_OK)
1760 {
1761 returnCode = EE_CheckAvailabilityStatus(handle);
1762 }
1763 }
1764 }
1765 if (returnCode == EE_NOT_OK)
1766 {
1767 break;
1768 }
1769 } while (sectorAddress != currentActsectorAddress);
1770 }
1771 /* it is the first time initialization because it does not has active sector*/
1772 else
1773 {
1774 sectorAddress = (uint32_t)handle->eeStartAddress;
1775 /* find and erase all the ALT sectors have erase cycle different 1 if there is no ACT sector */
1776 for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1777 {
1778 uint32_t tempVal =
1779 EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset, 0x01u);
1780 uint32_t tempValBackup =
1781 EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset, 0xFFFFFFFFu);
1782
1783 if ((EE_OK != tempVal) && (EE_OK != tempValBackup))
1784 {
1785 returnCode = EE_ReEraseEeprom(handle, sectorAddress);
1786 if (returnCode != EE_NOT_OK)
1787 {
1788 returnCode = EE_CheckAvailabilityStatus(handle);
1789 }
1790 }
1791 if (returnCode == EE_NOT_OK)
1792 {
1793 break;
1794 }
1795 sectorAddress += (uint32_t)handle->eeSectorSize;
1796 }
1797 }
1798 }
1799
1800 return returnCode;
1801 }
1802
EE_InitAltSector(eeprom_emulation_handle_t * handle,uint8_t * number)1803 static uint32_t EE_InitAltSector(eeprom_emulation_handle_t *handle, uint8_t *number)
1804 {
1805 uint32_t returnCode = EE_OK; /* variable return EE_InitEeprom() function state.*/
1806 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1807 uint32_t expErsCycValue[4]; /* buffer to store erase cycle, which is written to erase cycle address.*/
1808 #else
1809 uint32_t expErsCycValue[2]; /* buffer to store erase cycle, which is written to erase cycle address.*/
1810 #endif
1811 uint32_t sectorAddress; /* variable help we know the address is activated at that time.*/
1812 uint32_t currentActsectorAddress = 0x00u;
1813 uint8_t tempTotalActiveSector = 0x00u; /* variable help we know how many active sector at that time.*/
1814 uint8_t sectorStatus; /* variable help we know the state of sector when we call.*/
1815 uint8_t i;
1816
1817 if (handle->ftfxProgramSize > FTFx_LONGWORD_SIZE)
1818 {
1819 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1820 expErsCycValue[1] = 0xFFFFFFFFu;
1821 expErsCycValue[2] = 0xFFFFFFFFu;
1822 expErsCycValue[3] = 0xFFFFFFFFu;
1823 g_eraseCycles[1] = 0xFFFFFFFFu;
1824 g_eraseCycles[2] = 0xFFFFFFFFu;
1825 g_eraseCycles[3] = 0xFFFFFFFFu;
1826 #else
1827 expErsCycValue[1] = 0xFFFFFFFFu;
1828 g_eraseCycles[1] = 0xFFFFFFFFu;
1829 #endif
1830 }
1831
1832 /***********
1833 STEP 3:
1834 This step will check if STEP 1 & STEP 2is done and successful, it will make all alive sectors to ALT sectors
1835 ***********/
1836
1837 /* This segment will make all blank sector to alter sector by write erase cycle to its address.
1838 When make a blank sector to alter sector, if making fail. It will re-erase this sector and
1839 re-make to alter sector several time before make dead sector. If make dead sector fail too
1840 return EE_NOT_OK error. It will check total dead sector and return EE_NOT_OK error if break
1841 sequence because of not enough alter sector */
1842 tempTotalActiveSector = EE_GetSectorNumber(handle, EE_SECTOR_ACTIVE);
1843 /* If this is the first time initializing, erase cycle must is 1 */
1844 if (tempTotalActiveSector == 0x00u)
1845 {
1846 expErsCycValue[0u] = 0x01u;
1847 g_eraseCycles[0x00u] = expErsCycValue[0u];
1848 sectorAddress = (uint32_t)handle->eeStartAddress;
1849 for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1850 {
1851 sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1852 if (sectorStatus == EE_SECTOR_BLANK)
1853 {
1854 returnCode = EE_ValidateEraseCycle(handle, sectorAddress, (uint8_t *)expErsCycValue);
1855 }
1856 if (returnCode == EE_MAKEDEAD_OK)
1857 {
1858 returnCode = EE_CheckAvailabilityStatus(handle);
1859 }
1860 if (returnCode == EE_NOT_OK)
1861 {
1862 break;
1863 }
1864 sectorAddress += (uint32_t)handle->eeSectorSize;
1865 }
1866 }
1867 /* Write valid erase cycle for all BLANKS sectors */
1868 else
1869 {
1870 expErsCycValue[0u] = READ32(currentActsectorAddress + handle->eeSectorEraseCycleOffset);
1871 g_eraseCycles[0u] = expErsCycValue[0u];
1872 sectorAddress = EE_FindActSector(handle, handle->eeStartAddress, false, false);
1873 currentActsectorAddress = sectorAddress;
1874 /* Make all blank sector before active sector to alternate sector */
1875 do
1876 {
1877 sectorAddress = EE_PrevSector(handle, sectorAddress);
1878 /* calculate erase cycle of all blank sectors before oldest active sector */
1879 if ((EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_BLANK) &&
1880 (sectorAddress >= handle->eeStartAddress))
1881 {
1882 expErsCycValue[0u] = g_eraseCycles[0] + 0x01u;
1883 }
1884 /* calculate erase cycle of all blank sectors behind oldest active sector */
1885 if ((EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_BLANK) &&
1886 (sectorAddress > currentActsectorAddress) && (sectorAddress <= (g_eeEndAddress - handle->eeSectorSize)))
1887 {
1888 expErsCycValue[0u] = g_eraseCycles[0u];
1889 }
1890 /* write erase cycle for blank sector */
1891 if (EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_BLANK)
1892 {
1893 returnCode = EE_ValidateEraseCycle(handle, sectorAddress, (uint8_t *)expErsCycValue);
1894 if (returnCode == EE_MAKEDEAD_OK)
1895 {
1896 returnCode = EE_CheckAvailabilityStatus(handle);
1897 }
1898 if (returnCode == EE_NOT_OK)
1899 {
1900 break;
1901 }
1902 }
1903 } while (sectorAddress != currentActsectorAddress);
1904 }
1905
1906 *number = tempTotalActiveSector;
1907
1908 return returnCode;
1909 }
1910
EE_InitActiveSector(eeprom_emulation_handle_t * handle,uint8_t number)1911 static uint32_t EE_InitActiveSector(eeprom_emulation_handle_t *handle, uint8_t number)
1912 {
1913 uint32_t returnCode = EE_OK; /* variable return EE_InitEeprom() function state.*/
1914 uint32_t sectorAddress = 0x00U; /* variable help we know the address is activated at that time.*/
1915 uint8_t tempTotalActiveSector = number; /* variable help we know how many active sector at that time.*/
1916 uint8_t sectorStatus; /* variable help we know the state of sector when we call.*/
1917
1918 /***********
1919 STEP 4:
1920 This step will check if STEP 1, STEP 2, and STEP 3 is done and successful, it will make all ALT sectors to
1921 ACT sectors
1922 ***********/
1923
1924 /* This segment will make all alter sector to active sector by write erase cycle to its address.
1925 When make a alter sector to active sector, if making fail. It will re-erase this sector and
1926 re-make to active sector several time before make dead sector. If make dead sector fail return
1927 EE_NOT_OK error. It will check total dead sector and return EE_NOT_OK error if break sequence
1928 because of not enough alter sector */
1929 /* check enough sector for sequence */
1930 if (tempTotalActiveSector == 0x00u)
1931 {
1932 sectorAddress = handle->eeStartAddress;
1933 }
1934 else
1935 {
1936 sectorAddress = EE_FindActSector(handle, sectorAddress, true, true);
1937 }
1938
1939 /* make enough active sector for EEE */
1940 if (tempTotalActiveSector < (uint32_t)handle->eeActiveSectors)
1941 {
1942 do
1943 {
1944 sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1945 if (sectorStatus == EE_SECTOR_ALTERNATIVE)
1946 {
1947 returnCode = EE_ValidateActIndicator(handle, sectorAddress);
1948 if (returnCode == EE_OK)
1949 {
1950 tempTotalActiveSector++;
1951 }
1952 if (returnCode == EE_MAKEDEAD_OK)
1953 {
1954 returnCode = EE_CheckAvailabilityStatus(handle);
1955 }
1956 if (returnCode == EE_NOT_OK)
1957 {
1958 break;
1959 }
1960 }
1961 sectorAddress = EE_NextSector(handle, sectorAddress);
1962 } while (tempTotalActiveSector < handle->eeActiveSectors);
1963 }
1964
1965 /* re-check enough sector for sequence */
1966 if (returnCode == EE_OK)
1967 {
1968 returnCode = EE_CheckAvailabilityStatus(handle);
1969 if (returnCode == EE_OK)
1970 {
1971 tempTotalActiveSector = 0x01u;
1972 g_currentActiveSector = EE_FindActSector(handle, handle->eeStartAddress, false, false);
1973 g_freeSpaceAddress = EE_SearchBlankSpace(handle, g_currentActiveSector);
1974 while (
1975 (tempTotalActiveSector < handle->eeActiveSectors) &&
1976 ((g_freeSpaceAddress + handle->eeSectorRecordLength) > (g_currentActiveSector + handle->eeSectorSize)))
1977 {
1978 /* update g_freeSpaceAddress */
1979 g_currentActiveSector = EE_NextSector(handle, g_currentActiveSector);
1980 if (EE_GetSectorStatus(handle, g_currentActiveSector) == EE_SECTOR_ACTIVE)
1981 {
1982 tempTotalActiveSector++;
1983 g_freeSpaceAddress = EE_SearchBlankSpace(handle, g_currentActiveSector);
1984 }
1985 }
1986 }
1987 }
1988
1989 return returnCode;
1990 }
1991
1992 /*******************************************************************************
1993 *
1994 * Function Name : EE_Init
1995 * Description : This function will determine active,
1996 alternative and brown out affected sectors and
1997 erase/update the sectors. Initializing variables
1998 that hold active sector related information like
1999 the start addresses of the active sector
2000 and the blank space available is also done in this
2001 function. The dead sectors are re-erased again for
2002 next usage and cache table is also initialized in this
2003 function. If no sectors are initialized then,
2004 this function shall initialize all the sectors in
2005 a round robin queue
2006 * Arguments : N/A
2007 * Return Value :
2008 * - EE_OK if successful
2009 * - EE_NOT_OK if failed
2010 *
2011 *******************************************************************************/
2012
EE_Init(eeprom_emulation_handle_t * handle)2013 uint32_t EE_Init(eeprom_emulation_handle_t *handle)
2014 {
2015 uint32_t returnCode = EE_OK; /* variable return EE_InitEeprom() function state.*/
2016 uint8_t totalActiveSector = 0x00u; /* variable help we know how many active sector at that time.*/
2017 /* Initialize all global variables */
2018 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
2019 g_addressToMain = 0xFFFFFFFFu;
2020 g_endAddressToMain = 0xFFFFFFFFu;
2021 #endif
2022 g_eraseStatusFlag = IDLE;
2023 g_eeEndAddress = handle->eeEndAddress;
2024
2025 {
2026 /* clear cache */
2027 #if EE_CACHETABLE_ENABLE
2028 sectorAddress = (uint32_t)EE_CACHETABLE_START_ADDRESS;
2029 for (i = 0x01u; i <= EE_CACHETABLE_MAX_ENTRY; i++)
2030 {
2031 WRITE32(sectorAddress, 0xFFFFFFFFu);
2032 sectorAddress += (uint32_t)EE_CACHETABLE_ITEM_SIZE;
2033 }
2034 #endif
2035
2036 /* Check initliazation or not. */
2037 returnCode = EE_PreInitCheck(handle);
2038 if (EE_OK == returnCode)
2039 {
2040 /* Init altnative sectors. */
2041 returnCode = EE_InitAltSector(handle, &totalActiveSector);
2042 }
2043
2044 if (EE_OK == returnCode)
2045 {
2046 /* Init active sectors. */
2047 returnCode = EE_InitActiveSector(handle, totalActiveSector);
2048 }
2049 }
2050
2051 /* update cache table if enabled */
2052 #if EE_CACHETABLE_ENABLE == true
2053 if (returnCode == EE_OK)
2054 {
2055 EE_UpdateCacheTable(handle);
2056 }
2057 #endif
2058 return (returnCode);
2059 }
2060
2061 /*******************************************************************************
2062 *
2063 * Function Name : EE_ReadEeprom
2064 * Description : This function is used to read the specific data record.
2065 The starting address of the record data will be returned.
2066 * Arguments :
2067 * - dataID: the record ID to be read.
2068 * - recordAddr: address of found record.
2069 * Return Value :
2070 * - EE_OK if found record.
2071 * - 0xFFFFFFFFu if not found record.
2072 * - EE_ERR_IDRANGE if ID invalid value.
2073 *
2074 *******************************************************************************/
EE_ReadData(eeprom_emulation_handle_t * handle,uint16_t dataID,uint32_t * recordAddr)2075 uint32_t EE_ReadData(eeprom_emulation_handle_t *handle, uint16_t dataID, uint32_t *recordAddr)
2076 {
2077 uint32_t returnCode = EE_OK;
2078 /* This segment will for validate ID, sure that it is in the range of ID */
2079 if (((uint16_t)(handle->eeMaxRecordNumber) < dataID) || (0x00u == dataID))
2080 {
2081 returnCode = EE_ERR_IDRANGE;
2082 }
2083 /* Search for data for the record in all active sectors. It will return address
2084 of data record if found ID. Or it return 0xFFFFFFFFu value*/
2085 if (returnCode != EE_ERR_IDRANGE)
2086 {
2087 *recordAddr = EE_SearchLoop(handle, dataID);
2088 if (*recordAddr == 0xFFFFFFFFu)
2089 {
2090 returnCode = 0xFFFFFFFFu;
2091 }
2092 }
2093 return (returnCode);
2094 }
2095
2096 /*******************************************************************************
2097 *
2098 * Function Name : EE_WriteData
2099 * Description : This function will be used to write new data record to
2100 * EEPROM emulation.
2101 * Arguments :
2102 * - dataID: record ID to be written.
2103 * - source: source data to be written.
2104 * Return Value :
2105 * - EE_OK if successful
2106 * - EE_NOT_OK if failed
2107 * - EE_ERR_IDRANGE if ID out of range
2108 * - EE_ERR_UPDATE if swapping occurred but fail
2109 *
2110 *******************************************************************************/
EE_WriteData(eeprom_emulation_handle_t * handle,uint16_t dataID,uint32_t source)2111 uint32_t EE_WriteData(eeprom_emulation_handle_t *handle, uint16_t dataID, uint32_t source)
2112 {
2113 uint32_t returnCode = EE_OK;
2114 uint32_t sectorAddress;
2115 uint32_t alginedSize;
2116 uint32_t remainingSize;
2117 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2118 uint32_t i;
2119 #endif
2120
2121 uint8_t sectorStatus = 0x00u;
2122 /* Defined in preprocessor */
2123 uint8_t remainData[EE_DATA_VALUE_REMAINING_PART];
2124 bool swapFlag = false;
2125
2126 /*Calculate data value aligned part and remaining part */
2127 alginedSize = handle->eeDataValueSize - (handle->eeDataValueSize % handle->ftfxProgramSize);
2128 remainingSize = handle->eeSectorRecordLength - alginedSize - handle->ftfxProgramSize - handle->complementSize;
2129
2130 /* Check if the ID is within the range or equal to zero */
2131 if ((dataID > (uint16_t)handle->eeMaxRecordNumber) || (dataID == 0x00u))
2132 {
2133 returnCode = EE_ERR_IDRANGE;
2134 }
2135 else
2136 {
2137 /* Copying the data ID and the data Values into the structure */
2138 g_dataRecord.dataID = dataID;
2139 /* Copying the dataAddr into the structure */
2140 g_dataRecord.dataAddr = source;
2141 /* Calculate free space available in the current active sector */
2142 /* Check if the space is enough to write a record */
2143 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2144 /* scan for 2 times in synchronous model to write internal data */
2145 for (i = 0x00u; i < handle->eeActiveSectors; i++)
2146 {
2147 #endif
2148 /* for synchronous model,need to back WriteEeprom function to write
2149 internal data here (when i is 0x1) */
2150
2151 if (((g_currentActiveSector + handle->eeSectorSize) - g_freeSpaceAddress) < handle->eeSectorRecordLength)
2152 {
2153 /* if there is no free space on current active sector*/
2154 sectorAddress = g_currentActiveSector;
2155 returnCode = EE_CheckAvailabilityStatus(handle);
2156
2157 if (returnCode == EE_NOT_OK)
2158 {
2159 /* Return EE_NOT_OK error if break sequence because of not enough alter sector */
2160 break;
2161 }
2162
2163 if (returnCode == EE_OK)
2164 {
2165 do
2166 {
2167 sectorAddress = EE_NextSector(handle, sectorAddress);
2168 sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
2169 } while ((sectorStatus == EE_SECTOR_DEAD) || (sectorStatus == EE_SECTOR_READY));
2170 }
2171
2172 if ((sectorStatus == EE_SECTOR_ALTERNATIVE) && (returnCode == EE_OK))
2173 {
2174 /* if there is no active sector in the next ones. Swapping must occur*/
2175 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2176 returnCode = EE_SwapSector(handle);
2177 if (returnCode == EE_OK)
2178 {
2179 /* if swapping successful, continue to write internal data*/
2180 continue;
2181 }
2182 else
2183 {
2184 /* if swapping fail, return EE_ERR_UPDATE*/
2185 returnCode = EE_ERR_UPDATE;
2186 break;
2187 }
2188 #else
2189 returnCode = EE_SwapSector(handle);
2190 swapFlag = true;
2191 #endif
2192 }
2193 /* if find active one in the next sector, no swapping is needed.*/
2194 /* Make new sector as active one to write record to this new sector */
2195 if (sectorStatus == EE_SECTOR_ACTIVE)
2196 {
2197 g_currentActiveSector = sectorAddress;
2198 g_freeSpaceAddress = g_currentActiveSector + (uint32_t)handle->eeSectorHeaderSize;
2199 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2200 /* "i = handle->eeActiveSectors;" is same method to break this for() loop, but it violates MISRA
2201 * rule 14.2(required). */
2202 break;
2203 #endif
2204 }
2205 }
2206
2207 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2208 }
2209 #endif
2210 }
2211
2212 /* no swapping occurs. Write new record to current free space address*/
2213 /* prepare remaining data */
2214 /* initialize remainData, reuse sectorStatus variable to save stack */
2215 if (((returnCode == (uint32_t)EE_OK) && (swapFlag == false) &&
2216 (((g_currentActiveSector + handle->eeSectorSize) - g_freeSpaceAddress) >=
2217 (uint32_t)handle->eeSectorRecordLength)))
2218 {
2219 for (sectorStatus = 0x00u; sectorStatus < remainingSize; sectorStatus++)
2220 {
2221 if (sectorStatus < ((uint8_t)handle->eeDataValueSize - (uint8_t)alginedSize))
2222 {
2223 remainData[sectorStatus] = (uint8_t)READ8(g_dataRecord.dataAddr + (uint8_t)alginedSize + sectorStatus);
2224 }
2225 else
2226 {
2227 remainData[sectorStatus] = 0xFFu;
2228 }
2229 }
2230 remainData[remainingSize - ID_LOWBYTE_OFFSET] = (uint8_t)(g_dataRecord.dataID);
2231 remainData[remainingSize - ID_HIGHBYTE_OFFSET] = (uint8_t)(g_dataRecord.dataID >> 8);
2232 returnCode = EE_CopyRecord(handle, g_dataRecord, remainData);
2233 if (returnCode == EE_OK)
2234 {
2235 g_eraseStatusFlag = IDLE;
2236 }
2237 }
2238
2239 return (returnCode);
2240 }
2241
2242 /*******************************************************************************
2243 *
2244 * Function Name : EE_ReportStatus
2245 * Description : This function reports the erase cycle of current active sector.
2246 * Arguments : N/A
2247 * Return Value :
2248 * - erase cycle of current active sector.
2249 *
2250 *******************************************************************************/
EE_ReportStatus(eeprom_emulation_handle_t * handle)2251 uint32_t EE_ReportStatus(eeprom_emulation_handle_t *handle)
2252 {
2253 /* get erase cycle for current active sector */
2254 return (READ32(g_currentActiveSector + handle->eeSectorEraseCycleOffset));
2255 }
2256
2257 /*******************************************************************************
2258 *
2259 * Function Name : EE_Deinit
2260 * Description : This function is to release all the Flash used to
2261 EEPROM emulation. After de-initialize, the Flash
2262 for emulation will be fully erased.
2263 * Arguments : N/A
2264 * Return Value :
2265 * - EE_OK if successful
2266 * - EE_NOT_OK if failed
2267 *
2268 *******************************************************************************/
EE_Deinit(eeprom_emulation_handle_t * handle)2269 uint32_t EE_Deinit(eeprom_emulation_handle_t *handle)
2270 {
2271 uint32_t sectorAddress = handle->eeStartAddress;
2272 uint32_t returnCode = EE_OK;
2273 uint8_t numDead = 0x00u;
2274 uint8_t i;
2275 /* Re-erase all sectors, one by one from first sector to end sector */
2276 for (i = 0x00u; i < handle->eeAllotedSectors; i++)
2277 {
2278 returnCode = EE_ReEraseEeprom(handle, sectorAddress);
2279 if (returnCode == EE_NOT_OK)
2280 {
2281 break;
2282 }
2283 if (returnCode == EE_MAKEDEAD_OK)
2284 {
2285 numDead++;
2286 }
2287 sectorAddress += (uint32_t)handle->eeSectorSize;
2288 }
2289 if (numDead > handle->eeExtraReadySectors)
2290 {
2291 returnCode = EE_NOT_OK;
2292 }
2293 if ((returnCode != EE_NOT_OK) && (numDead <= handle->eeActualReadySectors))
2294 {
2295 returnCode = EE_OK;
2296 }
2297
2298 return (returnCode);
2299 }
2300
2301 /*******************************************************************************
2302 *
2303 * Function Name : EE_Main()
2304 * Description : Completes the initialization of sectors and other
2305 operations to make it ready for EEPROM emulation.
2306 * Arguments : N/A
2307 * Return Value :
2308 * - EE_OK if successful
2309 * - EE_NOT_OK if failed
2310 * - EE_ERR_UPDATE if swapping occurred but fail
2311 *
2312 *******************************************************************************/
2313 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
EE_Main(eeprom_emulation_handle_t * handle)2314 uint32_t EE_Main(eeprom_emulation_handle_t *handle)
2315 {
2316 uint32_t returnCode = EE_OK;
2317 uint32_t erasedSectorAddr;
2318
2319 if (DONE == g_eraseStatusFlag)
2320 {
2321 /* Check for there is still flash sector in the EEE sector need erased */
2322 g_addressToMain += handle->flashSectorSize;
2323 if (g_addressToMain < g_endAddressToMain)
2324 {
2325 /* Erase the next flash sector in the EEE sector */
2326 EE_AsyncFlashErase(handle, g_addressToMain);
2327 }
2328 else
2329 {
2330 /* Get address of the erased sector */
2331 erasedSectorAddr = g_endAddressToMain - handle->eeSectorSize;
2332
2333 /* complete erase for entire EE sector. So, verify section to make sure the sector
2334 was erased successfully */
2335 /* verify if sector erase done and successful. If sector is dead ignore this section */
2336 returnCode = EE_FlashEraseVerifySection(handle, erasedSectorAddr,
2337 (uint16_t)(handle->eeSectorSize / handle->ftfxRD1SECSize),
2338 handle->flashReadMargin);
2339 if (returnCode == EE_OK)
2340 {
2341 /* pass verify section, change g_eraseStatusFlag to IDLE */
2342 /* program erase cycle to the sector which has been erased */
2343 /* write internal data which causes swapping */
2344 returnCode = EE_MultiProgram(handle, erasedSectorAddr + handle->eeSectorEraseCycleOffset,
2345 (uint32_t)handle->ftfxProgramSize, (uint8_t *)&g_eraseCycles);
2346 }
2347
2348 if (returnCode != EE_OK)
2349 {
2350 /* fail in verify section, make the global flag to FAIL */
2351 g_eraseStatusFlag = FAIL;
2352
2353 g_numErase++;
2354 if (g_numErase <= handle->eeRetryMax)
2355 {
2356 /* Reset address point to start-address of the erased sector... */
2357 g_addressToMain = erasedSectorAddr;
2358
2359 /* ...then re-erase the EEE sector */
2360 EE_AsyncFlashErase(handle, g_addressToMain);
2361
2362 /* Update return code */
2363 returnCode = EE_OK;
2364 }
2365 else
2366 {
2367 /* Make this sector as DEAD */
2368 returnCode = EE_ValidateDeadIndicator(handle, erasedSectorAddr);
2369
2370 if (returnCode == EE_OK)
2371 {
2372 /* validate successfully */
2373 /* update global flag to IDLE and then write internal data which causes swapping */
2374 returnCode = EE_CheckAvailabilityStatus(handle);
2375 if (returnCode == EE_OK)
2376 {
2377 /* Reset erase flag */
2378 g_eraseStatusFlag = IDLE;
2379 }
2380 }
2381
2382 if (returnCode != EE_OK)
2383 {
2384 /* Return UPDATE error if can't make the sector to DEAD or
2385 * there isn't enough sectors for the sequence */
2386 returnCode = EE_ERR_UPDATE;
2387 }
2388
2389 /* Reset re-erase number */
2390 g_numErase = 0u;
2391 }
2392 }
2393 else
2394 {
2395 /* Reset erase flag */
2396 g_eraseStatusFlag = IDLE;
2397 g_numErase = 0u;
2398 }
2399
2400 /* Only write internal data if finish the erasing, updating erase cycle */
2401 if ((IDLE == g_eraseStatusFlag) && (returnCode == EE_OK))
2402 {
2403 returnCode = EE_WriteData(handle, g_dataRecord.dataID, g_dataRecord.dataAddr);
2404 }
2405 }
2406 }
2407
2408 return (returnCode);
2409 }
2410 #endif /* EE_USE_ASYNCHRONOUS_MODEL */
2411