nvm_hal.c
Go to the documentation of this file.00001
00016 #include <stdbool.h>
00017 #include "em_msc.h"
00018 #include "nvm.h"
00019 #include "nvm_hal.h"
00020
00021
00022
00023
00024
00027
00028 #define NVMHAL_FFFFFFFF 0xffffffffUL
00029
00030 #if (NVMHAL_DMAREAD == true)
00031
00032 #define NVMHAL_DMA_CHANNELS 1
00033 #define NVMHAL_DMA_CHANNEL_FLASH 0
00034
00035
00036 #if defined (__ICCARM__)
00037 #pragma data_alignment=256
00038 static DMA_DESCRIPTOR_TypeDef NVMHAL_dmaControlBlock[DMA_CHAN_COUNT * 2];
00039 #elif defined (__CC_ARM)
00040 static DMA_DESCRIPTOR_TypeDef NVMHAL_dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256)));
00041 #elif defined (__GNUC__)
00042 static DMA_DESCRIPTOR_TypeDef NVMHAL_dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256)));
00043 #else
00044 #error Undefined toolkit, need to define alignment
00045 #endif
00046
00047 #endif
00048
00049 #if (NVMHAL_SLEEP == true || NVMHAL_DMAREAD == true)
00050
00051 static volatile bool NVMHAL_FlashTransferActive;
00052 #endif
00053
00056
00057
00058
00059
00060
00061
00068 #if (NVMHAL_SLEEP == true)
00069 #ifdef __CC_ARM
00070 static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes);
00071 static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress);
00072 #endif
00073
00074 #ifdef __ICCARM__
00075 __ramfunc static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes);
00076 __ramfunc static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress);
00077 #endif
00078
00079 #ifdef __GNUC__
00080 #ifdef __CROSSWORKS_ARM
00081 static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes) __attribute__ ((section(".fast")));
00082 static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress) __attribute__ ((section(".fast")));
00083 #else
00084 static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes) __attribute__ ((section(".ram")));
00085 static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress) __attribute__ ((section(".ram")));
00086 #endif
00087 #endif
00088 #endif
00089
00094 #if (NVMHAL_DMAREAD == true)
00095
00098 static void NVM_ReadFromFlashComplete(unsigned int channel, bool primary, void *user)
00099 {
00100
00101 NVMHAL_FlashTransferActive = false;
00102 }
00103 #endif
00104
00105 #if (NVMHAL_SLEEP == true)
00106
00109 void MSC_IRQHandler(void)
00110 {
00111
00112 MSC_IntClear(MSC_IFC_ERASE);
00113 MSC_IntClear(MSC_IFC_WRITE);
00114
00115 NVMHAL_FlashTransferActive = false;
00116 }
00117 #endif
00118
00119 #if (NVMHAL_SLEEP_WRITE == true)
00120
00121
00158 #ifdef __CC_ARM
00159 #pragma arm section code="ram_code"
00160 #endif
00161 static msc_Return_TypeDef NVMHAL_MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes)
00162 {
00163 uint32_t timeOut;
00164 uint32_t wordCount;
00165 uint32_t numWords;
00166
00167
00168 MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
00169
00170
00171 numWords = numBytes >> 2;
00172
00173 for (wordCount = 0; wordCount < numWords; wordCount++)
00174 {
00175
00176 MSC->ADDRB = (uint32_t)(address + wordCount);
00177 MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
00178
00179
00180 if (MSC->STATUS & MSC_STATUS_INVADDR)
00181 {
00182
00183 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00184 return mscReturnInvalidAddr;
00185 }
00186
00187
00188 if (MSC->STATUS & MSC_STATUS_LOCKED)
00189 {
00190
00191 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00192 return mscReturnLocked;
00193 }
00194
00195
00196
00197 timeOut = MSC_PROGRAM_TIMEOUT;
00198 while (((MSC->STATUS & MSC_STATUS_WDATAREADY) == 0) && (timeOut != 0))
00199 {
00200 timeOut--;
00201 }
00202
00203
00204 if (timeOut == 0)
00205 {
00206
00207 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00208 return mscReturnTimeOut;
00209 }
00210
00211
00212 MSC->WDATA = *(((uint32_t *) data) + wordCount);
00213
00214
00215 MSC->IFC = MSC_IEN_WRITE;
00216 MSC->IEN |= MSC_IEN_WRITE;
00217 NVIC->ISER[((uint32_t)(MSC_IRQn) >> 5)] = (1 << ((uint32_t)(MSC_IRQn) & 0x1F));
00218
00219
00220 NVMHAL_FlashTransferActive = true;
00221
00222
00223 MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 INT_Disable();
00238
00239 while ((MSC->STATUS & MSC_STATUS_BUSY) && NVMHAL_FlashTransferActive)
00240 {
00241
00242
00243 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
00244 __WFI();
00245
00246 INT_Enable();
00247
00248 INT_Disable();
00249 }
00250
00251 INT_Enable();
00252
00253
00254
00255 NVMHAL_FlashTransferActive = false;
00256
00257
00258 MSC->IFC = MSC_IEN_WRITE;
00259 }
00260
00261
00262 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00263 return mscReturnOk;
00264 }
00265 #ifdef __CC_ARM
00266 #pragma arm section code
00267 #endif
00268
00269 #endif
00270
00271 #if (NVMHAL_SLEEP == true)
00272
00303 #ifdef __CC_ARM
00304 #pragma arm section code="ram_code"
00305 #endif
00306 static msc_Return_TypeDef NVMHAL_MSC_ErasePage(uint32_t *startAddress)
00307 {
00308
00309 MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
00310
00311
00312 MSC->ADDRB = (uint32_t) startAddress;
00313 MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
00314
00315
00316 if (MSC->STATUS & MSC_STATUS_INVADDR)
00317 {
00318
00319 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00320 return mscReturnInvalidAddr;
00321 }
00322
00323
00324 if (MSC->STATUS & MSC_STATUS_LOCKED)
00325 {
00326
00327 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00328 return mscReturnLocked;
00329 }
00330
00331
00332 MSC->IFC = MSC_IEN_ERASE;
00333 MSC->IEN |= MSC_IEN_ERASE;
00334 NVIC->ISER[((uint32_t)(MSC_IRQn) >> 5)] = (1 << ((uint32_t)(MSC_IRQn) & 0x1F));
00335
00336 NVMHAL_FlashTransferActive = true;
00337
00338
00339 MSC->WRITECMD = MSC_WRITECMD_ERASEPAGE;
00340
00341 INT_Disable();
00342
00343 while ((MSC->STATUS & MSC_STATUS_BUSY) && NVMHAL_FlashTransferActive)
00344 {
00345
00346 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
00347 __WFI();
00348 INT_Enable();
00349 INT_Disable();
00350 }
00351 INT_Enable();
00352
00353 NVMHAL_FlashTransferActive = false;
00354
00355
00356 MSC->IFC = MSC_IEN_ERASE;
00357
00358
00359 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
00360 return mscReturnOk;
00361 }
00362 #ifdef __CC_ARM
00363 #pragma arm section code
00364 #endif
00365
00366 #endif
00367
00370
00384 static Ecode_t NVMHAL_ReturnTypeConvert(msc_Return_TypeDef result)
00385 {
00386
00387
00388 switch (result)
00389 {
00390 case mscReturnOk:
00391 return ECODE_EMDRV_NVM_OK;
00392 case mscReturnInvalidAddr:
00393 return ECODE_EMDRV_NVM_ADDR_INVALID;
00394 case mscReturnUnaligned:
00395 return ECODE_EMDRV_NVM_ALIGNMENT_INVALID;
00396 default:
00397 return ECODE_EMDRV_NVM_ERROR;
00398 }
00399 }
00400
00401
00402
00403
00404
00405
00414 void NVMHAL_Init(void)
00415 {
00416 MSC_Init();
00417
00418 #if (NVMHAL_DMAREAD == true)
00419
00420 CMU_ClockEnable(cmuClock_DMA, true);
00421
00422
00423 DMA_Init_TypeDef dmaInit;
00424 dmaInit.hprot = 0;
00425 dmaInit.controlBlock = NVMHAL_dmaControlBlock;
00426 DMA_Init(&dmaInit);
00427 #endif
00428 }
00429
00430
00438 void NVMHAL_DeInit(void)
00439 {
00440 MSC_Deinit();
00441 }
00442
00443
00464 void NVMHAL_Read(uint8_t *pAddress, void *pObject, uint16_t len)
00465 {
00466 #if (NVMHAL_DMAREAD == true)
00467
00468 DMA_CB_TypeDef cb[DMA_CHAN_COUNT];
00469 cb[NVMHAL_DMA_CHANNEL_FLASH].cbFunc = NVM_ReadFromFlashComplete;
00470
00471
00472
00473 cb[NVMHAL_DMA_CHANNEL_FLASH].userPtr = NULL;
00474
00475
00476 DMA_CfgChannel_TypeDef chnlCfg;
00477 chnlCfg.highPri = false;
00478 chnlCfg.enableInt = true;
00479 chnlCfg.select = 0;
00480 chnlCfg.cb = &(cb[NVMHAL_DMA_CHANNEL_FLASH]);
00481 DMA_CfgChannel(NVMHAL_DMA_CHANNEL_FLASH, &chnlCfg);
00482
00483
00484 DMA_CfgDescr_TypeDef descrCfg;
00485 descrCfg.dstInc = dmaDataInc1;
00486 descrCfg.srcInc = dmaDataInc1;
00487 descrCfg.size = dmaDataSize1;
00488 descrCfg.arbRate = dmaArbitrate1;
00489 descrCfg.hprot = 0;
00490 DMA_CfgDescr(NVMHAL_DMA_CHANNEL_FLASH, true, &descrCfg);
00491
00492
00493
00494 NVMHAL_FlashTransferActive = true;
00495
00496
00497 DMA_ActivateAuto(NVMHAL_DMA_CHANNEL_FLASH,
00498 true,
00499 pObject,
00500 pAddress,
00501 len - 1);
00502
00503
00504 INT_Disable();
00505 while (NVMHAL_FlashTransferActive)
00506 {
00507 EMU_EnterEM1();
00508 INT_Enable();
00509 INT_Disable();
00510 }
00511 INT_Enable();
00512 #else
00513
00514 uint8_t *pObjectInt = (uint8_t*) pObject;
00515
00516 while (0 < len)
00517 {
00518
00519 *pObjectInt = *pAddress;
00520
00521 ++pObjectInt;
00522
00523 ++pAddress;
00524
00525 --len;
00526 }
00527 #endif
00528
00529 }
00530
00531
00555 Ecode_t NVMHAL_Write(uint8_t *pAddress, void const *pObject, uint16_t len)
00556 {
00557
00558 msc_Return_TypeDef msc_Return = mscReturnOk;
00559
00560 uint32_t tempWord;
00561
00562
00563 uint8_t *pObjectInt = (uint8_t*) pObject;
00564
00565
00566 uint8_t padLen;
00567
00568
00569 padLen = (uint32_t) pAddress % sizeof(tempWord);
00570
00571 if (padLen != 0)
00572 {
00573 pAddress -= padLen;
00574
00575
00576 tempWord = *(uint32_t *) pObjectInt;
00577
00578 tempWord = tempWord << 8 * padLen;
00579
00580 tempWord |= NVMHAL_FFFFFFFF >> (8 * (sizeof(tempWord) - padLen));
00581
00582
00583 if (len < sizeof(tempWord) - padLen)
00584 {
00585
00586 tempWord |= NVMHAL_FFFFFFFF << (8 * (padLen + len));
00587 len = 0;
00588 }
00589 else
00590 {
00591 len -= sizeof(tempWord) - padLen;
00592 }
00593
00594 #if (NVMHAL_SLEEP_WRITE == true)
00595 msc_Return = NVMHAL_MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
00596 #else
00597 msc_Return = MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
00598 #endif
00599 pObjectInt += sizeof(tempWord) - padLen;
00600 pAddress += sizeof(tempWord);
00601 }
00602
00603
00604 while ((len >= sizeof(tempWord)) && (mscReturnOk == msc_Return))
00605 {
00606 #if (NVMHAL_SLEEP_WRITE == true)
00607 msc_Return = NVMHAL_MSC_WriteWord((uint32_t *) pAddress, pObjectInt, sizeof(tempWord));
00608 #else
00609 msc_Return = MSC_WriteWord((uint32_t *) pAddress, pObjectInt, sizeof(tempWord));
00610 #endif
00611 pAddress += sizeof(tempWord);
00612 pObjectInt += sizeof(tempWord);
00613 len -= sizeof(tempWord);
00614 }
00615
00616
00617 if ((len > 0) && (mscReturnOk == msc_Return))
00618 {
00619
00620 tempWord = *(uint32_t *) pObjectInt;
00621
00622 tempWord |= NVMHAL_FFFFFFFF << (8 * len);
00623
00624 #if (NVMHAL_SLEEP_WRITE == true)
00625 msc_Return = NVMHAL_MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
00626 #else
00627 msc_Return = MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
00628 #endif
00629 }
00630
00631
00632 return NVMHAL_ReturnTypeConvert(msc_Return);
00633 }
00634
00635
00650 #if (NVMHAL_SLEEP == true)
00651 Ecode_t NVMHAL_PageErase(uint8_t *pAddress)
00652 {
00653
00654 return NVMHAL_ReturnTypeConvert(NVMHAL_MSC_ErasePage((uint32_t *) pAddress));
00655 }
00656
00657 #else
00658 Ecode_t NVMHAL_PageErase(uint8_t *pAddress)
00659 {
00660
00661 return NVMHAL_ReturnTypeConvert(MSC_ErasePage((uint32_t *) pAddress));
00662 }
00663 #endif
00664
00665
00688 void NVMHAL_Checksum(uint16_t *pChecksum, void *pMemory, uint16_t len)
00689 {
00690 uint8_t *pointer = (uint8_t *) pMemory;
00691 uint16_t crc = *pChecksum;
00692
00693 while(len--)
00694 {
00695 crc = (crc >> 8) | (crc << 8);
00696 crc ^= *pointer++;
00697 crc ^= (crc & 0xf0) >> 4;
00698 crc ^= (crc & 0x0f) << 12;
00699 crc ^= (crc & 0xff) << 5;
00700 }
00701
00702 *pChecksum = crc;
00703 }