aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/hal/ports/STM32/STM32L4xx/hal_efl_lld.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios/os/hal/ports/STM32/STM32L4xx/hal_efl_lld.c')
-rw-r--r--lib/chibios/os/hal/ports/STM32/STM32L4xx/hal_efl_lld.c542
1 files changed, 542 insertions, 0 deletions
diff --git a/lib/chibios/os/hal/ports/STM32/STM32L4xx/hal_efl_lld.c b/lib/chibios/os/hal/ports/STM32/STM32L4xx/hal_efl_lld.c
new file mode 100644
index 000000000..7c534e762
--- /dev/null
+++ b/lib/chibios/os/hal/ports/STM32/STM32L4xx/hal_efl_lld.c
@@ -0,0 +1,542 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file hal_efl_lld.c
19 * @brief STM32L4xx Embedded Flash subsystem low level driver source.
20 *
21 * @addtogroup HAL_EFL
22 * @{
23 */
24
25#include <string.h>
26
27#include "hal.h"
28
29#if (HAL_USE_EFL == TRUE) || defined(__DOXYGEN__)
30
31/*===========================================================================*/
32/* Driver local definitions. */
33/*===========================================================================*/
34
35#define STM32_FLASH_SECTOR_SIZE 2048U
36#define STM32_FLASH_LINE_SIZE 8U
37#define STM32_FLASH_LINE_MASK (STM32_FLASH_LINE_SIZE - 1U)
38
39#define FLASH_PDKEY1 0x04152637U
40#define FLASH_PDKEY2 0xFAFBFCFDU
41
42#define FLASH_KEY1 0x45670123U
43#define FLASH_KEY2 0xCDEF89ABU
44
45#define FLASH_OPTKEY1 0x08192A3BU
46#define FLASH_OPTKEY2 0x4C5D6E7FU
47
48/*===========================================================================*/
49/* Driver exported variables. */
50/*===========================================================================*/
51
52/**
53 * @brief EFL1 driver identifier.
54 */
55EFlashDriver EFLD1;
56
57/*===========================================================================*/
58/* Driver local variables and types. */
59/*===========================================================================*/
60
61static const flash_descriptor_t efl_lld_descriptor = {
62 .attributes = FLASH_ATTR_ERASED_IS_ONE |
63 FLASH_ATTR_MEMORY_MAPPED |
64 FLASH_ATTR_ECC_CAPABLE |
65 FLASH_ATTR_ECC_ZERO_LINE_CAPABLE,
66 .page_size = STM32_FLASH_LINE_SIZE,
67 .sectors_count = STM32_FLASH_NUMBER_OF_BANKS *
68 STM32_FLASH_SECTORS_PER_BANK,
69 .sectors = NULL,
70 .sectors_size = STM32_FLASH_SECTOR_SIZE,
71 .address = (uint8_t *)0x08000000U,
72 .size = STM32_FLASH_NUMBER_OF_BANKS *
73 STM32_FLASH_SECTORS_PER_BANK *
74 STM32_FLASH_SECTOR_SIZE
75};
76
77/*===========================================================================*/
78/* Driver local functions. */
79/*===========================================================================*/
80
81static inline void stm32_flash_lock(EFlashDriver *eflp) {
82
83 eflp->flash->CR |= FLASH_CR_LOCK;
84}
85
86static inline void stm32_flash_unlock(EFlashDriver *eflp) {
87
88 eflp->flash->KEYR |= FLASH_KEY1;
89 eflp->flash->KEYR |= FLASH_KEY2;
90}
91
92static inline void stm32_flash_enable_pgm(EFlashDriver *eflp) {
93
94 eflp->flash->CR |= FLASH_CR_PG;
95}
96
97static inline void stm32_flash_disable_pgm(EFlashDriver *eflp) {
98
99 eflp->flash->CR &= ~FLASH_CR_PG;
100}
101
102static inline void stm32_flash_clear_status(EFlashDriver *eflp) {
103
104 eflp->flash->SR = 0x0000FFFFU;
105}
106
107static inline void stm32_flash_wait_busy(EFlashDriver *eflp) {
108
109 /* Wait for busy bit clear.*/
110 while ((eflp->flash->SR & FLASH_SR_BSY) != 0U) {
111 }
112}
113
114static inline flash_error_t stm32_flash_check_errors(EFlashDriver *eflp) {
115 uint32_t sr = eflp->flash->SR;
116
117 /* Clearing error conditions.*/
118 eflp->flash->SR = sr & 0x0000FFFFU;
119
120 /* Some errors are only caught by assertion.*/
121 osalDbgAssert((sr & (FLASH_SR_FASTERR |
122 FLASH_SR_MISERR |
123 FLASH_SR_SIZERR)) == 0U, "unexpected flash error");
124
125 /* Decoding relevant errors.*/
126 if ((sr & FLASH_SR_WRPERR) != 0U) {
127 return FLASH_ERROR_HW_FAILURE;
128 }
129
130 if ((sr & (FLASH_SR_PGAERR | FLASH_SR_PROGERR | FLASH_SR_OPERR)) != 0U) {
131 return eflp->state == FLASH_PGM ? FLASH_ERROR_PROGRAM : FLASH_ERROR_ERASE;
132 }
133
134 return FLASH_NO_ERROR;
135}
136
137/*===========================================================================*/
138/* Driver interrupt handlers. */
139/*===========================================================================*/
140
141/*===========================================================================*/
142/* Driver exported functions. */
143/*===========================================================================*/
144
145/**
146 * @brief Low level Embedded Flash driver initialization.
147 *
148 * @notapi
149 */
150void efl_lld_init(void) {
151
152 /* Driver initialization.*/
153 eflObjectInit(&EFLD1);
154 EFLD1.flash = FLASH;
155}
156
157/**
158 * @brief Configures and activates the Embedded Flash peripheral.
159 *
160 * @param[in] eflp pointer to a @p EFlashDriver structure
161 *
162 * @notapi
163 */
164void efl_lld_start(EFlashDriver *eflp) {
165
166 stm32_flash_unlock(eflp);
167 FLASH->CR = 0x00000000U;
168}
169
170/**
171 * @brief Deactivates the Embedded Flash peripheral.
172 *
173 * @param[in] eflp pointer to a @p EFlashDriver structure
174 *
175 * @notapi
176 */
177void efl_lld_stop(EFlashDriver *eflp) {
178
179 stm32_flash_lock(eflp);
180}
181
182/**
183 * @brief Gets the flash descriptor structure.
184 *
185 * @param[in] ip pointer to a @p EFlashDriver instance
186 * @return A flash device descriptor.
187 *
188 * @notapi
189 */
190const flash_descriptor_t *efl_lld_get_descriptor(void *instance) {
191
192 (void)instance;
193
194 return &efl_lld_descriptor;
195}
196
197/**
198 * @brief Read operation.
199 *
200 * @param[in] ip pointer to a @p EFlashDriver instance
201 * @param[in] offset flash offset
202 * @param[in] n number of bytes to be read
203 * @param[out] rp pointer to the data buffer
204 * @return An error code.
205 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
206 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
207 * @retval FLASH_ERROR_READ if the read operation failed.
208 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
209 *
210 * @notapi
211 */
212flash_error_t efl_lld_read(void *instance, flash_offset_t offset,
213 size_t n, uint8_t *rp) {
214 EFlashDriver *devp = (EFlashDriver *)instance;
215 flash_error_t err = FLASH_NO_ERROR;
216
217 osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
218 osalDbgCheck((size_t)offset + n <= (size_t)efl_lld_descriptor.size);
219 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
220 "invalid state");
221
222 /* No reading while erasing.*/
223 if (devp->state == FLASH_ERASE) {
224 return FLASH_BUSY_ERASING;
225 }
226
227 /* FLASH_READY state while the operation is performed.*/
228 devp->state = FLASH_READ;
229
230 /* Clearing error status bits.*/
231 stm32_flash_clear_status(devp);
232
233 /* Actual read implementation.*/
234 memcpy((void *)rp, (const void *)efl_lld_descriptor.address + offset, n);
235
236 /* Checking for errors after reading.*/
237 if ((devp->flash->SR & FLASH_SR_RDERR) != 0U) {
238 err = FLASH_ERROR_READ;
239 }
240
241 /* Ready state again.*/
242 devp->state = FLASH_READY;
243
244 return err;
245
246}
247
248/**
249 * @brief Program operation.
250 * @note The device supports ECC, it is only possible to write erased
251 * pages once except when writing all zeroes.
252 *
253 * @param[in] ip pointer to a @p EFlashDriver instance
254 * @param[in] offset flash offset
255 * @param[in] n number of bytes to be programmed
256 * @param[in] pp pointer to the data buffer
257 * @return An error code.
258 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
259 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
260 * @retval FLASH_ERROR_PROGRAM if the program operation failed.
261 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
262 *
263 * @notapi
264 */
265flash_error_t efl_lld_program(void *instance, flash_offset_t offset,
266 size_t n, const uint8_t *pp) {
267 EFlashDriver *devp = (EFlashDriver *)instance;
268 flash_error_t err = FLASH_NO_ERROR;
269
270 osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U));
271 osalDbgCheck((size_t)offset + n <= (size_t)efl_lld_descriptor.size);
272
273 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
274 "invalid state");
275
276 /* No programming while erasing.*/
277 if (devp->state == FLASH_ERASE) {
278 return FLASH_BUSY_ERASING;
279 }
280
281 /* FLASH_PGM state while the operation is performed.*/
282 devp->state = FLASH_PGM;
283
284 /* Clearing error status bits.*/
285 stm32_flash_clear_status(devp);
286
287 /* Enabling PGM mode in the controller.*/
288 stm32_flash_enable_pgm(devp);
289
290 /* Actual program implementation.*/
291 while (n > 0U) {
292 volatile uint32_t *address;
293
294 union {
295 uint32_t w[STM32_FLASH_LINE_SIZE / sizeof (uint32_t)];
296 uint8_t b[STM32_FLASH_LINE_SIZE / sizeof (uint8_t)];
297 } line;
298
299 /* Unwritten bytes are initialized to all ones.*/
300 line.w[0] = 0xFFFFFFFFU;
301 line.w[1] = 0xFFFFFFFFU;
302
303 /* Programming address aligned to flash lines.*/
304 address = (volatile uint32_t *)(efl_lld_descriptor.address +
305 (offset & ~STM32_FLASH_LINE_MASK));
306
307 /* Copying data inside the prepared line.*/
308 do {
309 line.b[offset & STM32_FLASH_LINE_MASK] = *pp;
310 offset++;
311 n--;
312 pp++;
313 }
314 while ((n > 0U) & ((offset & STM32_FLASH_LINE_MASK) != 0U));
315
316 /* Programming line.*/
317 address[0] = line.w[0];
318 address[1] = line.w[1];
319 stm32_flash_wait_busy(devp);
320 err = stm32_flash_check_errors(devp);
321 if (err != FLASH_NO_ERROR) {
322 break;
323 }
324 }
325
326 /* Disabling PGM mode in the controller.*/
327 stm32_flash_disable_pgm(devp);
328
329 /* Ready state again.*/
330 devp->state = FLASH_READY;
331
332 return err;
333}
334
335/**
336 * @brief Starts a whole-device erase operation.
337 * @note This function only erases bank 2 if it is present. Bank 1 is not
338 * touched because it is where the program is running on.
339 * Pages on bank 1 can be individually erased.
340 *
341 * @param[in] ip pointer to a @p EFlashDriver instance
342 * @return An error code.
343 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
344 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
345 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
346 *
347 * @notapi
348 */
349flash_error_t efl_lld_start_erase_all(void *instance) {
350 EFlashDriver *devp = (EFlashDriver *)instance;
351
352 osalDbgCheck(instance != NULL);
353 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
354 "invalid state");
355
356 /* No erasing while erasing.*/
357 if (devp->state == FLASH_ERASE) {
358 return FLASH_BUSY_ERASING;
359 }
360
361 /* FLASH_PGM state while the operation is performed.*/
362 devp->state = FLASH_ERASE;
363
364 /* Clearing error status bits.*/
365 stm32_flash_clear_status(devp);
366
367#if defined(FLASH_CR_MER2)
368 devp->flash->CR |= FLASH_CR_MER2;
369 devp->flash->CR |= FLASH_CR_STRT;
370#endif
371
372 return FLASH_NO_ERROR;
373}
374
375/**
376 * @brief Starts an sector erase operation.
377 *
378 * @param[in] ip pointer to a @p EFlashDriver instance
379 * @param[in] sector sector to be erased
380 * @return An error code.
381 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
382 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
383 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
384 *
385 * @notapi
386 */
387flash_error_t efl_lld_start_erase_sector(void *instance,
388 flash_sector_t sector) {
389 EFlashDriver *devp = (EFlashDriver *)instance;
390
391 osalDbgCheck(instance != NULL);
392 osalDbgCheck(sector < efl_lld_descriptor.sectors_count);
393 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
394 "invalid state");
395
396 /* No erasing while erasing.*/
397 if (devp->state == FLASH_ERASE) {
398 return FLASH_BUSY_ERASING;
399 }
400
401 /* FLASH_PGM state while the operation is performed.*/
402 devp->state = FLASH_ERASE;
403
404 /* Clearing error status bits.*/
405 stm32_flash_clear_status(devp);
406
407 /* Enable page erase.*/
408 devp->flash->CR |= FLASH_CR_PER;
409
410#if defined(FLASH_CR_BKER)
411 /* Bank selection.*/
412 if (sector < STM32_FLASH_SECTORS_PER_BANK) {
413 /* First bank.*/
414 devp->flash->CR &= ~FLASH_CR_BKER;
415 }
416 else {
417 /* Second bank.*/
418 devp->flash->CR |= FLASH_CR_BKER;
419 }
420#endif
421
422 /* Mask off the page selection bits.*/
423 devp->flash->CR &= ~FLASH_CR_PNB;
424
425 /* Set the page selection bits.*/
426 devp->flash->CR |= sector << FLASH_CR_PNB_Pos;
427
428 /* Start the erase.*/
429 devp->flash->CR |= FLASH_CR_STRT;
430
431 return FLASH_NO_ERROR;
432}
433
434/**
435 * @brief Queries the driver for erase operation progress.
436 *
437 * @param[in] ip pointer to a @p EFlashDriver instance
438 * @param[out] msec recommended time, in milliseconds, that
439 * should be spent before calling this
440 * function again, can be @p NULL
441 * @return An error code.
442 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
443 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
444 * @retval FLASH_ERROR_ERASE if the erase operation failed.
445 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
446 *
447 * @api
448 */
449flash_error_t efl_lld_query_erase(void *instance, uint32_t *msec) {
450 EFlashDriver *devp = (EFlashDriver *)instance;
451 flash_error_t err;
452
453 /* If there is an erase in progress then the device must be checked.*/
454 if (devp->state == FLASH_ERASE) {
455
456 /* Checking for operation in progress.*/
457 if ((devp->flash->SR & FLASH_SR_BSY) == 0U) {
458
459 /* Disabling the various erase control bits.*/
460 devp->flash->CR &= ~(FLASH_CR_MER1 |
461#if defined(FLASH_CR_MER2)
462 FLASH_CR_MER2 |
463#endif
464 FLASH_CR_PER);
465
466 /* No operation in progress, checking for errors.*/
467 err = stm32_flash_check_errors(devp);
468
469 /* Back to ready state.*/
470 devp->state = FLASH_READY;
471 }
472 else {
473 /* Recommended time before polling again, this is a simplified
474 implementation.*/
475 if (msec != NULL) {
476 *msec = (uint32_t)STM32_FLASH_WAIT_TIME_MS;
477 }
478
479 err = FLASH_BUSY_ERASING;
480 }
481 }
482 else {
483 err = FLASH_NO_ERROR;
484 }
485
486 return err;
487}
488
489/**
490 * @brief Returns the erase state of a sector.
491 *
492 * @param[in] ip pointer to a @p EFlashDriver instance
493 * @param[in] sector sector to be verified
494 * @return An error code.
495 * @retval FLASH_NO_ERROR if the sector is erased.
496 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
497 * @retval FLASH_ERROR_VERIFY if the verify operation failed.
498 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
499 *
500 * @notapi
501 */
502flash_error_t efl_lld_verify_erase(void *instance, flash_sector_t sector) {
503 EFlashDriver *devp = (EFlashDriver *)instance;
504 uint32_t *address;
505 flash_error_t err = FLASH_NO_ERROR;
506 unsigned i;
507
508 osalDbgCheck(instance != NULL);
509 osalDbgCheck(sector < efl_lld_descriptor.sectors_count);
510 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
511 "invalid state");
512
513 /* No verifying while erasing.*/
514 if (devp->state == FLASH_ERASE) {
515 return FLASH_BUSY_ERASING;
516 }
517
518 /* Address of the sector.*/
519 address = (uint32_t *)(efl_lld_descriptor.address +
520 flashGetSectorOffset(getBaseFlash(devp), sector));
521
522 /* FLASH_READY state while the operation is performed.*/
523 devp->state = FLASH_READ;
524
525 /* Scanning the sector space.*/
526 for (i = 0U; i < STM32_FLASH_SECTOR_SIZE / sizeof(uint32_t); i++) {
527 if (*address != 0xFFFFFFFFU) {
528 err = FLASH_ERROR_VERIFY;
529 break;
530 }
531 address++;
532 }
533
534 /* Ready state again.*/
535 devp->state = FLASH_READY;
536
537 return err;
538}
539
540#endif /* HAL_USE_EFL == TRUE */
541
542/** @} */