00001
00016 #include <stdbool.h>
00017 #include "nvm.h"
00018
00019
00020
00021
00022
00027 #define NVM_VERSION 0x2U
00028
00029
00030 #define NVM_CONTENT_SIZE (NVM_PAGE_SIZE - (NVM_HEADER_SIZE + NVM_FOOTER_SIZE))
00031 #define NVM_WEAR_CONTENT_SIZE (NVM_PAGE_SIZE - NVM_HEADER_SIZE)
00032
00033 #define NVM_PAGE_EMPTY_VALUE 0xffffU
00034 #define NVM_NO_PAGE_RETURNED 0xffffffffUL
00035 #define NVM_NO_WRITE_16BIT 0xffffU
00036 #define NVM_NO_WRITE_32BIT 0xffffffffUL
00037 #define NVM_HIGHEST_32BIT 0xffffffffUL
00038 #define NVM_FLIP_FIRST_BIT_OF_32_WHEN_WRITE 0xffff7fffUL
00039 #define NVM_FIRST_BIT_ONE 0x8000U
00040 #define NVM_FIRST_BIT_ZERO 0x7fffU
00041 #define NVM_LAST_BIT_ZERO 0xfffeU
00042
00043 #define NVM_CHECKSUM_INITIAL 0xffffU
00044 #define NVM_CHECKSUM_LENGTH 0x2U
00045
00046 #define NVM_PAGES_PER_WEAR_HISTORY 0x8U
00047
00048
00049
00050
00051 #ifndef NVM_ACQUIRE_WRITE_LOCK
00052 #define NVM_ACQUIRE_WRITE_LOCK
00053 #endif
00054
00055 #ifndef NVM_RELEASE_WRITE_LOCK
00056 #define NVM_RELEASE_WRITE_LOCK
00057 #endif
00058
00061
00062
00063
00064
00067 typedef enum
00068 {
00069 nvmValidateResultOk = 0,
00070 nvmValidateResultOkMarked = 1,
00071 nvmValidateResultOld = 2,
00072 nvmValidateResultError = 3
00073 } NVM_ValidateResult_t;
00074
00077 typedef struct
00078 {
00079 uint16_t watermark;
00080 uint32_t updateId;
00081 uint16_t version;
00082 } NVM_Page_Header_t;
00083
00085 #define NVM_HEADER_SIZE (2 * sizeof(uint16_t) + sizeof(uint32_t))
00086
00089 typedef struct
00090 {
00091 uint16_t checksum;
00092 uint16_t watermark;
00093 } NVM_Page_Footer_t;
00094
00096 #define NVM_FOOTER_SIZE (2 * sizeof(uint16_t))
00097
00100
00101
00102
00103
00107 static NVM_Config_t const *nvmConfig;
00108
00109 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
00110
00111
00112
00113
00114 static uint8_t nvmStaticWearWriteHistory[(NVM_MAX_NUMBER_OF_PAGES + (NVM_PAGES_PER_WEAR_HISTORY - 1)) / NVM_PAGES_PER_WEAR_HISTORY];
00115
00116
00117 static uint16_t nvmStaticWearWritesInHistory;
00118
00119
00120 static uint16_t nvmStaticWearErasesSinceReset;
00121
00122
00123 static bool nvmStaticWearWorking = false;
00124 #endif
00125
00128
00129
00130
00131
00134 static uint8_t* NVM_PageFind(uint16_t pageId);
00135 static uint8_t* NVM_ScratchPageFindBest(void);
00136 static Ecode_t NVM_PageErase(uint8_t *pPhysicalAddress);
00137 static NVM_Page_Descriptor_t NVM_PageGet(uint16_t pageId);
00138 static NVM_ValidateResult_t NVM_PageValidate(uint8_t *pPhysicalAddress);
00139
00140 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00141 static uint16_t NVM_WearIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc);
00142 static bool NVM_WearReadIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc, uint16_t *pIndex);
00143 #endif
00144
00145 static void NVM_ChecksumAdditive(uint16_t *pChecksum, void *pBuffer, uint16_t len);
00146
00147 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
00148 static void NVM_StaticWearReset(void);
00149 static void NVM_StaticWearUpdate(uint16_t address);
00150 static Ecode_t NVM_StaticWearCheck(void);
00151 #endif
00152
00154
00155
00156
00157
00158
00184 Ecode_t NVM_Init(NVM_Config_t const *config)
00185 {
00186 uint16_t page;
00187
00188 Ecode_t result = ECODE_EMDRV_NVM_ERROR;
00189
00190
00191 uint8_t *pPhysicalAddress = (uint8_t *)(config->nvmArea);
00192
00193 uint8_t *pDuplicatePhysicalAddress;
00194
00195
00196 uint16_t logicalAddress;
00197
00198 uint16_t duplicateLogicalAddress;
00199
00200
00201 NVM_ValidateResult_t validationResult;
00202
00203 Ecode_t eraseResult;
00204
00205
00206 if( (config->pages <= config->userPages) || (config->pages > NVM_MAX_NUMBER_OF_PAGES) )
00207 return ECODE_EMDRV_NVM_ERROR;
00208
00209
00210 {
00211 uint16_t pageIdx = 0, obj = 0, sum = 0;
00212 const NVM_Page_Descriptor_t *currentPage;
00213
00214 for(pageIdx = 0; pageIdx < config->userPages; pageIdx++)
00215 {
00216 sum = 0;
00217 obj = 0;
00218 currentPage = &((*(config->nvmPages))[pageIdx]);
00219
00220 while( (*(currentPage->page))[obj].location != 0)
00221 sum += (*(currentPage->page))[obj++].size;
00222
00223 if(currentPage->pageType == nvmPageTypeNormal)
00224 {
00225 if( sum > NVM_CONTENT_SIZE )
00226 {
00227 return ECODE_EMDRV_NVM_ERROR;
00228 }
00229 }
00230 else
00231 {
00232 if(currentPage->pageType == nvmPageTypeWear)
00233 {
00234 if( (sum+NVM_CHECKSUM_LENGTH) > NVM_WEAR_CONTENT_SIZE )
00235 {
00236 return ECODE_EMDRV_NVM_ERROR;
00237 }
00238 } else
00239 {
00240 return ECODE_EMDRV_NVM_ERROR;
00241 }
00242 }
00243 }
00244 }
00245
00246 nvmConfig = config;
00247
00248
00249 NVM_ACQUIRE_WRITE_LOCK
00250
00251
00252 NVMHAL_Init();
00253
00254 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
00255
00256 NVM_StaticWearReset();
00257 #endif
00258
00259
00260 for (page = 0; page < nvmConfig->pages; ++page)
00261 {
00262
00263
00264 NVMHAL_Read(pPhysicalAddress, &logicalAddress, sizeof(logicalAddress));
00265 if (NVM_PAGE_EMPTY_VALUE != logicalAddress)
00266 {
00267
00268 validationResult = NVM_PageValidate(pPhysicalAddress);
00269
00270
00271 if (nvmValidateResultOk == validationResult)
00272 {
00273
00274
00275 if (ECODE_EMDRV_NVM_ERROR == result)
00276 {
00277 result = ECODE_EMDRV_NVM_OK;
00278 }
00279 }
00280 else if (nvmValidateResultOkMarked == validationResult)
00281 {
00282
00283
00284
00285
00286
00287 pDuplicatePhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
00288 for (page = 0; (NVM_PAGE_EMPTY_VALUE != logicalAddress) && (page < nvmConfig->pages);
00289 ++page)
00290 {
00291 NVMHAL_Read(pDuplicatePhysicalAddress, &duplicateLogicalAddress, sizeof(duplicateLogicalAddress));
00292
00293 if ((pDuplicatePhysicalAddress != pPhysicalAddress) && ((logicalAddress | NVM_FIRST_BIT_ONE) == duplicateLogicalAddress))
00294 {
00295
00296
00297 validationResult = NVM_PageValidate(pDuplicatePhysicalAddress);
00298
00299 if (nvmValidateResultOk == validationResult)
00300 {
00301
00302 eraseResult = NVM_PageErase(pPhysicalAddress);
00303 }
00304 else
00305 {
00306
00307 eraseResult = NVM_PageErase(pDuplicatePhysicalAddress);
00308 }
00309
00310
00311 if (ECODE_EMDRV_NVM_OK != eraseResult)
00312 {
00313 result = ECODE_EMDRV_NVM_ERROR;
00314 }
00315 }
00316
00317
00318 pDuplicatePhysicalAddress += NVM_PAGE_SIZE;
00319 }
00320
00321
00322
00323 if (ECODE_EMDRV_NVM_ERROR == result)
00324 {
00325 result = ECODE_EMDRV_NVM_OK;
00326 }
00327 }
00328 else
00329 {
00330
00331 result = ECODE_EMDRV_NVM_ERROR;
00332 }
00333 }
00334
00335
00336 pPhysicalAddress += NVM_PAGE_SIZE;
00337 }
00338
00339
00340 if (ECODE_EMDRV_NVM_ERROR == result)
00341 {
00342 result = ECODE_EMDRV_NVM_NO_PAGES_AVAILABLE;
00343 }
00344
00345
00346 NVM_RELEASE_WRITE_LOCK
00347
00348 return result;
00349 }
00350
00351
00369 Ecode_t NVM_Erase(uint32_t erasureCount)
00370 {
00371 uint16_t page;
00372
00373 Ecode_t result = ECODE_EMDRV_NVM_ERROR;
00374
00375
00376 uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
00377
00378
00379 uint32_t tempErasureCount = erasureCount;
00380
00381
00382 NVM_ACQUIRE_WRITE_LOCK
00383
00384
00385 for (page = 0;
00386 (page < nvmConfig->pages) && ((ECODE_EMDRV_NVM_OK == result) || (ECODE_EMDRV_NVM_ERROR == result));
00387 ++page)
00388 {
00389
00390
00391 if (NVM_ERASE_RETAINCOUNT == erasureCount)
00392 {
00393
00394 NVMHAL_Read(pPhysicalAddress + 2, &tempErasureCount, sizeof(tempErasureCount));
00395 }
00396
00397
00398 result = NVMHAL_PageErase(pPhysicalAddress);
00399
00400
00401 if (ECODE_EMDRV_NVM_OK == result)
00402 {
00403 result = NVMHAL_Write(pPhysicalAddress + 2, &tempErasureCount, sizeof(tempErasureCount));
00404 }
00405
00406
00407 pPhysicalAddress += NVM_PAGE_SIZE;
00408 }
00409
00410
00411 NVM_RELEASE_WRITE_LOCK
00412
00413 return result;
00414 }
00415
00416
00441 Ecode_t NVM_Write(uint16_t pageId, uint8_t objectId)
00442 {
00443
00444 Ecode_t result = ECODE_EMDRV_NVM_ERROR;
00445
00446
00447 uint16_t watermark = pageId | NVM_FIRST_BIT_ONE;
00448
00449 const uint32_t flipWatermark = NVM_FLIP_FIRST_BIT_OF_32_WHEN_WRITE;
00450
00451
00452 NVM_Page_Descriptor_t pageDesc;
00453
00454
00455
00456 NVM_Page_Header_t header;
00457
00458
00459 uint16_t checksum = NVM_CHECKSUM_INITIAL;
00460
00461
00462 uint8_t *pOldPhysicalAddress = (uint8_t *) NVM_NO_PAGE_RETURNED;
00463 uint8_t *pNewPhysicalAddress = (uint8_t *) NVM_NO_PAGE_RETURNED;
00464
00465
00466 uint16_t offsetAddress;
00467
00468 uint8_t copyBuffer;
00469
00470 uint8_t objectIndex;
00471
00472 uint16_t copyLength;
00473
00474
00475
00476 bool wearWrite = false;
00477
00478 #if (NVM_FEATURE_WRITE_NECESSARY_CHECK_ENABLED == true)
00479
00480 bool rewriteNeeded;
00481 #endif
00482
00483 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00484
00485 uint16_t wearChecksum;
00486
00487 uint16_t wearObjectSize;
00488
00489 uint16_t wearIndex;
00490
00491 #if (NVM_FEATURE_WRITE_VALIDATION_ENABLED == true)
00492
00493 uint16_t wearIndexNew;
00494 #endif
00495 #endif
00496
00497
00498 NVM_ACQUIRE_WRITE_LOCK
00499
00500
00501 pOldPhysicalAddress = NVM_PageFind(pageId);
00502
00503
00504 pageDesc = NVM_PageGet(pageId);
00505
00506 #if (NVM_FEATURE_WRITE_NECESSARY_CHECK_ENABLED == true)
00507
00508
00509
00510
00511 if (((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
00512 && (nvmPageTypeNormal == pageDesc.pageType)
00513 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
00514 && !nvmStaticWearWorking
00515 #endif
00516
00517 )
00518 {
00519 rewriteNeeded = false;
00520 objectIndex = 0;
00521 offsetAddress = 0;
00522
00523
00524
00525 while (((*pageDesc.page)[objectIndex].size != 0) && !rewriteNeeded)
00526 {
00527
00528
00529 if ((NVM_WRITE_ALL_CMD == objectId) ||
00530 ((*pageDesc.page)[objectIndex].objectId == objectId))
00531 {
00532
00533
00534 copyLength = (*pageDesc.page)[objectIndex].size;
00535
00536
00537 while (copyLength != 0)
00538 {
00539
00540 NVMHAL_Read(pOldPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00541 ©Buffer,
00542 sizeof(copyBuffer));
00543
00544
00545 if (*(uint8_t *)((*pageDesc.page)[objectIndex].location + offsetAddress) != copyBuffer)
00546 {
00547 rewriteNeeded = true;
00548 break;
00549 }
00550
00551
00552 offsetAddress += sizeof(copyBuffer);
00553 copyLength -= sizeof(copyBuffer);
00554 }
00555 }
00556 else
00557 {
00558
00559 offsetAddress += (*pageDesc.page)[objectIndex].size;
00560 }
00561
00562
00563 objectIndex++;
00564 }
00565
00566 if (!rewriteNeeded)
00567 {
00568
00569 NVM_RELEASE_WRITE_LOCK
00570
00571 return ECODE_EMDRV_NVM_OK;
00572 }
00573 }
00574 #endif
00575
00576
00577
00578 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00579
00580
00581
00582
00583 if (nvmPageTypeWear == pageDesc.pageType)
00584 {
00585
00586
00587
00588
00589 wearChecksum = NVM_CHECKSUM_INITIAL;
00590 NVM_ChecksumAdditive(&wearChecksum, (*pageDesc.page)[0].location, (*pageDesc.page)[0].size);
00591 wearChecksum &= NVM_LAST_BIT_ZERO;
00592
00593
00594 if ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
00595 {
00596
00597 wearIndex = NVM_WearIndex(pOldPhysicalAddress, &pageDesc);
00598 wearObjectSize = (*pageDesc.page)[0].size + NVM_CHECKSUM_LENGTH;
00599
00600
00601 if (wearIndex < ((uint16_t) NVM_WEAR_CONTENT_SIZE) / wearObjectSize)
00602 {
00603 result = NVMHAL_Write(pOldPhysicalAddress + NVM_HEADER_SIZE + wearIndex * wearObjectSize,
00604 (*pageDesc.page)[0].location,
00605 (*pageDesc.page)[0].size);
00606 result = NVMHAL_Write(pOldPhysicalAddress + NVM_HEADER_SIZE + wearIndex * wearObjectSize + (*pageDesc.page)[0].size,
00607 &wearChecksum,
00608 sizeof(wearChecksum));
00609
00610
00611 wearWrite = true;
00612
00613 #if (NVM_FEATURE_WRITE_VALIDATION_ENABLED == true)
00614
00615
00616 if ((!NVM_WearReadIndex(pOldPhysicalAddress, &pageDesc, &wearIndexNew)) ||
00617 (wearIndexNew != wearIndex))
00618 {
00619 result = ECODE_EMDRV_NVM_ERROR;
00620 }
00621 #endif
00622 }
00623 }
00624 }
00625 #endif
00626
00627 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00628
00629 if (!wearWrite)
00630 {
00631 #endif
00632
00633 if ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
00634 {
00635 result = NVMHAL_Write(pOldPhysicalAddress, &flipWatermark, 4);
00636
00637 if (ECODE_EMDRV_NVM_OK != result)
00638 {
00639
00640 NVM_RELEASE_WRITE_LOCK
00641 return result;
00642 }
00643 }
00644
00645
00646 pNewPhysicalAddress = NVM_ScratchPageFindBest();
00647
00648 if ((uint8_t*) NVM_NO_PAGE_RETURNED == pNewPhysicalAddress)
00649 {
00650
00651 NVM_RELEASE_WRITE_LOCK
00652 return ECODE_EMDRV_NVM_ERROR;
00653 }
00654
00655
00656 header.watermark = watermark;
00657 header.updateId = NVM_NO_WRITE_32BIT;
00658 header.version = NVM_VERSION;
00659
00660
00661 result = NVMHAL_Write(pNewPhysicalAddress, &header.watermark, sizeof(header.watermark));
00662 result = NVMHAL_Write(pNewPhysicalAddress + sizeof(header.watermark), &header.updateId, sizeof(header.updateId));
00663 result = NVMHAL_Write(pNewPhysicalAddress + sizeof(header.watermark)+ + sizeof(header.updateId), &header.version, sizeof(header.version));
00664
00665
00666 offsetAddress = 0;
00667
00668 objectIndex = 0;
00669
00670
00671
00672 while (((*pageDesc.page)[objectIndex].size != 0) && (ECODE_EMDRV_NVM_OK == result))
00673 {
00674
00675
00676 if ((NVM_WRITE_ALL_CMD == objectId) ||
00677 ((*pageDesc.page)[objectIndex].objectId == objectId))
00678 {
00679
00680 result = NVMHAL_Write(pNewPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00681 (*pageDesc.page)[objectIndex].location,
00682 (*pageDesc.page)[objectIndex].size);
00683 offsetAddress += (*pageDesc.page)[objectIndex].size;
00684
00685 NVM_ChecksumAdditive(&checksum, (*pageDesc.page)[objectIndex].location, (*pageDesc.page)[objectIndex].size);
00686 }
00687 else
00688 {
00689
00690 if ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
00691 {
00692 NVM_ChecksumAdditive(&checksum, pOldPhysicalAddress + offsetAddress + NVM_HEADER_SIZE, (*pageDesc.page)[objectIndex].size);
00693
00694 copyLength = (*pageDesc.page)[objectIndex].size;
00695
00696 while ((copyLength != 0) && (ECODE_EMDRV_NVM_OK == result))
00697 {
00698
00699 NVMHAL_Read(pOldPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00700 ©Buffer,
00701 sizeof(copyBuffer));
00702 result = NVMHAL_Write(pNewPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00703 ©Buffer,
00704 sizeof(copyBuffer));
00705
00706 offsetAddress += sizeof(copyBuffer);
00707 copyLength -= sizeof(copyBuffer);
00708 }
00709 }
00710 }
00711
00712 objectIndex++;
00713 }
00714
00715
00716 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00717 if (nvmPageTypeWear == pageDesc.pageType)
00718 {
00719 result = NVMHAL_Write(pNewPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00720 &wearChecksum,
00721 sizeof(wearChecksum));
00722 }
00723
00724 else
00725 {
00726 #endif
00727 if (ECODE_EMDRV_NVM_OK == result)
00728 {
00729
00730 result = NVMHAL_Write(pNewPhysicalAddress + (NVM_PAGE_SIZE - NVM_FOOTER_SIZE), &checksum, sizeof(checksum));
00731
00732 result = NVMHAL_Write(pNewPhysicalAddress + (NVM_PAGE_SIZE + sizeof(checksum) - NVM_FOOTER_SIZE), &watermark, sizeof(watermark));
00733 }
00734
00735 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00736 }
00737 #endif
00738
00739 #if (NVM_FEATURE_WRITE_VALIDATION_ENABLED == true)
00740
00741 if (nvmValidateResultOk != NVM_PageValidate(pNewPhysicalAddress))
00742 {
00743 result = ECODE_EMDRV_NVM_ERROR;
00744 }
00745 #endif
00746
00747 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00748 }
00749 #endif
00750
00751
00752 if ((!wearWrite) &&
00753 ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress))
00754 {
00755 if (ECODE_EMDRV_NVM_OK == result)
00756 {
00757 result = NVM_PageErase(pOldPhysicalAddress);
00758 }
00759 else
00760 {
00761 NVM_PageErase(pNewPhysicalAddress);
00762 }
00763 }
00764
00765
00766 NVM_RELEASE_WRITE_LOCK
00767
00768 return result;
00769 }
00770
00771
00791 Ecode_t NVM_Read(uint16_t pageId, uint8_t objectId)
00792 {
00793 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00794
00795 uint16_t wearIndex;
00796 #endif
00797
00798
00799 uint8_t *pPhysicalAddress;
00800
00801
00802 NVM_Page_Descriptor_t pageDesc;
00803
00804
00805 uint8_t objectIndex;
00806
00807 uint16_t offsetAddress;
00808
00809
00810
00811 NVM_ACQUIRE_WRITE_LOCK
00812
00813
00814 pPhysicalAddress = NVM_PageFind(pageId);
00815
00816
00817 if ((uint8_t*) NVM_NO_PAGE_RETURNED == pPhysicalAddress)
00818 {
00819
00820 NVM_RELEASE_WRITE_LOCK
00821 return ECODE_EMDRV_NVM_PAGE_INVALID;
00822 }
00823
00824
00825 pageDesc = NVM_PageGet(pageId);
00826
00827 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00828
00829
00830 if (nvmPageTypeWear == pageDesc.pageType)
00831 {
00832
00833 if (NVM_WearReadIndex(pPhysicalAddress, &pageDesc, &wearIndex))
00834 {
00835 NVMHAL_Read(pPhysicalAddress + NVM_HEADER_SIZE +
00836 wearIndex * ((*pageDesc.page)[0].size + NVM_CHECKSUM_LENGTH),
00837 (*pageDesc.page)[0].location,
00838 (*pageDesc.page)[0].size);
00839 }
00840 else
00841 {
00842
00843
00844 NVM_RELEASE_WRITE_LOCK
00845 return ECODE_EMDRV_NVM_DATA_INVALID;
00846 }
00847 }
00848 else
00849 #endif
00850 {
00851
00852 objectIndex = 0;
00853 offsetAddress = 0;
00854
00855 #if (NVM_FEATURE_READ_VALIDATION_ENABLED == true)
00856 if (nvmValidateResultError == NVM_PageValidate(pPhysicalAddress))
00857 {
00858
00859 NVM_RELEASE_WRITE_LOCK
00860 return ECODE_EMDRV_NVM_DATA_INVALID;
00861 }
00862 #endif
00863
00864
00865
00866 while ((*pageDesc.page)[objectIndex].size != 0)
00867 {
00868
00869 if ((NVM_READ_ALL_CMD == objectId) || ((*pageDesc.page)[objectIndex].objectId == objectId))
00870 {
00871 NVMHAL_Read(pPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00872 (*pageDesc.page)[objectIndex].location,
00873 (*pageDesc.page)[objectIndex].size);
00874 }
00875
00876 offsetAddress += (*pageDesc.page)[objectIndex].size;
00877 objectIndex++;
00878 }
00879 }
00880
00881
00882 NVM_RELEASE_WRITE_LOCK
00883
00884 return ECODE_EMDRV_NVM_OK;
00885 }
00886
00887
00898 #if (NVM_FEATURE_WEARLEVELGET_ENABLED == true)
00899 uint32_t NVM_WearLevelGet(void)
00900 {
00901 uint16_t page;
00902
00903 uint32_t updateId;
00904
00905 uint32_t worstUpdateId = 0;
00906
00907
00908 uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
00909
00910
00911 for (page = 0; page < nvmConfig->pages; ++page)
00912 {
00913
00914 NVMHAL_Read(pPhysicalAddress + 2, &updateId, sizeof(updateId));
00915 if (updateId > worstUpdateId)
00916 {
00917 worstUpdateId = updateId;
00918 }
00919
00920
00921 pPhysicalAddress += NVM_PAGE_SIZE;
00922 }
00923
00924 return worstUpdateId;
00925 }
00926 #endif
00927
00928
00929
00930
00931
00934
00949 static uint8_t* NVM_PageFind(uint16_t pageId)
00950 {
00951 uint16_t page;
00952
00953 uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
00954
00955 uint16_t logicalAddress;
00956
00957
00958 for (page = 0; page < nvmConfig->pages; ++page)
00959 {
00960
00961
00962 NVMHAL_Read(pPhysicalAddress, &logicalAddress, sizeof(logicalAddress));
00963 if (((pageId | NVM_FIRST_BIT_ONE) == logicalAddress) || (pageId == logicalAddress))
00964 {
00965 return pPhysicalAddress;
00966 }
00967
00968
00969 pPhysicalAddress += NVM_PAGE_SIZE;
00970 }
00971
00972
00973 return (uint8_t *) NVM_NO_PAGE_RETURNED;
00974 }
00975
00976
00988 static uint8_t* NVM_ScratchPageFindBest(void)
00989 {
00990 uint16_t page;
00991
00992 uint8_t *pPhysicalPage = (uint8_t *) NVM_NO_PAGE_RETURNED;
00993
00994
00995 uint32_t updateId = NVM_HIGHEST_32BIT;
00996
00997 uint32_t bestUpdateId = NVM_HIGHEST_32BIT;
00998
00999
01000 uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
01001
01002 uint16_t logicalAddress;
01003
01004
01005 for (page = 0; page < nvmConfig->pages; ++page)
01006 {
01007
01008 NVMHAL_Read(pPhysicalAddress, &logicalAddress, sizeof(logicalAddress));
01009 if ((uint16_t) NVM_PAGE_EMPTY_VALUE == logicalAddress)
01010 {
01011
01012 NVMHAL_Read(pPhysicalAddress + 2, &updateId, sizeof(updateId));
01013 if (updateId < bestUpdateId)
01014 {
01015 bestUpdateId = updateId;
01016 pPhysicalPage = pPhysicalAddress;
01017 }
01018 }
01019
01020
01021 pPhysicalAddress += NVM_PAGE_SIZE;
01022 }
01023
01024
01025 return pPhysicalPage;
01026 }
01027
01028
01042 static Ecode_t NVM_PageErase(uint8_t *pPhysicalAddress)
01043 {
01044 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
01045
01046 uint16_t logicalAddress;
01047 #endif
01048
01049
01050 uint32_t updateId;
01051 NVMHAL_Read(pPhysicalAddress + 2, &updateId, sizeof(updateId));
01052
01053 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
01054
01055 NVMHAL_Read(pPhysicalAddress, &logicalAddress, sizeof(logicalAddress));
01056
01057
01058 if (logicalAddress != NVM_PAGE_EMPTY_VALUE)
01059 {
01060
01061 logicalAddress = logicalAddress & NVM_FIRST_BIT_ZERO;
01062 NVM_StaticWearUpdate(logicalAddress);
01063 }
01064 #endif
01065
01066
01067 NVMHAL_PageErase(pPhysicalAddress);
01068
01069
01070 updateId++;
01071
01072
01073 return NVMHAL_Write(pPhysicalAddress + 2, &updateId, sizeof(updateId));
01074 }
01075
01076
01095 static NVM_Page_Descriptor_t NVM_PageGet(uint16_t pageId)
01096 {
01097 uint8_t pageIndex;
01098 static const NVM_Page_Descriptor_t nullPage = { (uint8_t) 0, 0, (NVM_Page_Type_t) 0 };
01099
01100
01101 for (pageIndex = 0; pageIndex < nvmConfig->userPages; ++pageIndex)
01102 {
01103
01104 if ( (*(nvmConfig->nvmPages))[pageIndex].pageId == pageId)
01105 {
01106 return (*(nvmConfig->nvmPages))[pageIndex];
01107 }
01108 }
01109
01110
01111 return nullPage;
01112 }
01113
01114
01135 static NVM_ValidateResult_t NVM_PageValidate(uint8_t *pPhysicalAddress)
01136 {
01137
01138 NVM_ValidateResult_t result;
01139
01140
01141 NVM_Page_Header_t header;
01142 NVM_Page_Footer_t footer;
01143
01144
01145 NVM_Page_Descriptor_t pageDesc;
01146
01147
01148 uint16_t checksum;
01149
01150
01151 uint8_t objectIndex;
01152
01153 uint16_t offsetAddress;
01154
01155 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
01156
01157 uint16_t index;
01158 #endif
01159
01160
01161 NVMHAL_Read(pPhysicalAddress, &header.watermark, sizeof(header.watermark));
01162 NVMHAL_Read(pPhysicalAddress + sizeof(header.watermark), &header.updateId, sizeof(header.updateId));
01163 NVMHAL_Read(pPhysicalAddress + sizeof(header.watermark) + sizeof(header.updateId), &header.version, sizeof(header.version));
01164
01165
01166 if (NVM_VERSION != header.version)
01167 {
01168 return nvmValidateResultOld;
01169 }
01170
01171
01172 pageDesc = NVM_PageGet((header.watermark & NVM_FIRST_BIT_ZERO));
01173
01174
01175 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
01176 if (nvmPageTypeWear == pageDesc.pageType)
01177 {
01178
01179
01180
01181 if ((header.watermark & NVM_FIRST_BIT_ZERO) == header.watermark)
01182 {
01183 result = nvmValidateResultOkMarked;
01184 }
01185 else
01186 {
01187
01188 result = nvmValidateResultOk;
01189 }
01190
01191
01192 if (!NVM_WearReadIndex(pPhysicalAddress, &pageDesc, &index))
01193 {
01194 result = nvmValidateResultError;
01195 }
01196 }
01197 else
01198 #endif
01199 {
01200
01201 NVMHAL_Read(pPhysicalAddress + (NVM_PAGE_SIZE - NVM_FOOTER_SIZE), &footer.checksum, sizeof(footer.checksum));
01202 NVMHAL_Read(pPhysicalAddress + (NVM_PAGE_SIZE + sizeof(checksum) - NVM_FOOTER_SIZE), &footer.watermark, sizeof(footer.watermark));
01203
01204 if (header.watermark == footer.watermark)
01205 {
01206 result = nvmValidateResultOk;
01207 }
01208 else if ((header.watermark | NVM_FIRST_BIT_ONE) == footer.watermark)
01209 {
01210 result = nvmValidateResultOkMarked;
01211 }
01212 else
01213 {
01214 result = nvmValidateResultError;
01215 }
01216
01217
01218 objectIndex = 0;
01219 offsetAddress = 0;
01220 checksum = NVM_CHECKSUM_INITIAL;
01221
01222
01223
01224
01225 while ((*pageDesc.page)[objectIndex].size != 0)
01226 {
01227 NVMHAL_Checksum(&checksum, (uint8_t *) pPhysicalAddress + NVM_HEADER_SIZE + offsetAddress, (*pageDesc.page)[objectIndex].size);
01228 offsetAddress += (*pageDesc.page)[objectIndex].size;
01229 objectIndex++;
01230 }
01231
01232 if (checksum != footer.checksum)
01233 {
01234 result = nvmValidateResultError;
01235 }
01236 }
01237
01238 return result;
01239 }
01240
01241 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
01242
01260 static uint16_t NVM_WearIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc)
01261 {
01262
01263 uint16_t wearIndex = 0;
01264
01265
01266 uint16_t checksum;
01267
01268
01269 uint16_t wearObjectSize = ((*pPageDesc->page)[0].size + NVM_CHECKSUM_LENGTH);
01270
01271
01272
01273 while (wearIndex < NVM_WEAR_CONTENT_SIZE / wearObjectSize)
01274 {
01275 NVMHAL_Read((uint8_t *)(pPhysicalAddress + NVM_HEADER_SIZE +
01276 wearIndex * wearObjectSize +
01277 (*pPageDesc->page)[0].size
01278 ),
01279 &checksum,
01280 sizeof(checksum));
01281
01282
01283
01284 if ((checksum & NVM_LAST_BIT_ZERO) != checksum)
01285 {
01286
01287 break;
01288 }
01289
01290
01291
01292 wearIndex++;
01293 }
01294
01295 return wearIndex;
01296 }
01297 #endif
01298
01299
01320 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
01321 static bool NVM_WearReadIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc, uint16_t *pIndex)
01322 {
01323 #if (NVM_FEATURE_READ_VALIDATION_ENABLED == true)
01324
01325 uint16_t checksum = NVM_CHECKSUM_INITIAL;
01326 #endif
01327
01328
01329 const uint16_t wearObjectSize = ((*pPageDesc->page)[0].size + NVM_CHECKSUM_LENGTH);
01330
01331
01332 bool validObjectFound = false;
01333
01334
01335 uint16_t readBuffer;
01336
01337
01338 *pIndex = (((uint16_t) NVM_WEAR_CONTENT_SIZE) / wearObjectSize);
01339
01340
01341 while ((*pIndex > 0) && (!validObjectFound))
01342 {
01343 (*pIndex)--;
01344
01345
01346 uint8_t *temp = pPhysicalAddress + NVM_HEADER_SIZE + (*pIndex) * wearObjectSize + (*pPageDesc->page)[0].size;
01347 NVMHAL_Read((uint8_t *) temp, &readBuffer, sizeof(readBuffer));
01348
01349 #if (NVM_FEATURE_READ_VALIDATION_ENABLED == true)
01350
01351 checksum = NVM_CHECKSUM_INITIAL;
01352 NVMHAL_Checksum(&checksum, pPhysicalAddress + NVM_HEADER_SIZE + (*pIndex) * wearObjectSize, (*pPageDesc->page)[0].size);
01353
01354
01355 if ((uint16_t)(checksum & NVM_LAST_BIT_ZERO) == readBuffer)
01356 #else
01357 if (NVM_NO_WRITE_16BIT != readBuffer)
01358 #endif
01359 {
01360 validObjectFound = true;
01361 }
01362 }
01363
01364 return validObjectFound;
01365 }
01366 #endif
01367
01368
01387 static void NVM_ChecksumAdditive(uint16_t *pChecksum, void *pBuffer, uint16_t len)
01388 {
01389 uint8_t *pointer = (uint8_t *) pBuffer;
01390 uint16_t crc = *pChecksum;
01391
01392 while(len--)
01393 {
01394 crc = (crc >> 8) | (crc << 8);
01395 crc ^= *pointer++;
01396 crc ^= (crc & 0xf0) >> 4;
01397 crc ^= (crc & 0x0f) << 12;
01398 crc ^= (crc & 0xff) << 5;
01399 }
01400
01401 *pChecksum = crc;
01402 }
01403
01404 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
01405
01414 static void NVM_StaticWearReset(void)
01415 {
01416 uint16_t i;
01417 nvmStaticWearErasesSinceReset = 0;
01418 nvmStaticWearWritesInHistory = 0;
01419
01420 for (i = 0; (NVM_PAGES_PER_WEAR_HISTORY * i) < nvmConfig->userPages; i += 1)
01421 {
01422 nvmStaticWearWriteHistory[i] = 0;
01423 }
01424 }
01425
01426
01437 static void NVM_StaticWearUpdate(uint16_t address)
01438 {
01439 if (address < nvmConfig->userPages)
01440 {
01441
01442
01443
01444 uint8_t mask = 1U << (address % NVM_PAGES_PER_WEAR_HISTORY);
01445
01446 if ((nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] & mask) == 0)
01447 {
01448
01449 nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] |= mask;
01450
01451 nvmStaticWearWritesInHistory++;
01452 }
01453
01454
01455 nvmStaticWearErasesSinceReset++;
01456
01457
01458 NVM_StaticWearCheck();
01459 }
01460 }
01461
01462
01471 static Ecode_t NVM_StaticWearCheck(void)
01472 {
01473
01474 if (!nvmStaticWearWorking)
01475 {
01476 nvmStaticWearWorking = true;
01477 while (nvmStaticWearErasesSinceReset / nvmStaticWearWritesInHistory > NVM_STATIC_WEAR_THRESHOLD)
01478 {
01479
01480 if (nvmStaticWearWritesInHistory >= nvmConfig->userPages)
01481 {
01482 NVM_StaticWearReset();
01483 break;
01484 }
01485
01486
01487 uint16_t address = 0;
01488 uint8_t mask = 1U << (address % NVM_PAGES_PER_WEAR_HISTORY);
01489 while ((nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] & mask) != 0)
01490 {
01491 address++;
01492 mask = 1U << (address % NVM_PAGES_PER_WEAR_HISTORY);
01493 }
01494
01495
01496 if (nvmPageTypeWear == NVM_PageGet(address).pageType)
01497 {
01498
01499 nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] |= mask;
01500
01501 nvmStaticWearWritesInHistory++;
01502 }
01503 else
01504 {
01505
01506
01507
01508
01509 NVM_RELEASE_WRITE_LOCK
01510
01511 NVM_Write(address, NVM_WRITE_NONE_CMD);
01512
01513
01514 NVM_ACQUIRE_WRITE_LOCK
01515 }
01516 }
01517 nvmStaticWearWorking = false;
01518 }
01519
01520 return ECODE_EMDRV_NVM_OK;
01521 }
01522
01523 #endif
01524
01528