Contiki 2.5
flash.c
Go to the documentation of this file.
1 /** @file hal/micro/cortexm3/flash.c
2  * @brief Implements the generic flash manipulation routines.
3  *
4  * The file 'flash-sw-spec.txt' should provide *all* the information needed
5  * to understand and work with the FLITF and flash.
6  *
7  *
8  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved. -->
9  */
10 
11 #include PLATFORM_HEADER
12 #include "error.h"
14 #include "hal/micro/cortexm3/mpu.h"
15 #include "memmap.h"
16 #include "flash.h"
17 
18 #ifdef FLASH_PROGRAMMING_WITH_EMPTY_FIB
19 #define ST_EMU_TEST
20 #endif
21 // A translation table used to convert FibStatus codes to corresponding
22 // StStatus values
23 static const StStatus fibToStStatus[] = {
24  ST_SUCCESS, // FIB_SUCCESS 0
25  ST_BAD_ARGUMENT, // FIB_ERR_UNALIGNED 1
26  ST_BAD_ARGUMENT, // FIB_ERR_INVALID_ADDRESS 2
27  ST_BAD_ARGUMENT, // FIB_ERR_INVALID_TYPE 3
28  ST_ERR_FLASH_PROG_FAIL, // FIB_ERR_WRITE_PROTECTED 4
29  ST_ERR_FLASH_PROG_FAIL, // FIB_ERR_WRITE_FAILED 5
30  ST_ERR_FLASH_WRITE_INHIBITED, // FIB_ERR_ERASE_REQUIRED 6
31  ST_ERR_FLASH_VERIFY_FAILED // FIB_ERR_VERIFY_FAILED 7
32 };
33 
34 //The purpose of flashEraseIsActive and halFlashEraseIsActive() is so that
35 //interrupts can query the flash library to find out of Flash Erase is
36 //active when their ISR gets invoked. This is useful because Flash Erase
37 //causes the chip to go ATOMIC for 21ms and this delay will disrupt interrupt
38 //latency. By having a sinple API that an ISR can query for this state,
39 //the ISR can appriopriately adjust for a 21ms latency time.
40 boolean flashEraseIsActive = FALSE;
41 boolean halFlashEraseIsActive(void)
42 {
43  return flashEraseIsActive;
44 }
45 
46 
47 // Emulators do not have FIB bootloaders, so need to include a copy of
48 // these core flash routines.
49 
50 #if defined(ST_EMU_TEST)
51 
52 static void enableFlitf(void)
53 {
54  //First, unlock the FLITF by writing the two key values to the Flash
55  //Protection Unlock register
56  FPEC_KEY = FPEC_KEY1;
57  FPEC_KEY = FPEC_KEY2;
58 
59  //Second, unlock the CIB by writing the two key values to the CIB
60  //Protection Unlock register
61  OPT_KEY = FPEC_KEY1;
62  OPT_KEY = FPEC_KEY2;
63 
64  //Turn on the FPEC clock for flash manipulation operations
65  FPEC_CLKREQ = FPEC_CLKREQ_FIELD;
66 
67  //make sure the FPEC clock is running before we proceed
68  while( (FPEC_CLKSTAT&FPEC_CLKACK) != FPEC_CLKACK) {}
69 
70  //just in case, wait until the flash is no longer busy
71  while( (FLASH_STATUS&FLASH_STATUS_FLA_BSY) == FLASH_STATUS_FLA_BSY ) {}
72 }
73 
74 static void disableFlitf(void)
75 {
76  //make sure the FPEC is completely idle before turning off the clock
77  while( (FPEC_CLKSTAT&FPEC_CLKBSY) == FPEC_CLKBSY) {}
78 
79  //Turn off the FPEC clock now that we're done
80  FPEC_CLKREQ = FPEC_CLKREQ_RESET;
81 
82  //Set LOCK and clear OPTWREN to lock both the FLITF and the CIB.
83  //NOTE: The PROG bit must also be cleared otherwise Flash can still
84  // be programmed even with the LOCK bit set. BugzID: 6267
85  FLASH_CTRL = FLASH_CTRL_LOCK; //lock the flash from further accesses
86 }
87 
88 static FibStatus fibFlashWrite(int32u address, int8u *data, int32u length, int32u dummy)
89 {
90  int32u i;
91  int16u *ptr;
92  FibStatus status = FIB_SUCCESS;
93  // Address and length must be half-word aligned.
94  if ((address & 1) || (length & 1)) {
95  return FIB_ERR_UNALIGNED;
96  }
97  // Start and end address must be in MFB or CIB.
98  if (!((address >= MFB_BOTTOM && address + length <= MFB_TOP + 1)
99  || (address >= CIB_BOTTOM && address + length <= CIB_TOP + 1))) {
100  return FIB_ERR_INVALID_ADDRESS;
101  }
102  enableFlitf();
103  ptr = (int16u *)address;
104  for (i = 0; i < length; i += 2) {
105  int16u currentData = *ptr;
106  int16u newData = HIGH_LOW_TO_INT(data[i + 1], data[i]);
107  // Only program the data if it makes sense to do so.
108  if (currentData == newData) {
109  // If the new data matches the flash, don't bother doing anything.
110  } else if (currentData == 0xFFFF || newData == 0x0000) {
111  // If the flash is 0xFFFF we're allowed to write anything.
112  // If the new data is 0x0000 it doesn't matter what the flash is.
113  // OPTWREN must stay set to keep CIB unlocked.
114  if ((CIB_OB_BOTTOM <= (int32u)ptr) && ((int32u)ptr <= CIB_OB_TOP)) {
115  FLASH_CTRL = (FLASH_CTRL_OPTWREN | FLASH_CTRL_OPTPROG);
116  } else {
117  FLASH_CTRL = (FLASH_CTRL_OPTWREN | FLASH_CTRL_PROG);
118  }
119  // Assigning data to the address performs the actual write.
120  (*ptr) = newData;
121  // Wait for the busy bit to clear, indicating operation is done.
122  while ((FLASH_STATUS & FLASH_STATUS_FLA_BSY) != 0) {}
123  // Reset the operation complete flag.
124  FLASH_STATUS = FLASH_STATUS_EOP;
125  // Check if any error bits have been tripped, and if so, exit.
126  // The bit PAGE_PROG_ERR is not relevant in this programming mode.
127  if (FLASH_STATUS & (FLASH_STATUS_WRP_ERR | FLASH_STATUS_PROG_ERR)) {
128  if (FLASH_STATUS & FLASH_STATUS_WRP_ERR) {
129  status = FIB_ERR_WRITE_PROTECTED;
130  } else {
131  status = FIB_ERR_WRITE_FAILED;
132  }
133  FLASH_STATUS = FLASH_STATUS_WRP_ERR;
134  FLASH_STATUS = FLASH_STATUS_PROG_ERR;
135  break;
136  }
137  } else {
138  status = FIB_ERR_ERASE_REQUIRED;
139  break;
140  }
141  ptr++;
142  }
143  disableFlitf();
144  return status;
145 }
146 
147 static FibStatus fibFlashWriteVerify(int32u address, int8u *data, int32u length)
148 {
149  int32u i;
150  int8u *ptr = (int8u *)address;
151  for (i = 0; i < length; i++) {
152  if (*ptr != data[i]) {
153  return FIB_ERR_VERIFY_FAILED;
154  }
155  ptr++;
156  }
157  return FIB_SUCCESS;
158 }
159 
160 static FibStatus fibFlashErase(FibEraseType eraseType, int32u address)
161 {
162  int32u eraseOp;
163  int32u *ptr;
164  int32u length;
165  FibStatus status = FIB_SUCCESS;
166  if (BYTE_0(eraseType) == MFB_MASS_ERASE) {
167  eraseOp = FLASH_CTRL_MASSERASE;
168  ptr = (int32u *)MFB_BOTTOM;
169  length = MFB_SIZE_W;
170  } else if (BYTE_0(eraseType) == MFB_PAGE_ERASE) {
171  if (address < MFB_BOTTOM || address > MFB_TOP) {
172  return FIB_ERR_INVALID_ADDRESS;
173  }
174  eraseOp = FLASH_CTRL_PAGEERASE;
175  ptr = (int32u *)(address & MFB_PAGE_MASK_B);
176  length = MFB_PAGE_SIZE_W;
177  } else if (BYTE_0(eraseType) == CIB_ERASE) {
178  eraseOp = FLASH_CTRL_OPTWREN | FLASH_CTRL_OPTERASE;
179  ptr = (int32u *)CIB_BOTTOM;
180  length = CIB_SIZE_W;
181  } else {
182  return FIB_ERR_INVALID_TYPE;
183  }
184  if ((eraseType & DO_ERASE) != 0) {
185  enableFlitf();
186  FLASH_CTRL = eraseOp;
187  if (BYTE_0(eraseType) == MFB_PAGE_ERASE) {
188  FLASH_ADDR = (address & MFB_PAGE_MASK_B);
189  }
190  eraseOp |= FLASH_CTRL_FLA_START;
191  // Perform the actual erase.
192  FLASH_CTRL = eraseOp;
193  // Wait for the busy bit to clear, indicating operation is done.
194  while ((FLASH_STATUS & FLASH_STATUS_FLA_BSY) != 0) {}
195  // Reset the operation complete flag.
196  FLASH_STATUS = FLASH_STATUS_EOP;
197  // Check for errors; the only relevant one for erasing is write protection.
198  if (FLASH_STATUS & FLASH_STATUS_WRP_ERR) {
199  FLASH_STATUS = FLASH_STATUS_WRP_ERR;
200  status = FIB_ERR_WRITE_PROTECTED;
201  }
202  disableFlitf();
203  }
204  if (status == FIB_SUCCESS
205  && (eraseType & DO_VERIFY) != 0) {
206  int32u i;
207  for (i = 0; i < length; i++) {
208  if (*ptr != 0xFFFFFFFF) {
209  return FIB_ERR_VERIFY_FAILED;
210  }
211  ptr++;
212  }
213  }
214  return status;
215 }
216 #endif // ST_EMU_TEST
217 
218 static boolean verifyFib(void)
219 {
220  // Ensure that a programmed FIB of a proper version is present
221  return ( (halFixedAddressTable.baseTable.type == FIXED_ADDRESS_TABLE_TYPE) &&
222  ( ( (halFixedAddressTable.baseTable.version & FAT_MAJOR_VERSION_MASK)
223  == 0x0000 ) &&
224  (halFixedAddressTable.baseTable.version >= 0x0002)
225  )
226  );
227 }
228 
229 //The parameter 'eraseType' chooses which erasure will be performed while
230 //the 'address' parameter chooses the page to be erased during MFB page erase.
231 StStatus halInternalFlashErase(int8u eraseType, int32u address)
232 {
233  FibStatus status;
234 
235  ATOMIC(
236  BYPASS_MPU(
237  flashEraseIsActive = TRUE;
238  #if defined(ST_EMU_TEST)
239  // Always try to use the FIB bootloader if its present
240  if(verifyFib()) {
241  status = halFixedAddressTable.fibFlashErase(
242  (((int32u)eraseType) | DO_ERASE),
243  address);
244  } else {
245  status = fibFlashErase((((int32u)eraseType) | DO_ERASE), address);
246  }
247  #else
248 
249 
250 
251  assert(verifyFib());
252  status = halFixedAddressTable.fibFlashErase(
253  (((int32u)eraseType) | DO_ERASE),
254  address);
255  #endif
256  )
257  )
258  //If there are any interrupts pending that could have been delayed for 21ms,
259  //they will be serviced here since we exit the ATOMIC block. These ISRs
260  //can query the flash library and find out that erasing is active. After
261  //this point, we're no longer ATOMIC/disrupting latency so our erase
262  //active flag should be cleared.
263  flashEraseIsActive = FALSE;
264 
265  if(status!=FIB_SUCCESS) {
266  return fibToStStatus[status];
267  }
268 
269  #if defined(ST_EMU_TEST)
270  // Always try to use the FIB bootloader if its present
271  if(verifyFib()) {
272  status = halFixedAddressTable.fibFlashErase(
273  (((int32u)eraseType) | DO_VERIFY),
274  address);
275  } else {
276  status = fibFlashErase((((int32u)eraseType) | DO_VERIFY), address);
277  }
278  #else
279  status = halFixedAddressTable.fibFlashErase(
280  (((int32u)eraseType) | DO_VERIFY),
281  address);
282  #endif
283  return fibToStStatus[status];
284 }
285 
286 
287 //The parameter 'address' defines the starting address of where the
288 //programming will occur - this parameter MUST be half-word aligned since all
289 //programming operations are HW. The parameter 'data' is a pointer to a buffer
290 //containin the 16bit half-words to be written. Length is the number of 16bit
291 //half-words contained in 'data' to be written to flash.
292 //NOTE: This function can NOT write the option bytes and will throw an error
293 //if that is attempted.
294 StStatus halInternalFlashWrite(int32u address, int16u * data, int32u length)
295 {
296  FibStatus status;
297 
298  length = length * 2; // fib routines specify length in bytes
299 
300  ATOMIC(
301  BYPASS_MPU(
302  #if defined(ST_EMU_TEST)
303  // Always try to use the FIB bootloader if its present
304  if(verifyFib()) {
305  status = halFixedAddressTable.fibFlashWrite(address,
306  (int8u *)data,
307  length,
308  0);
309  } else {
310  status = fibFlashWrite(address, (int8u *)data, length, 0);
311  }
312  #else
313 
314 
315 
316  // Ensure that a programmed FIB of a proper version is present
317  assert(verifyFib());
318  status = halFixedAddressTable.fibFlashWrite(address,
319  (int8u *)data,
320  length,
321  0);
322  #endif
323  )
324  )
325 
326  if(status!=FIB_SUCCESS) {
327  return fibToStStatus[status];
328  }
329 
330  #if defined(ST_EMU_TEST)
331  // Always try to use the FIB bootloader if its present
332  if(verifyFib()) {
333  status = halFixedAddressTable.fibFlashWrite(address,
334  (int8u *)data,
335  0,
336  length);
337  } else {
338  status = fibFlashWriteVerify(address, (int8u *)data, length);
339  }
340  #else
341  status = halFixedAddressTable.fibFlashWrite(address,
342  (int8u *)data,
343  0,
344  length);
345  #endif
346 
347  return fibToStStatus[status];
348 }
349 
350 
351 //The parameter 'byte' is the option byte number to be programmed. This
352 //parameter can have a value of 0 through 7. 'data' is the 8bit value to be
353 //programmed into the option byte since the hardware will calculate the
354 //compliment and program the full 16bit option byte.
355 StStatus halInternalCibOptionByteWrite(int8u byte, int8u data)
356 {
357  int16u dataAndInverse = HIGH_LOW_TO_INT(~data, data);
358  // There are only 8 option bytes, don't try to program more than that.
359  if (byte > 7) {
360  return ST_ERR_FLASH_PROG_FAIL;
361  }
362  return halInternalFlashWrite(CIB_OB_BOTTOM + (byte << 1), &dataAndInverse, 1);
363 }
364 
365