nvm_hal.c
Go to the documentation of this file.00001
00035 #include <stdbool.h>
00036 #include "em_msc.h"
00037 #include "nvm.h"
00038 #include "nvm_hal.h"
00039
00040
00041
00042
00043
00046
00047 #define NVMHAL_FFFFFFFF 0xffffffffUL
00048
00049 #if (NVMHAL_DMAREAD == true)
00050
00051 #define NVMHAL_DMA_CHANNELS 1
00052 #define NVMHAL_DMA_CHANNEL_FLASH 0
00053
00054
00055 #if defined (__ICCARM__)
00056 #pragma data_alignment=256
00057 static DMA_DESCRIPTOR_TypeDef NVMHAL_dmaControlBlock[DMA_CHAN_COUNT * 2];
00058 #elif defined (__CC_ARM)
00059 static DMA_DESCRIPTOR_TypeDef NVMHAL_dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256)));
00060 #elif defined (__GNUC__)
00061 static DMA_DESCRIPTOR_TypeDef NVMHAL_dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256)));
00062 #else
00063 #error Undefined toolkit, need to define alignment
00064 #endif
00065
00066 #endif
00067
00068 #if (NVMHAL_SLEEP == true || NVMHAL_DMAREAD == true)
00069
00070 static volatile bool NVMHAL_FlashTransferActive;
00071 #endif
00072
00075
00076
00077
00078
00079
00080
00087 #if (NVMHAL_SLEEP == true)
00088 #ifdef __CC_ARM
00089 static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes);
00090 static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress);
00091 #endif
00092
00093 #ifdef __ICCARM__
00094 __ramfunc static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes);
00095 __ramfunc static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress);
00096 #endif
00097
00098 #ifdef __GNUC__
00099 #ifdef __CROSSWORKS_ARM
00100 static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes) __attribute__ ((section(".fast")));
00101 static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress) __attribute__ ((section(".fast")));
00102 #else
00103 static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes) __attribute__ ((section(".ram")));
00104 static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress) __attribute__ ((section(".ram")));
00105 #endif
00106 #endif
00107 #endif
00108
00113 #if (NVMHAL_DMAREAD == true)
00114
00117 static void NVM_ReadFromFlashComplete(unsigned int channel, bool primary, void *user)
00118 {
00119
00120 NVMHAL_FlashTransferActive = false;
00121 }
00122 #endif
00123
00124 #if (NVMHAL_SLEEP == true)
00125
00128 void MSC_IRQHandler(void)
00129 {
00130
00131 MSC_IntClear(MSC_IFC_ERASE);
00132 MSC_IntClear(MSC_IFC_WRITE);
00133
00134 NVMHAL_FlashTransferActive = false;
00135 }
00136 #endif
00137
00138 #if (NVMHAL_SLEEP_WRITE == true)
00139
00140
00177 #ifdef __CC_ARM
00178 #pragma arm section code="ram_code"
00179 #endif
00180 static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes)
00181 {
00182 uint32_t timeOut;
00183 uint32_t wordCount;
00184 uint32_t numWords;
00185
00186
00187 MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
00188
00189
00190 numWords = numBytes >> 2;
00191
00192 for (wordCount = 0; wordCount < numWords; wordCount++)
00193 {
00194
00195 MSC->ADDRB = (uint32_t)(address + wordCount);
00196 MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
00197
00198
00199 if (MSC->STATUS & MSC_STATUS_INVADDR)
00200 {
00201
00202 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00203 return mscReturnInvalidAddr;
00204 }
00205
00206
00207 if (MSC->STATUS & MSC_STATUS_LOCKED)
00208 {
00209
00210 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00211 return mscReturnLocked;
00212 }
00213
00214
00215
00216 timeOut = MSC_PROGRAM_TIMEOUT;
00217 while (((MSC->STATUS & MSC_STATUS_WDATAREADY) == 0) && (timeOut != 0))
00218 {
00219 timeOut--;
00220 }
00221
00222
00223 if (timeOut == 0)
00224 {
00225
00226 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00227 return mscReturnTimeOut;
00228 }
00229
00230
00231 MSC->WDATA = *(((uint32_t *) data) + wordCount);
00232
00233
00234 MSC->IFC = MSC_IEN_WRITE;
00235 MSC->IEN |= MSC_IEN_WRITE;
00236 NVIC->ISER[((uint32_t)(MSC_IRQn) >> 5)] = (1 << ((uint32_t)(MSC_IRQn) & 0x1F));
00237
00238
00239 NVMHAL_FlashTransferActive = true;
00240
00241
00242 MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 INT_Disable();
00257
00258 while ((MSC->STATUS & MSC_STATUS_BUSY) && NVMHAL_FlashTransferActive)
00259 {
00260
00261
00262 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
00263 __WFI();
00264
00265 INT_Enable();
00266
00267 INT_Disable();
00268 }
00269
00270 INT_Enable();
00271
00272
00273
00274 NVMHAL_FlashTransferActive = false;
00275
00276
00277 MSC->IFC = MSC_IEN_WRITE;
00278 }
00279
00280
00281 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00282 return mscReturnOk;
00283 }
00284 #ifdef __CC_ARM
00285 #pragma arm section code
00286 #endif
00287
00288 #endif
00289
00290 #if (NVMHAL_SLEEP == true)
00291
00322 #ifdef __CC_ARM
00323 #pragma arm section code="ram_code"
00324 #endif
00325 static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress)
00326 {
00327
00328 MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
00329
00330
00331 MSC->ADDRB = (uint32_t) startAddress;
00332 MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
00333
00334
00335 if (MSC->STATUS & MSC_STATUS_INVADDR)
00336 {
00337
00338 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00339 return mscReturnInvalidAddr;
00340 }
00341
00342
00343 if (MSC->STATUS & MSC_STATUS_LOCKED)
00344 {
00345
00346 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00347 return mscReturnLocked;
00348 }
00349
00350
00351 MSC->IFC = MSC_IEN_ERASE;
00352 MSC->IEN |= MSC_IEN_ERASE;
00353 NVIC->ISER[((uint32_t)(MSC_IRQn) >> 5)] = (1 << ((uint32_t)(MSC_IRQn) & 0x1F));
00354
00355 NVMHAL_FlashTransferActive = true;
00356
00357
00358 MSC->WRITECMD = MSC_WRITECMD_ERASEPAGE;
00359
00360 INT_Disable();
00361
00362 while ((MSC->STATUS & MSC_STATUS_BUSY) && NVMHAL_FlashTransferActive)
00363 {
00364
00365 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
00366 __WFI();
00367 INT_Enable();
00368 INT_Disable();
00369 }
00370 INT_Enable();
00371
00372 NVMHAL_FlashTransferActive = false;
00373
00374
00375 MSC->IFC = MSC_IEN_ERASE;
00376
00377
00378 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00379 return mscReturnOk;
00380 }
00381 #ifdef __CC_ARM
00382 #pragma arm section code
00383 #endif
00384
00385 #endif
00386
00389
00403 static NVM_Result_t NVMHAL_ReturnTypeConvert(msc_Return_TypeDef result)
00404 {
00405
00406
00407 switch (result)
00408 {
00409 case mscReturnOk:
00410 return nvmResultOk;
00411 case mscReturnInvalidAddr:
00412 return nvmResultAddrInvalid;
00413 case mscReturnUnaligned:
00414 return nvmResultInputInvalid;
00415 default:
00416 return nvmResultError;
00417 }
00418 }
00419
00420
00421
00422
00423
00424
00433 void NVMHAL_Init(void)
00434 {
00435 MSC_Init();
00436
00437 #if (NVMHAL_DMAREAD == true)
00438
00439 CMU_ClockEnable(cmuClock_DMA, true);
00440
00441
00442 DMA_Init_TypeDef dmaInit;
00443 dmaInit.hprot = 0;
00444 dmaInit.controlBlock = NVMHAL_dmaControlBlock;
00445 DMA_Init(&dmaInit);
00446 #endif
00447 }
00448
00449
00457 void NVMHAL_DeInit(void)
00458 {
00459 MSC_Deinit();
00460 }
00461
00462
00483 void NVMHAL_Read(uint8_t *pAddress, void *pObject, uint16_t len)
00484 {
00485 #if (NVMHAL_DMAREAD == true)
00486
00487 DMA_CB_TypeDef cb[DMA_CHAN_COUNT];
00488 cb[NVMHAL_DMA_CHANNEL_FLASH].cbFunc = NVM_ReadFromFlashComplete;
00489
00490
00491
00492 cb[NVMHAL_DMA_CHANNEL_FLASH].userPtr = NULL;
00493
00494
00495 DMA_CfgChannel_TypeDef chnlCfg;
00496 chnlCfg.highPri = false;
00497 chnlCfg.enableInt = true;
00498 chnlCfg.select = 0;
00499 chnlCfg.cb = &(cb[NVMHAL_DMA_CHANNEL_FLASH]);
00500 DMA_CfgChannel(NVMHAL_DMA_CHANNEL_FLASH, &chnlCfg);
00501
00502
00503 DMA_CfgDescr_TypeDef descrCfg;
00504 descrCfg.dstInc = dmaDataInc1;
00505 descrCfg.srcInc = dmaDataInc1;
00506 descrCfg.size = dmaDataSize1;
00507 descrCfg.arbRate = dmaArbitrate1;
00508 descrCfg.hprot = 0;
00509 DMA_CfgDescr(NVMHAL_DMA_CHANNEL_FLASH, true, &descrCfg);
00510
00511
00512
00513 NVMHAL_FlashTransferActive = true;
00514
00515
00516 DMA_ActivateAuto(NVMHAL_DMA_CHANNEL_FLASH,
00517 true,
00518 pObject,
00519 pAddress,
00520 len - 1);
00521
00522
00523 INT_Disable();
00524 while (NVMHAL_FlashTransferActive)
00525 {
00526 EMU_EnterEM1();
00527 INT_Enable();
00528 INT_Disable();
00529 }
00530 INT_Enable();
00531 #else
00532
00533 uint8_t *pObjectInt = (uint8_t*) pObject;
00534
00535 while (0 < len)
00536 {
00537
00538 *pObjectInt = *pAddress;
00539
00540 ++pObjectInt;
00541
00542 ++pAddress;
00543
00544 --len;
00545 }
00546 #endif
00547
00548 }
00549
00550
00574 NVM_Result_t NVMHAL_Write(uint8_t *pAddress, void const *pObject, uint16_t len)
00575 {
00576
00577 msc_Return_TypeDef msc_Return = mscReturnOk;
00578
00579 uint32_t tempWord;
00580
00581
00582 uint8_t *pObjectInt = (uint8_t*) pObject;
00583
00584
00585 uint8_t padLen;
00586
00587
00588
00589 padLen = (uint32_t) pAddress % sizeof(tempWord);
00590
00591 if (padLen != 0)
00592 {
00593 pAddress -= padLen;
00594
00595
00596 tempWord = *(uint32_t *) pObjectInt;
00597
00598 tempWord = tempWord << 8 * padLen;
00599
00600 tempWord |= NVMHAL_FFFFFFFF >> (8 * (sizeof(tempWord) - padLen));
00601
00602
00603 if (len < sizeof(tempWord) - padLen)
00604 {
00605
00606 tempWord |= NVMHAL_FFFFFFFF << (8 * (padLen + len));
00607 len = 0;
00608 }
00609 else
00610 {
00611 len -= sizeof(tempWord) - padLen;
00612 }
00613
00614 #if (NVMHAL_SLEEP_WRITE == true)
00615 msc_Return = NVMHAL_MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
00616 #else
00617 msc_Return = MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
00618 #endif
00619 pObjectInt += sizeof(tempWord) - padLen;
00620 pAddress += sizeof(tempWord);
00621 }
00622
00623
00624 while ((len >= sizeof(tempWord)) && (mscReturnOk == msc_Return))
00625 {
00626 #if (NVMHAL_SLEEP_WRITE == true)
00627 msc_Return = NVMHAL_MSC_WriteWord((uint32_t *) pAddress, pObjectInt, sizeof(tempWord));
00628 #else
00629 msc_Return = MSC_WriteWord((uint32_t *) pAddress, pObjectInt, sizeof(tempWord));
00630 #endif
00631 pAddress += sizeof(tempWord);
00632 pObjectInt += sizeof(tempWord);
00633 len -= sizeof(tempWord);
00634 }
00635
00636
00637 if ((len > 0) && (mscReturnOk == msc_Return))
00638 {
00639
00640 tempWord = *(uint32_t *) pObjectInt;
00641
00642 tempWord |= NVMHAL_FFFFFFFF << (8 * len);
00643
00644 #if (NVMHAL_SLEEP_WRITE == true)
00645 msc_Return = NVMHAL_MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
00646 #else
00647 msc_Return = MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
00648 #endif
00649 }
00650
00651
00652 return NVMHAL_ReturnTypeConvert(msc_Return);
00653 }
00654
00655
00670 #if (NVMHAL_SLEEP == true)
00671 NVM_Result_t NVMHAL_PageErase(uint8_t *pAddress)
00672 {
00673
00674 return NVMHAL_ReturnTypeConvert(NVMHAL_MSC_ErasePage((uint32_t *) pAddress));
00675 }
00676
00677 #else
00678 NVM_Result_t NVMHAL_PageErase(uint8_t *pAddress)
00679 {
00680
00681 return NVMHAL_ReturnTypeConvert(MSC_ErasePage((uint32_t *) pAddress));
00682 }
00683 #endif
00684
00685
00708 void NVMHAL_Checksum(uint16_t *pChecksum, void *pMemory, uint16_t len)
00709 {
00710 uint8_t *pointer = (uint8_t *) pMemory;
00711 uint16_t crc = *pChecksum;
00712
00713 while(len--)
00714 {
00715 crc = (crc >> 8) | (crc << 8);
00716 crc ^= *pointer++;
00717 crc ^= (crc & 0xf0) >> 4;
00718 crc ^= (crc & 0x0f) << 12;
00719 crc ^= (crc & 0xff) << 5;
00720 }
00721
00722 *pChecksum = crc;
00723 }