EFM32 Wonder Gecko Software Documentation  efm32wg-doc-4.2.1
nvm_hal.c
Go to the documentation of this file.
1 /***************************************************************************/
16 #include <stdbool.h>
17 #include "em_msc.h"
18 #include "nvm.h"
19 #include "nvm_hal.h"
20 
21 
22 /*******************************************************************************
23  ****************************** CONSTANTS **********************************
24  ******************************************************************************/
25 
28 /* Padding value */
29 #define NVMHAL_FFFFFFFF 0xffffffffUL
30 
34 /*******************************************************************************
35  *************************** LOCAL FUNCTIONS *******************************
36  ******************************************************************************/
37 
41 /**************************************************************************/
46 static uint32_t readUnalignedWord(uint8_t *addr)
47 {
48  /* Check if the unaligned access trap is enabled */
49  if (SCB->CCR & SCB_CCR_UNALIGN_TRP_Msk)
50  {
51  /* Read word as bytes (always aligned) */
52  return (*(addr + 3) << 24) | (*(addr + 2) << 16) | (*(addr + 1) << 8) | *addr;
53  }
54  else
55  {
56  /* Use unaligned access */
57  return *(uint32_t *)addr;
58  }
59 }
60 
61 
62 /***************************************************************************/
76 static Ecode_t returnTypeConvert(MSC_Status_TypeDef result)
77 {
78  /* Direct return from switch gives smallest code size (smaller than if-else).
79  * Could try using an offset value to translate. */
80  switch (result)
81  {
82  case mscReturnOk:
83  return ECODE_EMDRV_NVM_OK;
84 
87 
88  case mscReturnUnaligned:
90 
91  default:
92  return ECODE_EMDRV_NVM_ERROR;
93  }
94 }
95 
98 /*******************************************************************************
99  ************************** GLOBAL FUNCTIONS *******************************
100  ******************************************************************************/
101 
102 /***************************************************************************/
111 void NVMHAL_Init(void)
112 {
113  MSC_Init();
114 }
115 
116 
117 /***************************************************************************/
125 void NVMHAL_DeInit(void)
126 {
127  MSC_Deinit();
128 }
129 
130 
131 /***************************************************************************/
152 void NVMHAL_Read(uint8_t *pAddress, void *pObject, uint16_t len)
153 {
154  /* Create a pointer to the void* pBuffer with type for easy movement. */
155  uint8_t *pObjectInt = (uint8_t*) pObject;
156 
157  while (0 < len) /* While there is more data to fetch. */
158  {
159  /* Move the data from memory to the buffer. */
160  *pObjectInt = *pAddress;
161  /* Move active location in buffer, */
162  ++pObjectInt;
163  /* and in memory. */
164  ++pAddress;
165  /* More data is read. */
166  --len;
167  }
168 }
169 
170 
171 /***************************************************************************/
191 Ecode_t NVMHAL_Write(uint8_t *pAddress, void const *pObject, uint16_t len)
192 {
193  /* Used to carry return data. */
194  MSC_Status_TypeDef mscStatus = mscReturnOk;
195  /* Used as a temporary variable to create the blocks to write when padding to closest word. */
196  uint32_t tempWord;
197 
198  /* Pointer to let us traverse the given pObject by single bytes. */
199  uint8_t *pObjectInt = (uint8_t*)pObject;
200 
201  /* Temporary variable to cache length of padding needed. */
202  uint8_t padLen;
203 
204  /* Get length of pad in front. */
205  padLen = (uint32_t) pAddress % sizeof(tempWord);
206 
207  if (padLen != 0)
208  {
209  /* Get first word. */
210  tempWord = readUnalignedWord((uint8_t *)pObject);
211 
212  /* Shift to offset. */
213  tempWord = tempWord << 8 * padLen;
214  /* Add nochanging padding. */
215  tempWord |= NVMHAL_FFFFFFFF >> (8 * (sizeof(tempWord) - padLen));
216 
217  /* Special case for unaligned writes smaller than 1 word. */
218  if (len < sizeof(tempWord) - padLen)
219  {
220  /* Add nochanging padding. */
221  tempWord |= NVMHAL_FFFFFFFF << (8 * (padLen + len));
222  len = 0;
223  }
224  else
225  {
226  len -= sizeof(tempWord) - padLen;
227  }
228 
229  /* Align the NVM write address */
230  pAddress -= padLen;
231  mscStatus = MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
232 
233  pObjectInt += sizeof(tempWord) - padLen;
234  pAddress += sizeof(tempWord);
235  }
236 
237 
238  /* Loop over body. */
239  while ((len >= sizeof(tempWord)) && (mscReturnOk == mscStatus))
240  {
241  tempWord = readUnalignedWord((uint8_t *)pObjectInt);
242  mscStatus = MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
243 
244  pAddress += sizeof(tempWord);
245  pObjectInt += sizeof(tempWord);
246  len -= sizeof(tempWord);
247  }
248 
249  /* Pad at the end */
250  if ((len > 0) && (mscReturnOk == mscStatus))
251  {
252  /* Get final word. */
253  tempWord = readUnalignedWord((uint8_t *)pObjectInt);
254 
255  /* Fill rest of word with padding. */
256  tempWord |= NVMHAL_FFFFFFFF << (8 * len);
257  mscStatus = MSC_WriteWord((uint32_t *) pAddress, &tempWord, sizeof(tempWord));
258  }
259 
260  /* Convert between return types, and return. */
261  return returnTypeConvert(mscStatus);
262 }
263 
264 
265 /***************************************************************************/
278 Ecode_t NVMHAL_PageErase(uint8_t *pAddress)
279 {
280  /* Call underlying library and convert between return types, and return. */
281  return returnTypeConvert(MSC_ErasePage((uint32_t *) pAddress));
282 }
283 
284 
285 /***************************************************************************/
308 void NVMHAL_Checksum(uint16_t *pChecksum, void *pMemory, uint16_t len)
309 {
310  uint8_t *pointer = (uint8_t *) pMemory;
311  uint16_t crc = *pChecksum;
312 
313  while(len--)
314  {
315  crc = (crc >> 8) | (crc << 8);
316  crc ^= *pointer++;
317  crc ^= (crc & 0xf0) >> 4;
318  crc ^= (crc & 0x0f) << 12;
319  crc ^= (crc & 0xff) << 5;
320  }
321  *pChecksum = crc;
322 }
void NVMHAL_Read(uint8_t *pAddress, void *pObject, uint16_t len)
Read data from NVM.
Definition: nvm_hal.c:152
void NVMHAL_Init(void)
Initialize NVM driver.
Definition: nvm_hal.c:111
Ecode_t NVMHAL_PageErase(uint8_t *pAddress)
Erase a page in the NVM.
Definition: nvm_hal.c:278
void MSC_Init(void)
Enables the flash controller for writing.
Definition: em_msc.c:101
void MSC_Deinit(void)
Disables the flash controller for writing.
Definition: em_msc.c:153
Non-Volatile Memory Wear-Leveling driver API.
Flash controller module (MSC) peripheral API.
void NVMHAL_Checksum(uint16_t *pChecksum, void *pMemory, uint16_t len)
Calculate checksum according to CCITT CRC16.
Definition: nvm_hal.c:308
MSC_FUNC_PREFIX MSC_Status_TypeDef MSC_ErasePage(uint32_t *startAddress) MSC_FUNC_POSTFIX
Erases a page in flash memory.
Definition: em_msc.c:637
#define ECODE_EMDRV_NVM_ERROR
General error.
Definition: nvm.h:55
void NVMHAL_DeInit(void)
De-initialize NVM .
Definition: nvm_hal.c:125
#define ECODE_EMDRV_NVM_ADDR_INVALID
Invalid address.
Definition: nvm.h:49
MSC_Status_TypeDef
Definition: em_msc.h:97
#define ECODE_EMDRV_NVM_OK
Success return value.
Definition: nvm.h:48
Non-Volatile Memory Wear-Leveling driver HAL.
#define ECODE_EMDRV_NVM_ALIGNMENT_INVALID
Invalid data alignment.
Definition: nvm.h:50
uint32_t Ecode_t
Typedef for API function errorcode return values.
Definition: ecode.h:31
MSC_FUNC_PREFIX MSC_Status_TypeDef MSC_WriteWord(uint32_t *address, void const *data, uint32_t numBytes) MSC_FUNC_POSTFIX
Writes data to flash memory. This function is interrupt safe, but slower than MSC_WriteWordFast(), which writes to flash with interrupts disabled. Write data must be aligned to words and contain a number of bytes that is divisable by four.
Definition: em_msc.c:738
Ecode_t NVMHAL_Write(uint8_t *pAddress, void const *pObject, uint16_t len)
Write data to NVM.
Definition: nvm_hal.c:191