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