00001
00053 #include <stdbool.h>
00054 #include "nvm.h"
00055 #include "nvm_hal.h"
00056
00057
00062
00067
00068
00069
00070
00075 #define NVM_VERSION 0x2U
00076
00077
00078 #define NVM_CONTENT_SIZE (NVM_PAGE_SIZE - (NVM_HEADER_SIZE + NVM_FOOTER_SIZE))
00079 #define NVM_WEAR_CONTENT_SIZE (NVM_PAGE_SIZE - NVM_HEADER_SIZE)
00080
00081
00082 #define NVM_PAGE_EMPTY_VALUE 0xffffU
00083 #define NVM_NO_PAGE_RETURNED 0xffffffffUL
00084 #define NVM_NO_WRITE_16BIT 0xffffU
00085 #define NVM_NO_WRITE_32BIT 0xffffffffUL
00086 #define NVM_HIGHEST_32BIT 0xffffffffUL
00087 #define NVM_FLIP_FIRST_BIT_OF_32_WHEN_WRITE 0xffff7fffUL
00088 #define NVM_FIRST_BIT_ONE 0x8000U
00089 #define NVM_FIRST_BIT_ZERO 0x7fffU
00090 #define NVM_LAST_BIT_ZERO 0xfffeU
00091
00092 #define NVM_CHECKSUM_INITIAL 0xffffU
00093 #define NVM_CHECKSUM_LENGTH 2U
00094
00095 #define NVM_PAGES_PER_WEAR_HISTORY 8U
00096
00097
00098
00099
00100 #ifndef NVM_ACQUIRE_WRITE_LOCK
00101 #define NVM_ACQUIRE_WRITE_LOCK
00102 #endif
00103
00104 #ifndef NVM_RELEASE_WRITE_LOCK
00105 #define NVM_RELEASE_WRITE_LOCK
00106 #endif
00107
00110
00111
00112
00113
00116 typedef enum
00117 {
00118 nvmValidateResultOk = 0,
00119 nvmValidateResultOkMarked = 1,
00120 nvmValidateResultOld = 2,
00121 nvmValidateResultError = 3
00122 } NVM_ValidateResult_t;
00123
00126 typedef struct
00127 {
00128 uint16_t watermark;
00129 uint32_t updateId;
00130 uint16_t version;
00131 } NVM_Page_Header_t;
00132
00134 #define NVM_HEADER_SIZE (2*sizeof(uint16_t)+sizeof(uint32_t))
00135
00138 typedef struct
00139 {
00140 uint16_t checksum;
00141 uint16_t watermark;
00142 } NVM_Page_Footer_t;
00143
00145 #define NVM_FOOTER_SIZE (2*sizeof(uint16_t))
00146
00149
00150
00151
00152
00156 static NVM_Config_t const *nvmConfig;
00157
00158 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
00159
00160
00161
00162
00163 static uint8_t nvmStaticWearWriteHistory[(NVM_MAX_NUMBER_OF_PAGES+(NVM_PAGES_PER_WEAR_HISTORY-1))/NVM_PAGES_PER_WEAR_HISTORY];
00164
00165
00166 static uint16_t nvmStaticWearWritesInHistory;
00167
00168
00169 static uint16_t nvmStaticWearErasesSinceReset;
00170
00171
00172 static bool nvmStaticWearWorking = false;
00173 #endif
00174
00177
00178
00179
00180
00183 static uint8_t* NVM_PageFind(uint16_t pageId);
00184 static uint8_t* NVM_ScratchPageFindBest(void);
00185 static NVM_Result_t NVM_PageErase(uint8_t *pPhysicalAddress);
00186 static NVM_Page_Descriptor_t NVM_PageGet(uint16_t pageId);
00187 static NVM_ValidateResult_t NVM_PageValidate(uint8_t *pPhysicalAddress);
00188
00189 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00190 static uint16_t NVM_WearIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc);
00191 static bool NVM_WearReadIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc, uint16_t *pIndex);
00192 #endif
00193
00194 static void NVM_ChecksumAdditive(uint16_t *pChecksum, void *pBuffer, uint16_t len);
00195
00196 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
00197 static void NVM_StaticWearReset(void);
00198 static void NVM_StaticWearUpdate(uint16_t address);
00199 static NVM_Result_t NVM_StaticWearCheck(void);
00200 #endif
00201
00203
00204
00205
00206
00207
00234 NVM_Result_t NVM_Init(NVM_Config_t const *config)
00235 {
00236 uint16_t page;
00237
00238 NVM_Result_t result = nvmResultErrorInitial;
00239
00240
00241 uint8_t *pPhysicalAddress = (uint8_t *)(config->nvmArea);
00242
00243 uint8_t *pDuplicatePhysicalAddress;
00244
00245
00246 uint16_t logicalAddress;
00247
00248 uint16_t duplicateLogicalAddress;
00249
00250
00251 NVM_ValidateResult_t validationResult;
00252
00253 NVM_Result_t eraseResult;
00254
00255
00256 if( (config->pages <= config->userPages) || (config->pages > NVM_MAX_NUMBER_OF_PAGES) )
00257 return nvmResultError;
00258
00259
00260 {
00261 uint16_t pageIdx = 0, obj = 0, sum = 0;
00262 const NVM_Page_Descriptor_t *current_page;
00263
00264 for(pageIdx=0;pageIdx < config->userPages; pageIdx++)
00265 {
00266 sum = 0;
00267 obj = 0;
00268 current_page = &((*(config->nvmPages))[pageIdx]);
00269
00270 while( (*(current_page->page))[obj].location != 0)
00271 sum += (*(current_page->page))[obj++].size;
00272
00273 if(current_page->pageType == nvmPageTypeNormal)
00274 {
00275 if( sum > NVM_CONTENT_SIZE )
00276 {
00277 return nvmResultError;
00278 }
00279 }
00280 else
00281 {
00282 if(current_page->pageType == nvmPageTypeWear)
00283 {
00284 if( (sum+NVM_CHECKSUM_LENGTH) > NVM_WEAR_CONTENT_SIZE )
00285 {
00286 return nvmResultError;
00287 }
00288 } else
00289 {
00290 return nvmResultError;
00291 }
00292 }
00293 }
00294 }
00295
00296 nvmConfig = config;
00297
00298
00299 NVM_ACQUIRE_WRITE_LOCK
00300
00301
00302 NVMHAL_Init();
00303
00304 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
00305
00306 NVM_StaticWearReset();
00307 #endif
00308
00309
00310 for (page = 0; page < nvmConfig->pages; ++page)
00311 {
00312
00313
00314 NVMHAL_Read(pPhysicalAddress, &logicalAddress, sizeof(logicalAddress));
00315 if (NVM_PAGE_EMPTY_VALUE != logicalAddress)
00316 {
00317
00318 validationResult = NVM_PageValidate(pPhysicalAddress);
00319
00320
00321 if (nvmValidateResultOk == validationResult)
00322 {
00323
00324
00325 if (nvmResultErrorInitial == result)
00326 {
00327 result = nvmResultOk;
00328 }
00329 }
00330 else if (nvmValidateResultOkMarked == validationResult)
00331 {
00332
00333
00334
00335
00336
00337 pDuplicatePhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
00338 for (page = 0; (NVM_PAGE_EMPTY_VALUE != logicalAddress) && (page < nvmConfig->pages);
00339 ++page)
00340 {
00341 NVMHAL_Read(pDuplicatePhysicalAddress, &duplicateLogicalAddress, sizeof(duplicateLogicalAddress));
00342
00343 if ((pDuplicatePhysicalAddress != pPhysicalAddress) && ((logicalAddress | NVM_FIRST_BIT_ONE) == duplicateLogicalAddress))
00344 {
00345
00346
00347 validationResult = NVM_PageValidate(pDuplicatePhysicalAddress);
00348
00349 if (nvmValidateResultOk == validationResult)
00350 {
00351
00352 eraseResult = NVM_PageErase(pPhysicalAddress);
00353 }
00354 else
00355 {
00356
00357 eraseResult = NVM_PageErase(pDuplicatePhysicalAddress);
00358 }
00359
00360
00361 if (nvmResultOk != eraseResult)
00362 {
00363 result = nvmResultError;
00364 }
00365 }
00366
00367
00368 pDuplicatePhysicalAddress += NVM_PAGE_SIZE;
00369 }
00370
00371
00372
00373 if (nvmResultErrorInitial == result)
00374 {
00375 result = nvmResultOk;
00376 }
00377 }
00378 else
00379 {
00380
00381 result = nvmResultError;
00382 }
00383 }
00384
00385
00386 pPhysicalAddress += NVM_PAGE_SIZE;
00387 }
00388
00389
00390 if (nvmResultErrorInitial == result)
00391 {
00392 result = nvmResultNoPages;
00393 }
00394
00395
00396 NVM_RELEASE_WRITE_LOCK
00397
00398 return result;
00399 }
00400
00401
00419 NVM_Result_t NVM_Erase(uint32_t erasureCount)
00420 {
00421 uint16_t page;
00422
00423 NVM_Result_t result = nvmResultErrorInitial;
00424
00425
00426 uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
00427
00428
00429 uint32_t tempErasureCount = erasureCount;
00430
00431
00432
00433 NVM_ACQUIRE_WRITE_LOCK
00434
00435
00436
00437 for (page = 0;
00438 (page < nvmConfig->pages) && ((nvmResultOk == result) || (nvmResultErrorInitial == result));
00439 ++page)
00440 {
00441
00442
00443 if (NVM_ERASE_RETAINCOUNT == erasureCount)
00444 {
00445
00446 NVMHAL_Read(pPhysicalAddress + 2, &tempErasureCount, sizeof(tempErasureCount));
00447 }
00448
00449
00450 result = NVMHAL_PageErase(pPhysicalAddress);
00451
00452
00453 if (nvmResultOk == result)
00454 {
00455 result = NVMHAL_Write(pPhysicalAddress + 2, &tempErasureCount, sizeof(tempErasureCount));
00456 }
00457
00458
00459 pPhysicalAddress += NVM_PAGE_SIZE;
00460 }
00461
00462
00463 NVM_RELEASE_WRITE_LOCK
00464
00465 return result;
00466 }
00467
00468
00493 NVM_Result_t NVM_Write(uint16_t pageId, uint8_t objectId)
00494 {
00495
00496 NVM_Result_t result = nvmResultErrorInitial;
00497
00498
00499 uint16_t watermark = pageId | NVM_FIRST_BIT_ONE;
00500
00501 const uint32_t flipWatermark = NVM_FLIP_FIRST_BIT_OF_32_WHEN_WRITE;
00502
00503
00504 NVM_Page_Descriptor_t pageDesc;
00505
00506
00507
00508 NVM_Page_Header_t header;
00509
00510
00511 uint16_t checksum = NVM_CHECKSUM_INITIAL;
00512
00513
00514 uint8_t *pOldPhysicalAddress = (uint8_t *) NVM_NO_PAGE_RETURNED;
00515 uint8_t *pNewPhysicalAddress = (uint8_t *) NVM_NO_PAGE_RETURNED;
00516
00517
00518 uint16_t offsetAddress;
00519
00520 uint8_t copyBuffer;
00521
00522 uint8_t objectIndex;
00523
00524 uint16_t copyLength;
00525
00526
00527
00528 bool wearWrite = false;
00529
00530 #if (NVM_FEATURE_WRITE_NECESSARY_CHECK_ENABLED == true)
00531
00532 bool rewriteNeeded;
00533 #endif
00534
00535 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00536
00537 uint16_t wearChecksum;
00538
00539 uint16_t wearObjectSize;
00540
00541 uint16_t wearIndex;
00542
00543 #if (NVM_FEATURE_WRITE_VALIDATION_ENABLED == true)
00544
00545 uint16_t wearIndexNew;
00546 #endif
00547 #endif
00548
00549
00550 NVM_ACQUIRE_WRITE_LOCK
00551
00552
00553 pOldPhysicalAddress = NVM_PageFind(pageId);
00554
00555
00556 pageDesc = NVM_PageGet(pageId);
00557
00558 #if (NVM_FEATURE_WRITE_NECESSARY_CHECK_ENABLED == true)
00559
00560
00561
00562
00563 if (((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
00564 && (nvmPageTypeNormal == pageDesc.pageType)
00565 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
00566 && !nvmStaticWearWorking
00567 #endif
00568
00569 )
00570 {
00571 rewriteNeeded = false;
00572 objectIndex = 0;
00573 offsetAddress = 0;
00574
00575
00576
00577 while (((*pageDesc.page)[objectIndex].size != 0) && !rewriteNeeded)
00578 {
00579
00580
00581 if ((NVM_WRITE_ALL_CMD == objectId) ||
00582 ((*pageDesc.page)[objectIndex].objectId == objectId))
00583 {
00584
00585
00586 copyLength = (*pageDesc.page)[objectIndex].size;
00587
00588
00589 while (copyLength != 0)
00590 {
00591
00592 NVMHAL_Read(pOldPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00593 ©Buffer,
00594 sizeof(copyBuffer));
00595
00596
00597 if (*(uint8_t *)((*pageDesc.page)[objectIndex].location + offsetAddress) != copyBuffer)
00598 {
00599 rewriteNeeded = true;
00600 break;
00601 }
00602
00603
00604 offsetAddress += sizeof(copyBuffer);
00605 copyLength -= sizeof(copyBuffer);
00606 }
00607 }
00608 else
00609 {
00610
00611 offsetAddress += (*pageDesc.page)[objectIndex].size;
00612 }
00613
00614
00615 objectIndex++;
00616 }
00617
00618 if (!rewriteNeeded)
00619 {
00620
00621 NVM_RELEASE_WRITE_LOCK
00622
00623 return nvmResultOk;
00624 }
00625 }
00626 #endif
00627
00628
00629
00630 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00631
00632
00633
00634
00635 if (nvmPageTypeWear == pageDesc.pageType)
00636 {
00637
00638
00639
00640
00641 wearChecksum = NVM_CHECKSUM_INITIAL;
00642 NVM_ChecksumAdditive(&wearChecksum, (*pageDesc.page)[0].location, (*pageDesc.page)[0].size);
00643 wearChecksum &= NVM_LAST_BIT_ZERO;
00644
00645
00646 if ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
00647 {
00648
00649 wearIndex = NVM_WearIndex(pOldPhysicalAddress, &pageDesc);
00650 wearObjectSize = (*pageDesc.page)[0].size + NVM_CHECKSUM_LENGTH;
00651
00652
00653 if (wearIndex < ((uint16_t) NVM_WEAR_CONTENT_SIZE) / wearObjectSize)
00654 {
00655 result = NVMHAL_Write(pOldPhysicalAddress + NVM_HEADER_SIZE + wearIndex * wearObjectSize,
00656 (*pageDesc.page)[0].location,
00657 (*pageDesc.page)[0].size);
00658 result = NVMHAL_Write(pOldPhysicalAddress + NVM_HEADER_SIZE + wearIndex * wearObjectSize + (*pageDesc.page)[0].size,
00659 &wearChecksum,
00660 sizeof(wearChecksum));
00661
00662
00663 wearWrite = true;
00664
00665 #if (NVM_FEATURE_WRITE_VALIDATION_ENABLED == true)
00666
00667
00668 if ((!NVM_WearReadIndex(pOldPhysicalAddress, &pageDesc, &wearIndexNew)) ||
00669 (wearIndexNew != wearIndex))
00670 {
00671 result = nvmResultError;
00672 }
00673 #endif
00674 }
00675 }
00676 }
00677 #endif
00678
00679 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00680
00681 if (!wearWrite)
00682 {
00683 #endif
00684
00685 if ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
00686 {
00687 result = NVMHAL_Write(pOldPhysicalAddress, &flipWatermark, 4);
00688
00689 if (nvmResultOk != result)
00690 {
00691
00692 NVM_RELEASE_WRITE_LOCK
00693 return result;
00694 }
00695 }
00696
00697
00698 pNewPhysicalAddress = NVM_ScratchPageFindBest();
00699
00700 if ((uint8_t*) NVM_NO_PAGE_RETURNED == pNewPhysicalAddress)
00701 {
00702
00703 NVM_RELEASE_WRITE_LOCK
00704 return nvmResultError;
00705 }
00706
00707
00708 header.watermark = watermark;
00709 header.updateId = NVM_NO_WRITE_32BIT;
00710 header.version = NVM_VERSION;
00711
00712
00713 result = NVMHAL_Write(pNewPhysicalAddress, &header.watermark, sizeof(header.watermark));
00714 result = NVMHAL_Write(pNewPhysicalAddress + sizeof(header.watermark), &header.updateId, sizeof(header.updateId));
00715 result = NVMHAL_Write(pNewPhysicalAddress + sizeof(header.watermark)+ + sizeof(header.updateId), &header.version, sizeof(header.version));
00716
00717
00718 offsetAddress = 0;
00719
00720 objectIndex = 0;
00721
00722
00723
00724 while (((*pageDesc.page)[objectIndex].size != 0) && (nvmResultOk == result))
00725 {
00726
00727
00728 if ((NVM_WRITE_ALL_CMD == objectId) ||
00729 ((*pageDesc.page)[objectIndex].objectId == objectId))
00730 {
00731
00732 result = NVMHAL_Write(pNewPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00733 (*pageDesc.page)[objectIndex].location,
00734 (*pageDesc.page)[objectIndex].size);
00735 offsetAddress += (*pageDesc.page)[objectIndex].size;
00736
00737 NVM_ChecksumAdditive(&checksum, (*pageDesc.page)[objectIndex].location, (*pageDesc.page)[objectIndex].size);
00738 }
00739 else
00740 {
00741
00742 if ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
00743 {
00744 NVM_ChecksumAdditive(&checksum, pOldPhysicalAddress + offsetAddress + NVM_HEADER_SIZE, (*pageDesc.page)[objectIndex].size);
00745
00746 copyLength = (*pageDesc.page)[objectIndex].size;
00747
00748 while ((copyLength != 0) && (nvmResultOk == result))
00749 {
00750
00751 NVMHAL_Read(pOldPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00752 ©Buffer,
00753 sizeof(copyBuffer));
00754 result = NVMHAL_Write(pNewPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00755 ©Buffer,
00756 sizeof(copyBuffer));
00757
00758 offsetAddress += sizeof(copyBuffer);
00759 copyLength -= sizeof(copyBuffer);
00760 }
00761 }
00762 }
00763
00764 objectIndex++;
00765 }
00766
00767
00768 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00769 if (nvmPageTypeWear == pageDesc.pageType)
00770 {
00771 result = NVMHAL_Write(pNewPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00772 &wearChecksum,
00773 sizeof(wearChecksum));
00774 }
00775
00776 else
00777 {
00778 #endif
00779 if (nvmResultOk == result)
00780 {
00781
00782 result = NVMHAL_Write(pNewPhysicalAddress + (NVM_PAGE_SIZE - NVM_FOOTER_SIZE), &checksum, sizeof(checksum));
00783
00784 result = NVMHAL_Write(pNewPhysicalAddress + (NVM_PAGE_SIZE + sizeof(checksum) - NVM_FOOTER_SIZE), &watermark, sizeof(watermark));
00785 }
00786
00787 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00788 }
00789 #endif
00790
00791 #if (NVM_FEATURE_WRITE_VALIDATION_ENABLED == true)
00792
00793 if (nvmValidateResultOk != NVM_PageValidate(pNewPhysicalAddress))
00794 {
00795 result = nvmResultError;
00796 }
00797 #endif
00798
00799 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00800 }
00801 #endif
00802
00803
00804 if ((!wearWrite) &&
00805 ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress))
00806 {
00807 if (nvmResultOk == result)
00808 {
00809 result = NVM_PageErase(pOldPhysicalAddress);
00810 }
00811 else
00812 {
00813 NVM_PageErase(pNewPhysicalAddress);
00814 }
00815 }
00816
00817
00818 NVM_RELEASE_WRITE_LOCK
00819
00820 return result;
00821 }
00822
00823
00843 NVM_Result_t NVM_Read(uint16_t pageId, uint8_t objectId)
00844 {
00845 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00846
00847 uint16_t wearIndex;
00848 #endif
00849
00850
00851 uint8_t *pPhysicalAddress;
00852
00853
00854 NVM_Page_Descriptor_t pageDesc;
00855
00856
00857 uint8_t objectIndex;
00858
00859 uint16_t offsetAddress;
00860
00861
00862
00863 NVM_ACQUIRE_WRITE_LOCK
00864
00865
00866 pPhysicalAddress = NVM_PageFind(pageId);
00867
00868
00869 if ((uint8_t*) NVM_NO_PAGE_RETURNED == pPhysicalAddress)
00870 {
00871
00872 NVM_RELEASE_WRITE_LOCK
00873 return nvmResultNoPage;
00874 }
00875
00876
00877 pageDesc = NVM_PageGet(pageId);
00878
00879 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
00880
00881
00882 if (nvmPageTypeWear == pageDesc.pageType)
00883 {
00884
00885 if (NVM_WearReadIndex(pPhysicalAddress, &pageDesc, &wearIndex))
00886 {
00887 NVMHAL_Read(pPhysicalAddress + NVM_HEADER_SIZE +
00888 wearIndex * ((*pageDesc.page)[0].size + NVM_CHECKSUM_LENGTH),
00889 (*pageDesc.page)[0].location,
00890 (*pageDesc.page)[0].size);
00891 }
00892 else
00893 {
00894
00895
00896 NVM_RELEASE_WRITE_LOCK
00897 return nvmResultDataInvalid;
00898 }
00899 }
00900 else
00901 #endif
00902 {
00903
00904 objectIndex = 0;
00905 offsetAddress = 0;
00906
00907 #if (NVM_FEATURE_READ_VALIDATION_ENABLED == true)
00908 if (nvmValidateResultError == NVM_PageValidate(pPhysicalAddress))
00909 {
00910
00911 NVM_RELEASE_WRITE_LOCK
00912 return nvmResultDataInvalid;
00913 }
00914 #endif
00915
00916
00917
00918 while ((*pageDesc.page)[objectIndex].size != 0)
00919 {
00920
00921 if ((NVM_READ_ALL_CMD == objectId) || ((*pageDesc.page)[objectIndex].objectId == objectId))
00922 {
00923 NVMHAL_Read(pPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
00924 (*pageDesc.page)[objectIndex].location,
00925 (*pageDesc.page)[objectIndex].size);
00926 }
00927
00928 offsetAddress += (*pageDesc.page)[objectIndex].size;
00929 objectIndex++;
00930 }
00931 }
00932
00933
00934 NVM_RELEASE_WRITE_LOCK
00935
00936 return nvmResultOk;
00937 }
00938
00939
00950 #if (NVM_FEATURE_WEARLEVELGET_ENABLED == true)
00951 uint32_t NVM_WearLevelGet(void)
00952 {
00953 uint16_t page;
00954
00955 uint32_t updateId;
00956
00957 uint32_t worstUpdateId = 0;
00958
00959
00960 uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
00961
00962
00963 for (page = 0; page < nvmConfig->pages; ++page)
00964 {
00965
00966 NVMHAL_Read(pPhysicalAddress + 2, &updateId, sizeof(updateId));
00967 if (updateId > worstUpdateId)
00968 {
00969 worstUpdateId = updateId;
00970 }
00971
00972
00973 pPhysicalAddress += NVM_PAGE_SIZE;
00974 }
00975
00976 return worstUpdateId;
00977 }
00978 #endif
00979
00980
00981
00982
00983
00986
01001 static uint8_t* NVM_PageFind(uint16_t pageId)
01002 {
01003 uint16_t page;
01004
01005 uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
01006
01007 uint16_t logicalAddress;
01008
01009
01010 for (page = 0; page < nvmConfig->pages; ++page)
01011 {
01012
01013
01014 NVMHAL_Read(pPhysicalAddress, &logicalAddress, sizeof(logicalAddress));
01015 if (((pageId | NVM_FIRST_BIT_ONE) == logicalAddress) || (pageId == logicalAddress))
01016 {
01017 return pPhysicalAddress;
01018 }
01019
01020
01021 pPhysicalAddress += NVM_PAGE_SIZE;
01022 }
01023
01024
01025 return (uint8_t *) NVM_NO_PAGE_RETURNED;
01026 }
01027
01028
01040 static uint8_t* NVM_ScratchPageFindBest(void)
01041 {
01042 uint16_t page;
01043
01044 uint8_t *pPhysicalPage = (uint8_t *) NVM_NO_PAGE_RETURNED;
01045
01046
01047 uint32_t updateId = NVM_HIGHEST_32BIT;
01048
01049 uint32_t bestUpdateId = NVM_HIGHEST_32BIT;
01050
01051
01052 uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
01053
01054 uint16_t logicalAddress;
01055
01056
01057 for (page = 0; page < nvmConfig->pages; ++page)
01058 {
01059
01060 NVMHAL_Read(pPhysicalAddress, &logicalAddress, sizeof(logicalAddress));
01061 if ((uint16_t) NVM_PAGE_EMPTY_VALUE == logicalAddress)
01062 {
01063
01064 NVMHAL_Read(pPhysicalAddress + 2, &updateId, sizeof(updateId));
01065 if (updateId < bestUpdateId)
01066 {
01067 bestUpdateId = updateId;
01068 pPhysicalPage = pPhysicalAddress;
01069 }
01070 }
01071
01072
01073 pPhysicalAddress += NVM_PAGE_SIZE;
01074 }
01075
01076
01077 return pPhysicalPage;
01078 }
01079
01080
01094 static NVM_Result_t NVM_PageErase(uint8_t *pPhysicalAddress)
01095 {
01096 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
01097
01098 uint16_t logicalAddress;
01099 #endif
01100
01101
01102 uint32_t updateId;
01103 NVMHAL_Read(pPhysicalAddress + 2, &updateId, sizeof(updateId));
01104
01105 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
01106
01107 NVMHAL_Read(pPhysicalAddress, &logicalAddress, sizeof(logicalAddress));
01108
01109
01110 if (logicalAddress != NVM_PAGE_EMPTY_VALUE)
01111 {
01112
01113 logicalAddress = logicalAddress & NVM_FIRST_BIT_ZERO;
01114 NVM_StaticWearUpdate(logicalAddress);
01115 }
01116 #endif
01117
01118
01119 NVMHAL_PageErase(pPhysicalAddress);
01120
01121
01122 updateId++;
01123
01124
01125 return NVMHAL_Write(pPhysicalAddress + 2, &updateId, sizeof(updateId));
01126 }
01127
01128
01147 static NVM_Page_Descriptor_t NVM_PageGet(uint16_t pageId)
01148 {
01149 uint8_t pageIndex;
01150 static const NVM_Page_Descriptor_t nullPage = { (uint8_t) 0, 0, (NVM_Page_Type_t) 0 };
01151
01152
01153 for (pageIndex = 0; pageIndex < nvmConfig->userPages; ++pageIndex)
01154 {
01155
01156 if ( (*(nvmConfig->nvmPages))[pageIndex].pageId == pageId)
01157 {
01158 return (*(nvmConfig->nvmPages))[pageIndex];
01159 }
01160 }
01161
01162
01163 return nullPage;
01164 }
01165
01166
01187 static NVM_ValidateResult_t NVM_PageValidate(uint8_t *pPhysicalAddress)
01188 {
01189
01190 NVM_ValidateResult_t result;
01191
01192
01193 NVM_Page_Header_t header;
01194 NVM_Page_Footer_t footer;
01195
01196
01197 NVM_Page_Descriptor_t pageDesc;
01198
01199
01200 uint16_t checksum;
01201
01202
01203 uint8_t objectIndex;
01204
01205 uint16_t offsetAddress;
01206
01207 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
01208
01209 uint16_t index;
01210 #endif
01211
01212
01213 NVMHAL_Read(pPhysicalAddress, &header.watermark, sizeof(header.watermark));
01214 NVMHAL_Read(pPhysicalAddress + sizeof(header.watermark), &header.updateId, sizeof(header.updateId));
01215 NVMHAL_Read(pPhysicalAddress + sizeof(header.watermark) + sizeof(header.updateId), &header.version, sizeof(header.version));
01216
01217
01218 if (NVM_VERSION != header.version)
01219 {
01220 return nvmValidateResultOld;
01221 }
01222
01223
01224 pageDesc = NVM_PageGet((header.watermark & NVM_FIRST_BIT_ZERO));
01225
01226
01227 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
01228 if (nvmPageTypeWear == pageDesc.pageType)
01229 {
01230
01231
01232
01233 if ((header.watermark & NVM_FIRST_BIT_ZERO) == header.watermark)
01234 {
01235 result = nvmValidateResultOkMarked;
01236 }
01237 else
01238 {
01239
01240 result = nvmValidateResultOk;
01241 }
01242
01243
01244 if (!NVM_WearReadIndex(pPhysicalAddress, &pageDesc, &index))
01245 {
01246 result = nvmValidateResultError;
01247 }
01248 }
01249 else
01250 #endif
01251 {
01252
01253 NVMHAL_Read(pPhysicalAddress + (NVM_PAGE_SIZE - NVM_FOOTER_SIZE), &footer.checksum, sizeof(footer.checksum));
01254 NVMHAL_Read(pPhysicalAddress + (NVM_PAGE_SIZE + sizeof(checksum) - NVM_FOOTER_SIZE), &footer.watermark, sizeof(footer.watermark));
01255
01256 if (header.watermark == footer.watermark)
01257 {
01258 result = nvmValidateResultOk;
01259 }
01260 else if ((header.watermark | NVM_FIRST_BIT_ONE) == footer.watermark)
01261 {
01262 result = nvmValidateResultOkMarked;
01263 }
01264 else
01265 {
01266 result = nvmValidateResultError;
01267 }
01268
01269
01270 objectIndex = 0;
01271 offsetAddress = 0;
01272 checksum = NVM_CHECKSUM_INITIAL;
01273
01274
01275
01276
01277 while ((*pageDesc.page)[objectIndex].size != 0)
01278 {
01279 NVMHAL_Checksum(&checksum, (uint8_t *) pPhysicalAddress + NVM_HEADER_SIZE + offsetAddress, (*pageDesc.page)[objectIndex].size);
01280 offsetAddress += (*pageDesc.page)[objectIndex].size;
01281 objectIndex++;
01282 }
01283
01284 if (checksum != footer.checksum)
01285 {
01286 result = nvmValidateResultError;
01287 }
01288 }
01289
01290 return result;
01291 }
01292
01293 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
01294
01312 static uint16_t NVM_WearIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc)
01313 {
01314
01315 uint16_t wearIndex = 0;
01316
01317
01318 uint16_t checksum;
01319
01320
01321 uint16_t wearObjectSize = ((*pPageDesc->page)[0].size + NVM_CHECKSUM_LENGTH);
01322
01323
01324
01325 while (wearIndex < NVM_WEAR_CONTENT_SIZE / wearObjectSize)
01326 {
01327 NVMHAL_Read((uint8_t *)(pPhysicalAddress + NVM_HEADER_SIZE +
01328 wearIndex * wearObjectSize +
01329 (*pPageDesc->page)[0].size
01330 ),
01331 &checksum,
01332 sizeof(checksum));
01333
01334
01335
01336 if ((checksum & NVM_LAST_BIT_ZERO) != checksum)
01337 {
01338
01339 break;
01340 }
01341
01342
01343
01344 wearIndex++;
01345 }
01346
01347 return wearIndex;
01348 }
01349 #endif
01350
01351
01372 #if (NVM_FEATURE_WEAR_PAGES_ENABLED == true)
01373 static bool NVM_WearReadIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc, uint16_t *pIndex)
01374 {
01375 #if (NVM_FEATURE_READ_VALIDATION_ENABLED == true)
01376
01377 uint16_t checksum = NVM_CHECKSUM_INITIAL;
01378 #endif
01379
01380
01381 const uint16_t wearObjectSize = ((*pPageDesc->page)[0].size + NVM_CHECKSUM_LENGTH);
01382
01383
01384 bool validObjectFound = false;
01385
01386
01387 uint16_t readBuffer;
01388
01389
01390 *pIndex = (((uint16_t) NVM_WEAR_CONTENT_SIZE) / wearObjectSize);
01391
01392
01393 while ((*pIndex > 0) && (!validObjectFound))
01394 {
01395 (*pIndex)--;
01396
01397
01398 uint8_t *temp = pPhysicalAddress + NVM_HEADER_SIZE + (*pIndex) * wearObjectSize + (*pPageDesc->page)[0].size;
01399 NVMHAL_Read((uint8_t *) temp, &readBuffer, sizeof(readBuffer));
01400
01401 #if (NVM_FEATURE_READ_VALIDATION_ENABLED == true)
01402
01403 checksum = NVM_CHECKSUM_INITIAL;
01404 NVMHAL_Checksum(&checksum, pPhysicalAddress + NVM_HEADER_SIZE + (*pIndex) * wearObjectSize, (*pPageDesc->page)[0].size);
01405
01406
01407 if ((uint16_t)(checksum & NVM_LAST_BIT_ZERO) == readBuffer)
01408 #else
01409 if (NVM_NO_WRITE_16BIT != readBuffer)
01410 #endif
01411 {
01412 validObjectFound = true;
01413 }
01414 }
01415
01416 return validObjectFound;
01417 }
01418 #endif
01419
01420
01439 static void NVM_ChecksumAdditive(uint16_t *pChecksum, void *pBuffer, uint16_t len)
01440 {
01441 uint8_t *pointer = (uint8_t *) pBuffer;
01442 uint16_t crc = *pChecksum;
01443
01444 while(len--)
01445 {
01446 crc = (crc >> 8) | (crc << 8);
01447 crc ^= *pointer++;
01448 crc ^= (crc & 0xf0) >> 4;
01449 crc ^= (crc & 0x0f) << 12;
01450 crc ^= (crc & 0xff) << 5;
01451 }
01452
01453 *pChecksum = crc;
01454 }
01455
01456 #if (NVM_FEATURE_STATIC_WEAR_ENABLED == true)
01457
01466 static void NVM_StaticWearReset(void)
01467 {
01468 uint16_t i;
01469 nvmStaticWearErasesSinceReset = 0;
01470 nvmStaticWearWritesInHistory = 0;
01471
01472 for (i = 0; (NVM_PAGES_PER_WEAR_HISTORY * i) < nvmConfig->userPages; i += 1)
01473 {
01474 nvmStaticWearWriteHistory[i] = 0;
01475 }
01476 }
01477
01478
01489 static void NVM_StaticWearUpdate(uint16_t address)
01490 {
01491 if (address < nvmConfig->userPages)
01492 {
01493
01494
01495
01496 uint8_t mask = 1U << (address % NVM_PAGES_PER_WEAR_HISTORY);
01497
01498 if ((nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] & mask) == 0)
01499 {
01500
01501 nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] |= mask;
01502
01503 nvmStaticWearWritesInHistory++;
01504 }
01505
01506
01507 nvmStaticWearErasesSinceReset++;
01508
01509
01510 NVM_StaticWearCheck();
01511 }
01512 }
01513
01514
01523 static NVM_Result_t NVM_StaticWearCheck(void)
01524 {
01525
01526 if (!nvmStaticWearWorking)
01527 {
01528 nvmStaticWearWorking = true;
01529 while (nvmStaticWearErasesSinceReset / nvmStaticWearWritesInHistory > NVM_STATIC_WEAR_THRESHOLD)
01530 {
01531
01532 if (nvmStaticWearWritesInHistory >= nvmConfig->userPages)
01533 {
01534 NVM_StaticWearReset();
01535 break;
01536 }
01537
01538
01539 uint16_t address = 0;
01540 uint8_t mask = 1U << (address % NVM_PAGES_PER_WEAR_HISTORY);
01541 while ((nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] & mask) != 0)
01542 {
01543 address++;
01544 mask = 1U << (address % NVM_PAGES_PER_WEAR_HISTORY);
01545 }
01546
01547
01548 if (nvmPageTypeWear == NVM_PageGet(address).pageType)
01549 {
01550
01551 nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] |= mask;
01552
01553 nvmStaticWearWritesInHistory++;
01554 }
01555 else
01556 {
01557
01558
01559
01560
01561 NVM_RELEASE_WRITE_LOCK
01562
01563 NVM_Write(address, NVM_WRITE_NONE_CMD);
01564
01565
01566 NVM_ACQUIRE_WRITE_LOCK
01567 }
01568 }
01569 nvmStaticWearWorking = false;
01570 }
01571
01572 return nvmResultOk;
01573 }
01574
01575 #endif
01576