1 /***************************************************************************//**
2 * @file
3 * @brief Flash controller (MSC) Peripheral API
4 * @author Energy Micro AS
5 * @version 3.0.0
6 *******************************************************************************
7 * @section License
8 * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
9 *******************************************************************************
10 *
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
14 *
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
20 *
21 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
22 * obligation to support this Software. Energy Micro AS is providing the
23 * Software "AS IS", with no express or implied warranties of any kind,
24 * including, but not limited to, any implied warranties of merchantability
25 * or fitness for any particular purpose or warranties against infringement
26 * of any proprietary rights of a third party.
27 *
28 * Energy Micro AS will not be liable for any consequential, incidental, or
29 * special damages, or any other relief, or for any claim by any third party,
30 * arising from your use of this Software.
31 *
32 ******************************************************************************/
33 #include "em_msc.h"
34 #if defined (_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
35 #include "em_cmu.h"
36 #endif
37 #include "em_assert.h"
38
39 /***************************************************************************//**
40 * @addtogroup EM_Library
41 * @{
42 ******************************************************************************/
43
44 /***************************************************************************//**
45 * @addtogroup MSC
46 * @brief Flash controller (MSC) Peripheral API
47 * @{
48 ******************************************************************************/
49
50 /*******************************************************************************
51 ************************** GLOBAL FUNCTIONS *******************************
52 ******************************************************************************/
53
54 /***************************************************************************//**
55 * @brief
56 * Enables the flash controller for writing.
57 * @note
58 * IMPORTANT: This function must be called before flash operations when
59 * AUXHFRCO clock has been changed from default 14MHz band.
60 ******************************************************************************/
MSC_Init(void)61 void MSC_Init(void)
62 {
63 #if defined (_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
64 uint32_t freq, cycles;
65 #endif
66 /* Enable writing to the MSC */
67 MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
68 /* Unlock the MSC */
69 MSC->LOCK = MSC_UNLOCK_CODE;
70 /* Disable writing to the MSC */
71 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
72
73 #if defined (_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY)
74 /* Configure MSC->TIMEBASE according to selected frequency */
75 freq = CMU_ClockFreqGet(cmuClock_AUX);
76
77 if( freq > 7000000)
78 {
79 /* Calculate number of clock cycles for 1us as base period */
80 freq = (freq * 11) / 10;
81 cycles = (freq / 1000000) + 1;
82
83 /* Configure clock cycles for flash timing */
84 MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK|
85 _MSC_TIMEBASE_PERIOD_MASK))|
86 MSC_TIMEBASE_PERIOD_1US|
87 (cycles << _MSC_TIMEBASE_BASE_SHIFT);
88 }
89 else
90 {
91 /* Calculate number of clock cycles for 5us as base period */
92 freq = (freq * 5 * 11) / 10;
93 cycles = (freq / 1000000) + 1;
94
95 /* Configure clock cycles for flash timing */
96 MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK|
97 _MSC_TIMEBASE_PERIOD_MASK))|
98 MSC_TIMEBASE_PERIOD_5US|
99 (cycles << _MSC_TIMEBASE_BASE_SHIFT);
100 }
101 #endif
102 }
103
104 /***************************************************************************//**
105 * @brief
106 * Disables the flash controller for writing.
107 ******************************************************************************/
MSC_Deinit(void)108 void MSC_Deinit(void)
109 {
110 /* Enable writing to the MSC */
111 MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
112 /* Lock the MSC */
113 MSC->LOCK = 0;
114 /* Disable writing to the MSC */
115 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
116 }
117
118 /***************************************************************************//**
119 * @brief
120 * Erases a page in flash memory.
121 * @note
122 * This function MUST be executed from RAM. Failure to execute this portion
123 * of the code in RAM will result in a hardfault. For IAR, Rowley and
124 * Codesourcery this will be achieved automatically. For Keil uVision 4 you
125 * must define a section called "ram_code" and place this manually in your
126 * project's scatter file.
127 * @param[in] startAddress
128 * Pointer to the flash page to erase. Must be aligned to beginning of page
129 * boundary.
130 * @return
131 * Returns the status of erase operation, #msc_Return_TypeDef
132 * @verbatim
133 * flashReturnOk - Operation completed successfully.
134 * flashReturnInvalidAddr - Operation tried to erase a non-flash area.
135 * flashReturnLocked - Operation tried to erase a locked area of the flash.
136 * flashReturnTimeOut - Operation timed out waiting for flash operation
137 * to complete.
138 * @endverbatim
139 ******************************************************************************/
140 #ifdef __CC_ARM /* MDK-ARM compiler */
141 #pragma arm section code="ram_code"
142 #endif /* __CC_ARM */
143 #if defined( __ICCARM__ )
144 /* Suppress warnings originating from use of EFM_ASSERT(): */
145 /* "Call to a non __ramfunc function from within a __ramfunc function" */
146 /* "Possible rom access from within a __ramfunc function" */
147 #pragma diag_suppress=Ta022
148 #pragma diag_suppress=Ta023
149 #endif
MSC_ErasePage(uint32_t * startAddress)150 msc_Return_TypeDef MSC_ErasePage(uint32_t *startAddress)
151 {
152 int timeOut = MSC_PROGRAM_TIMEOUT;
153
154 /* Address must be aligned to pages */
155 EFM_ASSERT((((uint32_t)startAddress) & 0x1FF) == 0);
156
157 /* Enable writing to the MSC */
158 MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
159
160 /* Load address */
161 MSC->ADDRB = (uint32_t)startAddress;
162 MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
163
164 /* Check for invalid address */
165 if (MSC->STATUS & MSC_STATUS_INVADDR)
166 {
167 /* Disable writing to the MSC */
168 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
169 return mscReturnInvalidAddr;
170 }
171
172 /* Check for write protected page */
173 if (MSC->STATUS & MSC_STATUS_LOCKED)
174 {
175 /* Disable writing to the MSC */
176 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
177 return mscReturnLocked;
178 }
179
180 /* Send erase page command */
181 MSC->WRITECMD = MSC_WRITECMD_ERASEPAGE;
182
183 /* Wait for the erase to complete */
184 while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0))
185 {
186 timeOut--;
187 }
188
189 if (timeOut == 0)
190 {
191 /* Disable writing to the MSC */
192 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
193 return mscReturnTimeOut;
194 }
195
196 /* Disable writing to the MSC */
197 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
198 return mscReturnOk;
199 }
200 #if defined( __ICCARM__ )
201 #pragma diag_default=Ta022
202 #pragma diag_default=Ta023
203 #endif
204
205 /***************************************************************************//**
206 * @brief
207 * Writes a single word to flash memory. Data to write must be aligned to
208 * words and contain a number of bytes that is divisable by four.
209 * @note
210 * The flash must be erased prior to writing a new word.
211 * This function must be run from RAM. Failure to execute this portion
212 * of the code in RAM will result in a hardfault. For IAR, Rowley and
213 * Codesourcery this will be achieved automatically. For Keil uVision 4 you
214 * must define a section called "ram_code" and place this manually in your
215 * project's scatter file.
216 *
217 * @param[in] address
218 * Pointer to the flash word to write to. Must be aligned to words.
219 * @param[in] data
220 * Data to write to flash.
221 * @param[in] numBytes
222 * Number of bytes to write from flash. NB: Must be divisable by four.
223 * @return
224 * Returns the status of the write operation, #msc_Return_TypeDef
225 * @verbatim
226 * flashReturnOk - Operation completed successfully.
227 * flashReturnInvalidAddr - Operation tried to erase a non-flash area.
228 * flashReturnLocked - Operation tried to erase a locked area of the flash.
229 * flashReturnTimeOut - Operation timed out waiting for flash operation
230 * to complete.
231 * @endverbatim
232 ******************************************************************************/
233 #ifdef __CC_ARM /* MDK-ARM compiler */
234 #pragma arm section code="ram_code"
235 #endif /* __CC_ARM */
236 #if defined( __ICCARM__ )
237 /* Suppress warnings originating from use of EFM_ASSERT(): */
238 /* "Call to a non __ramfunc function from within a __ramfunc function" */
239 /* "Possible rom access from within a __ramfunc function" */
240 #pragma diag_suppress=Ta022
241 #pragma diag_suppress=Ta023
242 #endif
MSC_WriteWord(uint32_t * address,void const * data,int numBytes)243 msc_Return_TypeDef MSC_WriteWord(uint32_t *address, void const *data, int numBytes)
244 {
245 int timeOut;
246 int wordCount;
247 int numWords;
248
249 /* Check alignment (Must be aligned to words) */
250 EFM_ASSERT(((uint32_t) address & 0x3) == 0);
251
252 /* Check number of bytes. Must be divisable by four */
253 EFM_ASSERT((numBytes & 0x3) == 0);
254
255 /* Enable writing to the MSC */
256 MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
257
258 /* Convert bytes to words */
259 numWords = numBytes >> 2;
260
261 for (wordCount = 0; wordCount < numWords; wordCount++)
262 {
263 /* Load address */
264 MSC->ADDRB = (uint32_t)(address + wordCount);
265 MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
266
267 /* Check for invalid address */
268 if (MSC->STATUS & MSC_STATUS_INVADDR)
269 {
270 /* Disable writing to the MSC */
271 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
272 return mscReturnInvalidAddr;
273 }
274
275 /* Check for write protected page */
276 if (MSC->STATUS & MSC_STATUS_LOCKED)
277 {
278 /* Disable writing to the MSC */
279 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
280 return mscReturnLocked;
281 }
282
283 /* Wait for the MSC to be ready for a new data word */
284 /* Due to the timing of this function, the MSC should already by ready */
285 timeOut = MSC_PROGRAM_TIMEOUT;
286 while (((MSC->STATUS & MSC_STATUS_WDATAREADY) == 0) && (timeOut != 0))
287 {
288 timeOut--;
289 }
290
291 /* Check for timeout */
292 if (timeOut == 0)
293 {
294 /* Disable writing to the MSC */
295 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
296 return mscReturnTimeOut;
297 }
298
299 /* Load data into write data register */
300 MSC->WDATA = *(((uint32_t *)data) + wordCount);
301
302 /* Trigger write once */
303 MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
304
305 /* Wait for the write to complete */
306 timeOut = MSC_PROGRAM_TIMEOUT;
307 while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0))
308 {
309 timeOut--;
310 }
311
312 /* Check for timeout */
313 if (timeOut == 0)
314 {
315 /* Disable writing to the MSC */
316 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
317 return mscReturnTimeOut;
318 }
319 }
320 /* Disable writing to the MSC */
321 MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
322 return mscReturnOk;
323 }
324 #if defined( __ICCARM__ )
325 #pragma diag_default=Ta022
326 #pragma diag_default=Ta023
327 #endif
328
329
330 #if defined(_EFM32_GIANT_FAMILY)
331 /***************************************************************************//**
332 * @brief
333 * Erase entire flash in one operation
334 * @note
335 * This command will erase the entire contents of the device.
336 * Use with care, both a debug session and all contents of the flash will be
337 * lost. The lock bit, MLW will prevent this operation from executing and
338 * might prevent successful mass erase.
339 ******************************************************************************/
340 #ifdef __CC_ARM /* MDK-ARM compiler */
341 #pragma arm section code="ram_code"
342 #endif /* __CC_ARM */
MSC_MassErase(void)343 msc_Return_TypeDef MSC_MassErase(void)
344 {
345 /* Enable writing to the MSC */
346 MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
347
348 /* Unlock device mass erase */
349 MSC->MASSLOCK = MSC_MASSLOCK_LOCKKEY_UNLOCK;
350
351 /* Erase first 512K block */
352 MSC->WRITECMD = MSC_WRITECMD_ERASEMAIN0;
353
354 /* Waiting for erase to complete */
355 while ((MSC->STATUS & MSC_STATUS_BUSY)){}
356
357 #if FLASH_SIZE >= (512*1024)
358 /* Erase second 512K block */
359 MSC->WRITECMD = MSC_WRITECMD_ERASEMAIN1;
360
361 /* Waiting for erase to complete */
362 while ((MSC->STATUS & MSC_STATUS_BUSY)){}
363 #endif
364
365 /* Restore mass erase lock */
366 MSC->MASSLOCK = MSC_MASSLOCK_LOCKKEY_LOCK;
367
368 /* This will only successfully return if calling function is also in SRAM */
369 return mscReturnOk;
370 }
371 #endif
372
373 /** @} (end addtogroup MSC) */
374 /** @} (end addtogroup EM_Library) */
375