28 #define NVM_VERSION                            0x3U 
   31 #define NVM_CONTENT_SIZE         (NVM_PAGE_SIZE - (NVM_HEADER_SIZE + NVM_FOOTER_SIZE)) 
   32 #define NVM_WEAR_CONTENT_SIZE    (NVM_PAGE_SIZE - NVM_HEADER_SIZE) 
   34 #define NVM_PAGE_EMPTY_VALUE                   0xffffU 
   35 #define NVM_NO_PAGE_RETURNED                   0xffffffffUL 
   36 #define NVM_NO_WRITE_16BIT                     0xffffU 
   37 #define NVM_NO_WRITE_32BIT                     0xffffffffUL 
   38 #define NVM_HIGHEST_32BIT                      0xffffffffUL 
   39 #define NVM_FLIP_FIRST_BIT_OF_32_WHEN_WRITE    0xffff7fffUL 
   40 #define NVM_FIRST_BIT_ONE                      0x8000U 
   41 #define NVM_FIRST_BIT_ZERO                     0x7fffU 
   42 #define NVM_LAST_BIT_ZERO                      0xfffeU 
   44 #define NVM_CHECKSUM_INITIAL                   0xffffU 
   45 #define NVM_CHECKSUM_LENGTH                    0x2U 
   47 #define NVM_PAGES_PER_WEAR_HISTORY             0x8U 
   52 #ifndef NVM_ACQUIRE_WRITE_LOCK 
   53 #define NVM_ACQUIRE_WRITE_LOCK 
   56 #ifndef NVM_RELEASE_WRITE_LOCK 
   57 #define NVM_RELEASE_WRITE_LOCK 
   70   nvmValidateResultOk       = 0, 
 
   71   nvmValidateResultOkMarked = 1, 
 
   72   nvmValidateResultOld      = 2, 
 
   73   nvmValidateResultError    = 3  
 
   74 } NVM_ValidateResult_t;
 
   86 #define NVM_HEADER_SIZE          (sizeof(NVM_Page_Header_t)) 
   97 #define NVM_FOOTER_SIZE          (sizeof(NVM_Page_Footer_t)) 
  108 static NVM_Config_t 
const *nvmConfig;
 
  110 #if (NVM_FEATURE_STATIC_WEAR_ENABLED) 
  115 static uint8_t nvmStaticWearWriteHistory[(NVM_MAX_NUMBER_OF_PAGES + (NVM_PAGES_PER_WEAR_HISTORY - 1)) / NVM_PAGES_PER_WEAR_HISTORY];
 
  118 static uint16_t nvmStaticWearWritesInHistory;
 
  121 static uint16_t nvmStaticWearErasesSinceReset;
 
  124 static bool nvmStaticWearWorking = 
false;
 
  135 static uint8_t* NVM_PagePhysicalAddressGet(uint16_t pageId);
 
  136 static uint8_t* NVM_ScratchPageFindBest(
void);
 
  137 static Ecode_t NVM_PageErase(uint8_t *pPhysicalAddress);
 
  138 static NVM_Page_Descriptor_t NVM_PageDescriptorGet(uint16_t pageId);
 
  139 static NVM_ValidateResult_t NVM_PageValidate(uint8_t *pPhysicalAddress);
 
  141 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
  142 static uint16_t NVM_WearIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc);
 
  143 static bool NVM_WearReadIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc, uint16_t *pIndex);
 
  146 static void NVM_ChecksumAdditive(uint16_t *pChecksum, 
void *pBuffer, uint16_t len);
 
  148 #if (NVM_FEATURE_STATIC_WEAR_ENABLED) 
  149 static void NVM_StaticWearReset(
void);
 
  150 static void NVM_StaticWearUpdate(uint16_t address);
 
  151 static Ecode_t NVM_StaticWearCheck(
void);
 
  192   uint8_t *pPhysicalAddress = (uint8_t *)(config->nvmArea);
 
  194   uint8_t *pDuplicatePhysicalAddress;
 
  197   uint16_t logicalAddress;
 
  199   uint16_t duplicateLogicalAddress;
 
  202   NVM_ValidateResult_t validationResult;
 
  207   if( (config->pages <= config->userPages)
 
  208     || (config->pages > NVM_MAX_NUMBER_OF_PAGES) )
 
  215     uint16_t pageIdx = 0, obj = 0, sum = 0;
 
  216     const NVM_Page_Descriptor_t *currentPage;
 
  218     for(pageIdx = 0; pageIdx < config->userPages; pageIdx++)
 
  222       currentPage = &((*(config->nvmPages))[pageIdx]);
 
  224       while( (*(currentPage->page))[obj].location != 0)
 
  226         sum += (*(currentPage->page))[obj++].size;
 
  229       if(currentPage->pageType == nvmPageTypeNormal)
 
  231         if( sum > NVM_CONTENT_SIZE )
 
  238         if(currentPage->pageType == nvmPageTypeWear)
 
  240           if( (sum+NVM_CHECKSUM_LENGTH) > NVM_WEAR_CONTENT_SIZE )
 
  255   NVM_ACQUIRE_WRITE_LOCK
 
  260 #if (NVM_FEATURE_STATIC_WEAR_ENABLED) 
  262   NVM_StaticWearReset();
 
  266   for (page = 0; page < nvmConfig->pages; ++page)
 
  270     NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, watermark),
 
  272                 sizeof(logicalAddress));
 
  273     if (NVM_PAGE_EMPTY_VALUE != logicalAddress)
 
  276       validationResult = NVM_PageValidate(pPhysicalAddress);
 
  279       if (nvmValidateResultOk == validationResult)
 
  288       else if (nvmValidateResultOkMarked == validationResult)
 
  295         pDuplicatePhysicalAddress = (uint8_t *)(nvmConfig->nvmArea)
 
  296                                       + offsetof(NVM_Page_Header_t, watermark);
 
  297         for (page = 0; (NVM_PAGE_EMPTY_VALUE != logicalAddress) && (page < nvmConfig->pages);
 
  300           NVMHAL_Read(pDuplicatePhysicalAddress + offsetof(NVM_Page_Header_t, watermark), &
 
  301                       duplicateLogicalAddress,
 
  302                       sizeof(duplicateLogicalAddress));
 
  304           if ((pDuplicatePhysicalAddress != pPhysicalAddress)
 
  305               && ((logicalAddress | NVM_FIRST_BIT_ONE) == duplicateLogicalAddress))
 
  309             validationResult = NVM_PageValidate(pDuplicatePhysicalAddress);
 
  311             if (nvmValidateResultOk == validationResult)
 
  314               eraseResult = NVM_PageErase(pPhysicalAddress);
 
  319               eraseResult = NVM_PageErase(pDuplicatePhysicalAddress);
 
  330           pDuplicatePhysicalAddress += NVM_PAGE_SIZE;
 
  348     pPhysicalAddress += NVM_PAGE_SIZE;
 
  358   NVM_RELEASE_WRITE_LOCK
 
  389   uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
 
  392   uint32_t tempEraseCount = eraseCount;
 
  395   NVM_ACQUIRE_WRITE_LOCK
 
  399        (page < nvmConfig->pages)
 
  408       NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, eraseCount),
 
  410                   sizeof(tempEraseCount));
 
  419       result = 
NVMHAL_Write(pPhysicalAddress + offsetof(NVM_Page_Header_t, eraseCount),
 
  421                             sizeof(tempEraseCount));
 
  425     pPhysicalAddress += NVM_PAGE_SIZE;
 
  429   NVM_RELEASE_WRITE_LOCK
 
  466   uint16_t watermark = pageId | NVM_FIRST_BIT_ONE;
 
  468   const uint32_t flipWatermark = NVM_FLIP_FIRST_BIT_OF_32_WHEN_WRITE;
 
  471   NVM_Page_Descriptor_t pageDesc;
 
  475   NVM_Page_Header_t header;
 
  478   uint16_t checksum = NVM_CHECKSUM_INITIAL;
 
  481   uint8_t *pOldPhysicalAddress = (uint8_t *) NVM_NO_PAGE_RETURNED;
 
  482   uint8_t *pNewPhysicalAddress = (uint8_t *) NVM_NO_PAGE_RETURNED;
 
  485   uint16_t offsetAddress;
 
  495   bool wearWrite = 
false;
 
  497 #if (NVM_FEATURE_WRITE_NECESSARY_CHECK_ENABLED) 
  502 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
  504   uint16_t wearChecksum;
 
  506   uint16_t wearObjectSize;
 
  510   #if (NVM_FEATURE_WRITE_VALIDATION_ENABLED) 
  512   uint16_t wearIndexNew;
 
  517   NVM_ACQUIRE_WRITE_LOCK
 
  520   pOldPhysicalAddress = NVM_PagePhysicalAddressGet(pageId);
 
  523   pageDesc = NVM_PageDescriptorGet(pageId);
 
  525 #if (NVM_FEATURE_WRITE_NECESSARY_CHECK_ENABLED) 
  530   if (((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
 
  531       && (nvmPageTypeNormal == pageDesc.pageType)
 
  532 #if (NVM_FEATURE_STATIC_WEAR_ENABLED)
 
  533       && !nvmStaticWearWorking
 
  538     rewriteNeeded = 
false;
 
  544     while (((*pageDesc.page)[objectIndex].size != 0) && !rewriteNeeded)
 
  549           ((*pageDesc.page)[objectIndex].objectId == objectId))
 
  553         copyLength = (*pageDesc.page)[objectIndex].size;
 
  556         while (copyLength != 0)
 
  559           NVMHAL_Read(pOldPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
 
  564           if (*(uint8_t *)((*pageDesc.page)[objectIndex].location + offsetAddress) != copyBuffer)
 
  566             rewriteNeeded = 
true;
 
  571           offsetAddress += 
sizeof(copyBuffer);
 
  572           copyLength    -= 
sizeof(copyBuffer);
 
  578         offsetAddress += (*pageDesc.page)[objectIndex].size;
 
  588       NVM_RELEASE_WRITE_LOCK
 
  597 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
  602   if (nvmPageTypeWear == pageDesc.pageType)
 
  608     wearChecksum = NVM_CHECKSUM_INITIAL;
 
  609     NVM_ChecksumAdditive(&wearChecksum,
 
  610                          (*pageDesc.page)[0].location,
 
  611                          (*pageDesc.page)[0].size);
 
  612     wearChecksum &= NVM_LAST_BIT_ZERO;
 
  615     if ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
 
  618       wearIndex      = NVM_WearIndex(pOldPhysicalAddress, &pageDesc);
 
  619       wearObjectSize = (*pageDesc.page)[0].size + NVM_CHECKSUM_LENGTH;
 
  622       if (wearIndex < ((uint16_t) NVM_WEAR_CONTENT_SIZE) / wearObjectSize)
 
  626                               + (wearIndex * wearObjectSize),
 
  627                               (*pageDesc.page)[0].location,
 
  628                               (*pageDesc.page)[0].size);
 
  631                               + (wearIndex * wearObjectSize)
 
  632                               + (*pageDesc.page)[0].size,
 
  634                               sizeof(wearChecksum));
 
  639 #if (NVM_FEATURE_WRITE_VALIDATION_ENABLED) 
  642         if ((!NVM_WearReadIndex(pOldPhysicalAddress, &pageDesc, &wearIndexNew)) ||
 
  643             (wearIndexNew != wearIndex))
 
  653 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
  659   if ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
 
  661     result = 
NVMHAL_Write(pOldPhysicalAddress, &flipWatermark, 4);
 
  666       NVM_RELEASE_WRITE_LOCK
 
  672   pNewPhysicalAddress = NVM_ScratchPageFindBest();
 
  674   if ((uint8_t*) NVM_NO_PAGE_RETURNED == pNewPhysicalAddress)
 
  677     NVM_RELEASE_WRITE_LOCK
 
  682   header.watermark  = watermark;
 
  683   header.eraseCount = NVM_NO_WRITE_32BIT;
 
  684   header.version    = NVM_VERSION;
 
  687   NVMHAL_Write(pNewPhysicalAddress + offsetof(NVM_Page_Header_t, watermark),
 
  689                sizeof(header.watermark));
 
  690   NVMHAL_Write(pNewPhysicalAddress + offsetof(NVM_Page_Header_t, eraseCount),
 
  691                &header.eraseCount, 
sizeof(header.eraseCount));
 
  693   NVMHAL_Write(pNewPhysicalAddress + offsetof(NVM_Page_Header_t, version),
 
  694                &header.version, 
sizeof(header.version));
 
  708         ((*pageDesc.page)[objectIndex].objectId == objectId))
 
  711       result = 
NVMHAL_Write(pNewPhysicalAddress + NVM_HEADER_SIZE + offsetAddress,
 
  712                             (*pageDesc.page)[objectIndex].location,
 
  713                             (*pageDesc.page)[objectIndex].size);
 
  714       offsetAddress += (*pageDesc.page)[objectIndex].size;
 
  716       NVM_ChecksumAdditive(&checksum,
 
  717                            (*pageDesc.page)[objectIndex].location,
 
  718                            (*pageDesc.page)[objectIndex].size);
 
  723       if ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress)
 
  725         NVM_ChecksumAdditive(&checksum,
 
  726                              pOldPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
 
  727                              (*pageDesc.page)[objectIndex].size);
 
  729         copyLength = (*pageDesc.page)[objectIndex].size;
 
  734           NVMHAL_Read(pOldPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
 
  737           result = 
NVMHAL_Write(pNewPhysicalAddress + NVM_HEADER_SIZE + offsetAddress,
 
  741           offsetAddress += 
sizeof(copyBuffer);
 
  742           copyLength    -= 
sizeof(copyBuffer);
 
  751 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
  752   if (nvmPageTypeWear == pageDesc.pageType)
 
  754     result = 
NVMHAL_Write(pNewPhysicalAddress + NVM_HEADER_SIZE + offsetAddress,
 
  756                           sizeof(wearChecksum));
 
  766                             (NVM_PAGE_SIZE - NVM_FOOTER_SIZE) +
 
  767                             offsetof(NVM_Page_Footer_t, checksum),
 
  771                             (NVM_PAGE_SIZE - NVM_FOOTER_SIZE) +
 
  772                             offsetof(NVM_Page_Footer_t, watermark),
 
  777 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
  781 #if (NVM_FEATURE_WRITE_VALIDATION_ENABLED) 
  783   if (nvmValidateResultOk != NVM_PageValidate(pNewPhysicalAddress))
 
  789 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
  795       ((uint8_t *) NVM_NO_PAGE_RETURNED != pOldPhysicalAddress))
 
  799       result = NVM_PageErase(pOldPhysicalAddress);
 
  803       NVM_PageErase(pNewPhysicalAddress);
 
  808   NVM_RELEASE_WRITE_LOCK
 
  836 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
  842   uint8_t *pPhysicalAddress;
 
  845   NVM_Page_Descriptor_t pageDesc;
 
  850   uint16_t offsetAddress;
 
  854   NVM_ACQUIRE_WRITE_LOCK
 
  857   pPhysicalAddress = NVM_PagePhysicalAddressGet(pageId);
 
  860   if ((uint8_t*) NVM_NO_PAGE_RETURNED == pPhysicalAddress)
 
  863     NVM_RELEASE_WRITE_LOCK
 
  868   pageDesc = NVM_PageDescriptorGet(pageId);
 
  870 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
  873   if (nvmPageTypeWear == pageDesc.pageType)
 
  876     if (NVM_WearReadIndex(pPhysicalAddress + offsetof(NVM_Page_Header_t, eraseCount),
 
  877                           &pageDesc, &wearIndex))
 
  880                   wearIndex * ((*pageDesc.page)[0].size + NVM_CHECKSUM_LENGTH),
 
  881                   (*pageDesc.page)[0].location,
 
  882                   (*pageDesc.page)[0].size);
 
  888       NVM_RELEASE_WRITE_LOCK
 
  899 #if (NVM_FEATURE_READ_VALIDATION_ENABLED) 
  900     if (nvmValidateResultError == NVM_PageValidate(pPhysicalAddress))
 
  903       NVM_RELEASE_WRITE_LOCK
 
  910     while ((*pageDesc.page)[objectIndex].size != 0)
 
  914           || ((*pageDesc.page)[objectIndex].objectId == objectId))
 
  916         NVMHAL_Read(pPhysicalAddress + offsetAddress + NVM_HEADER_SIZE,
 
  917                     (*pageDesc.page)[objectIndex].location,
 
  918                     (*pageDesc.page)[objectIndex].size);
 
  921       offsetAddress += (*pageDesc.page)[objectIndex].size;
 
  927   NVM_RELEASE_WRITE_LOCK
 
  932 #if (NVM_FEATURE_WEARLEVELGET_ENABLED) 
  944 uint32_t NVM_WearLevelGet(
void)
 
  950   uint32_t hiEraseCount = 0;
 
  953   uint8_t *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
 
  956   for (page = 0; page < nvmConfig->pages; ++page)
 
  959     NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, eraseCount),
 
  962     if (eraseCount > hiEraseCount)
 
  964       hiEraseCount = eraseCount;
 
  968     pPhysicalAddress += NVM_PAGE_SIZE;
 
  996 static uint8_t* NVM_PagePhysicalAddressGet(uint16_t pageId)
 
 1000   uint8_t  *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
 
 1002   uint16_t logicalAddress;
 
 1005   for (page = 0; page < nvmConfig->pages; ++page)
 
 1009     NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, watermark),
 
 1011                 sizeof(logicalAddress));
 
 1012     if (((pageId | NVM_FIRST_BIT_ONE) == logicalAddress) || (pageId == logicalAddress))
 
 1014       return pPhysicalAddress;
 
 1018     pPhysicalAddress += NVM_PAGE_SIZE;
 
 1022   return (uint8_t *) NVM_NO_PAGE_RETURNED;
 
 1038 static uint8_t* NVM_ScratchPageFindBest(
void)
 
 1042   uint8_t  *pPhysicalPage = (uint8_t *) NVM_NO_PAGE_RETURNED;
 
 1045   uint32_t eraseCount = NVM_HIGHEST_32BIT;
 
 1047   uint32_t loEraseCount = NVM_HIGHEST_32BIT;
 
 1050   uint8_t  *pPhysicalAddress = (uint8_t *)(nvmConfig->nvmArea);
 
 1052   uint16_t logicalAddress;
 
 1055   for (page = 0; page < nvmConfig->pages; ++page)
 
 1058     NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, watermark),
 
 1060                 sizeof(logicalAddress));
 
 1061     if ((uint16_t) NVM_PAGE_EMPTY_VALUE == logicalAddress)
 
 1064       NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, eraseCount),
 
 1066                   sizeof(eraseCount));
 
 1067       if (eraseCount < loEraseCount)
 
 1069         loEraseCount  = eraseCount;
 
 1070         pPhysicalPage = pPhysicalAddress;
 
 1075     pPhysicalAddress += NVM_PAGE_SIZE;
 
 1079   return pPhysicalPage;
 
 1097 static Ecode_t NVM_PageErase(uint8_t *pPhysicalAddress)
 
 1099 #if (NVM_FEATURE_STATIC_WEAR_ENABLED) 
 1101   uint16_t logicalAddress;
 
 1105   uint32_t eraseCount;
 
 1106   NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, eraseCount),
 
 1108               sizeof(eraseCount));
 
 1110 #if (NVM_FEATURE_STATIC_WEAR_ENABLED) 
 1112   NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, watermark),
 
 1114               sizeof(logicalAddress));
 
 1117   if (logicalAddress != NVM_PAGE_EMPTY_VALUE)
 
 1120     logicalAddress = logicalAddress & NVM_FIRST_BIT_ZERO;
 
 1121     NVM_StaticWearUpdate(logicalAddress);
 
 1132   return NVMHAL_Write(pPhysicalAddress + offsetof(NVM_Page_Header_t, eraseCount),
 
 1134                       sizeof(eraseCount));
 
 1157 static NVM_Page_Descriptor_t NVM_PageDescriptorGet(uint16_t pageId)
 
 1160   static const NVM_Page_Descriptor_t nullPage = { (uint8_t) 0, 0, (NVM_Page_Type_t) 0 };
 
 1163   for (pageIndex = 0; pageIndex < nvmConfig->userPages; ++pageIndex)
 
 1166     if ( (*(nvmConfig->nvmPages))[pageIndex].pageId == pageId)
 
 1168       return (*(nvmConfig->nvmPages))[pageIndex];
 
 1198 static NVM_ValidateResult_t NVM_PageValidate(uint8_t *pPhysicalAddress)
 
 1201   NVM_ValidateResult_t result;
 
 1204   NVM_Page_Header_t header;
 
 1205   NVM_Page_Footer_t footer;
 
 1208   NVM_Page_Descriptor_t pageDesc;
 
 1214   uint8_t  objectIndex;
 
 1216   uint16_t offsetAddress;
 
 1218 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
 1224   NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, watermark),
 
 1226               sizeof(header.watermark));
 
 1227   NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, eraseCount),
 
 1229               sizeof(header.eraseCount));
 
 1230   NVMHAL_Read(pPhysicalAddress + offsetof(NVM_Page_Header_t, version),
 
 1232               sizeof(header.version));
 
 1235   if (NVM_VERSION != header.version)
 
 1237     return nvmValidateResultOld;
 
 1241   pageDesc = NVM_PageDescriptorGet((header.watermark & NVM_FIRST_BIT_ZERO));
 
 1244 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
 1245   if (nvmPageTypeWear == pageDesc.pageType)
 
 1250     if ((header.watermark & NVM_FIRST_BIT_ZERO) == header.watermark)
 
 1252       result = nvmValidateResultOkMarked;
 
 1257       result = nvmValidateResultOk;
 
 1261     if (!NVM_WearReadIndex(pPhysicalAddress, &pageDesc, &index))
 
 1263       result = nvmValidateResultError;
 
 1270     NVMHAL_Read(pPhysicalAddress + (NVM_PAGE_SIZE - NVM_FOOTER_SIZE) +
 
 1271                   offsetof(NVM_Page_Footer_t, checksum),
 
 1273                 sizeof(footer.checksum));
 
 1274     NVMHAL_Read(pPhysicalAddress + (NVM_PAGE_SIZE - NVM_FOOTER_SIZE) +
 
 1275                   offsetof(NVM_Page_Footer_t, watermark),
 
 1277                 sizeof(footer.watermark));
 
 1279     if (header.watermark == footer.watermark)
 
 1281       result = nvmValidateResultOk;
 
 1283     else if ((header.watermark | NVM_FIRST_BIT_ONE) == footer.watermark)
 
 1285       result = nvmValidateResultOkMarked;
 
 1289       result = nvmValidateResultError;
 
 1295     checksum      = NVM_CHECKSUM_INITIAL;
 
 1300     while ((*pageDesc.page)[objectIndex].size != 0)
 
 1303                       (uint8_t *) pPhysicalAddress
 
 1304                        + NVM_HEADER_SIZE + offsetAddress,
 
 1305                       (*pageDesc.page)[objectIndex].size);
 
 1306       offsetAddress += (*pageDesc.page)[objectIndex].size;
 
 1310     if (checksum != footer.checksum)
 
 1312       result = nvmValidateResultError;
 
 1319 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
 1338 static uint16_t NVM_WearIndex(uint8_t *pPhysicalAddress, NVM_Page_Descriptor_t *pPageDesc)
 
 1341   uint16_t wearIndex = 0;
 
 1347   uint16_t wearObjectSize = ((*pPageDesc->page)[0].size + NVM_CHECKSUM_LENGTH);
 
 1351   while (wearIndex < NVM_WEAR_CONTENT_SIZE / wearObjectSize)
 
 1353     NVMHAL_Read((uint8_t *)(pPhysicalAddress + NVM_HEADER_SIZE
 
 1354                             + (wearIndex * wearObjectSize)
 
 1355                             + (*pPageDesc->page)[0].size
 
 1362     if ((checksum & NVM_LAST_BIT_ZERO) != checksum)
 
 1377 #if (NVM_FEATURE_WEAR_PAGES_ENABLED) 
 1399 static bool NVM_WearReadIndex(uint8_t *pPhysicalAddress,
 
 1400                               NVM_Page_Descriptor_t *pPageDesc,
 
 1403 #if (NVM_FEATURE_READ_VALIDATION_ENABLED) 
 1405   uint16_t checksum = NVM_CHECKSUM_INITIAL;
 
 1409   const uint16_t wearObjectSize = ((*pPageDesc->page)[0].size + NVM_CHECKSUM_LENGTH);
 
 1412   bool validObjectFound = 
false;
 
 1415   uint16_t readBuffer;
 
 1418   *pIndex = (((uint16_t) NVM_WEAR_CONTENT_SIZE) / wearObjectSize);
 
 1421   while ((*pIndex > 0) && (!validObjectFound))
 
 1426     uint8_t *temp = pPhysicalAddress
 
 1428                     + (*pIndex) * wearObjectSize
 
 1429                     + (*pPageDesc->page)[0].size;
 
 1430     NVMHAL_Read((uint8_t *) temp, &readBuffer, 
sizeof(readBuffer));
 
 1432 #if (NVM_FEATURE_READ_VALIDATION_ENABLED) 
 1434     checksum = NVM_CHECKSUM_INITIAL;
 
 1435     NVMHAL_Checksum(&checksum, pPhysicalAddress + NVM_HEADER_SIZE + (*pIndex) * wearObjectSize, (*pPageDesc->page)[0].size);
 
 1438     if ((uint16_t)(checksum & NVM_LAST_BIT_ZERO) == readBuffer)
 
 1440     if (NVM_NO_WRITE_16BIT != readBuffer)
 
 1443       validObjectFound = 
true;
 
 1446   return validObjectFound;
 
 1470 static void NVM_ChecksumAdditive(uint16_t *pChecksum, 
void *pBuffer, uint16_t len)
 
 1472   uint8_t *pointer = (uint8_t *) pBuffer;
 
 1473   uint16_t crc = *pChecksum;
 
 1477     crc = (crc >> 8) | (crc << 8);
 
 1479     crc ^= (crc & 0xf0) >> 4;
 
 1480     crc ^= (crc & 0x0f) << 12;
 
 1481     crc ^= (crc & 0xff) << 5;
 
 1488 #if (NVM_FEATURE_STATIC_WEAR_ENABLED) 
 1498 static void NVM_StaticWearReset(
void)
 
 1501   nvmStaticWearErasesSinceReset = 0;
 
 1502   nvmStaticWearWritesInHistory  = 0;
 
 1504   for (i = 0; (NVM_PAGES_PER_WEAR_HISTORY * i) < nvmConfig->userPages; i += 1)
 
 1506     nvmStaticWearWriteHistory[i] = 0;
 
 1521 static void NVM_StaticWearUpdate(uint16_t address)
 
 1523   if (address < nvmConfig->userPages)
 
 1528     uint8_t mask = 1U << (address % NVM_PAGES_PER_WEAR_HISTORY);
 
 1530     if ((nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] & mask) == 0)
 
 1533       nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] |= mask;
 
 1535       nvmStaticWearWritesInHistory++;
 
 1539     nvmStaticWearErasesSinceReset++;
 
 1542     NVM_StaticWearCheck();
 
 1556 static Ecode_t NVM_StaticWearCheck(
void)
 
 1559   if (!nvmStaticWearWorking)
 
 1561     nvmStaticWearWorking = 
true;
 
 1562     while (nvmStaticWearErasesSinceReset / nvmStaticWearWritesInHistory > NVM_STATIC_WEAR_THRESHOLD)
 
 1565       if (nvmStaticWearWritesInHistory >= nvmConfig->userPages)
 
 1567         NVM_StaticWearReset();
 
 1572       uint16_t address = 0;
 
 1573       uint8_t  mask    = 1U << (address % NVM_PAGES_PER_WEAR_HISTORY);
 
 1574       while ((nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] & mask) != 0)
 
 1577         mask = 1U << (address % NVM_PAGES_PER_WEAR_HISTORY);
 
 1581       if (nvmPageTypeWear == NVM_PageDescriptorGet(address).pageType)
 
 1584         nvmStaticWearWriteHistory[address / NVM_PAGES_PER_WEAR_HISTORY] |= mask;
 
 1586         nvmStaticWearWritesInHistory++;
 
 1594         NVM_RELEASE_WRITE_LOCK
 
 1599         NVM_ACQUIRE_WRITE_LOCK
 
 1602     nvmStaticWearWorking = 
false;
 
void NVMHAL_Read(uint8_t *pAddress, void *pObject, uint16_t len)
Read data from NVM. 
 
#define NVM_WRITE_ALL_CMD
 
void NVMHAL_Checksum(uint16_t *checksum, void *pMemory, uint16_t len)
Calculate checksum according to CCITT CRC16. 
 
Ecode_t NVM_Read(uint16_t pageId, uint8_t objectId)
Read an object or an entire page. 
 
#define NVM_ERASE_RETAINCOUNT
 
Ecode_t NVMHAL_Write(uint8_t *pAddress, void const *pObject, uint16_t len)
Write data to NVM. 
 
#define ECODE_EMDRV_NVM_NO_PAGES_AVAILABLE
Initialization didn't find any pages available to allocate. 
 
Ecode_t NVMHAL_PageErase(uint8_t *pAddress)
Erase a page in the NVM. 
 
Ecode_t NVM_Erase(uint32_t eraseCount)
Erase the entire allocated NVM area. 
 
Non-Volatile Memory Wear-Leveling driver API. 
 
Ecode_t NVM_Init(NVM_Config_t const *config)
Initialize the NVM manager. 
 
Ecode_t NVM_Write(uint16_t pageId, uint8_t objectId)
Write an object or a page. 
 
#define ECODE_EMDRV_NVM_PAGE_INVALID
Could not find the page specified. 
 
void NVMHAL_Init(void)
Initialize NVM driver. 
 
uint32_t Ecode_t
Typedef for API function error code return values. 
 
#define ECODE_EMDRV_NVM_ERROR
General error. 
 
#define ECODE_EMDRV_NVM_OK
Success return value. 
 
#define NVM_WRITE_NONE_CMD
 
#define ECODE_EMDRV_NVM_DATA_INVALID
Invalid input data or format.