Add STM32F412/F413 EFL driver support.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13119 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
parent
ea17238861
commit
5c89ae333b
|
@ -0,0 +1,660 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hal_efl_lld.c
|
||||
* @brief STM32F412/413 Embedded Flash subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup HAL_EFL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if (HAL_USE_EFL == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define STM32_FLASH_LINE_SIZE (1 << STM32_FLASH_PSIZE)
|
||||
#define STM32_FLASH_LINE_MASK (STM32_FLASH_LINE_SIZE - 1U)
|
||||
|
||||
#define FLASH_PDKEY1 0x04152637U
|
||||
#define FLASH_PDKEY2 0xFAFBFCFDU
|
||||
|
||||
#define FLASH_KEY1 0x45670123U
|
||||
#define FLASH_KEY2 0xCDEF89ABU
|
||||
|
||||
#define FLASH_OPTKEY1 0x08192A3BU
|
||||
#define FLASH_OPTKEY2 0x4C5D6E7FU
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief EFL1 driver identifier.
|
||||
*/
|
||||
EFlashDriver EFLD1;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if defined(STM32F413xx) || defined(STM32F412xx) || defined(__DOXYGEN__)
|
||||
/* Sector table for 1.5M device. */
|
||||
static const flash_sector_descriptor_t efl_lld_sect1[STM32_FLASH1_SECTORS_TOTAL] = {
|
||||
{ 0, 16134}, /* Sector 0. */
|
||||
{ 1 * 16134, 16134}, /* Sector 1. */
|
||||
{ 2 * 16134, 16134}, /* Sector 2. */
|
||||
{ 3 * 16134, 16134}, /* Sector 3. */
|
||||
{ 4 * 16134, 65536}, /* Sector 4. */
|
||||
{ 4 * 16134 + 65536, 131072}, /* Sector 5. */
|
||||
{ 4 * 16134 + 65536 + 1 * 131072, 131072}, /* Sector 6. */
|
||||
{ 4 * 16134 + 65536 + 2 * 131072, 131072}, /* Sector 7. */
|
||||
{ 4 * 16134 + 65536 + 3 * 131072, 131072}, /* Sector 8. */
|
||||
{ 4 * 16134 + 65536 + 4 * 131072, 131072}, /* Sector 9. */
|
||||
{ 4 * 16134 + 65536 + 5 * 131072, 131072}, /* Sector 10. */
|
||||
{ 4 * 16134 + 65536 + 6 * 131072, 131072}, /* Sector 11. */
|
||||
{ 4 * 16134 + 65536 + 7 * 131072, 131072}, /* Sector 12. */
|
||||
{ 4 * 16134 + 65536 + 8 * 131072, 131072}, /* Sector 13. */
|
||||
{ 4 * 16134 + 65536 + 9 * 131072, 131072}, /* Sector 14. */
|
||||
{ 4 * 16134 + 65536 + 10 * 131072, 131072} /* Sector 15. */
|
||||
};
|
||||
|
||||
/* Sector table for 1M device. */
|
||||
static const flash_sector_descriptor_t efl_lld_sect2[STM32_FLASH2_SECTORS_TOTAL] = {
|
||||
{ 0, 16134}, /* Sector 0. */
|
||||
{ 1 * 16134, 16134}, /* Sector 1. */
|
||||
{ 2 * 16134, 16134}, /* Sector 2. */
|
||||
{ 3 * 16134, 16134}, /* Sector 3. */
|
||||
{ 4 * 16134, 65536}, /* Sector 4. */
|
||||
{ 4 * 16134 + 65536, 131072}, /* Sector 5. */
|
||||
{ 4 * 16134 + 65536 + 1 * 131072, 131072}, /* Sector 6. */
|
||||
{ 4 * 16134 + 65536 + 2 * 131072, 131072}, /* Sector 7. */
|
||||
{ 4 * 16134 + 65536 + 3 * 131072, 131072}, /* Sector 8. */
|
||||
{ 4 * 16134 + 65536 + 4 * 131072, 131072}, /* Sector 9. */
|
||||
{ 4 * 16134 + 65536 + 5 * 131072, 131072}, /* Sector 10. */
|
||||
{ 4 * 16134 + 65536 + 6 * 131072, 131072} /* Sector 11. */
|
||||
};
|
||||
|
||||
/* The descriptors for 1.5M device. */
|
||||
static const flash_descriptor_t efl_lld_size1[STM32_FLASH_NUMBER_OF_BANKS] = {
|
||||
{ /* Single bank organisation. */
|
||||
.attributes = FLASH_ATTR_ERASED_IS_ONE |
|
||||
FLASH_ATTR_MEMORY_MAPPED,
|
||||
.page_size = STM32_FLASH_LINE_SIZE,
|
||||
.sectors_count = STM32_FLASH1_SECTORS_TOTAL,
|
||||
.sectors = efl_lld_sect1,
|
||||
.sectors_size = 0,
|
||||
.address = (uint8_t *)FLASH_BASE,
|
||||
.size = STM32_FLASH1_SIZE * STM32_FLASH_SIZE_SCALE
|
||||
}
|
||||
};
|
||||
|
||||
/* The descriptors for 1M device. */
|
||||
static const flash_descriptor_t efl_lld_size2[STM32_FLASH_NUMBER_OF_BANKS] = {
|
||||
{ /* Single bank organisation. */
|
||||
.attributes = FLASH_ATTR_ERASED_IS_ONE |
|
||||
FLASH_ATTR_MEMORY_MAPPED,
|
||||
.page_size = STM32_FLASH_LINE_SIZE,
|
||||
.sectors_count = STM32_FLASH2_SECTORS_TOTAL,
|
||||
.sectors = efl_lld_sect2,
|
||||
.sectors_size = 0,
|
||||
.address = (uint8_t *)FLASH_BASE,
|
||||
.size = STM32_FLASH2_SIZE * STM32_FLASH_SIZE_SCALE
|
||||
}
|
||||
};
|
||||
|
||||
/* Table describing possible flash sizes and descriptors for this device. */
|
||||
static const efl_lld_size_t efl_lld_flash_sizes[] = {
|
||||
{
|
||||
.desc = efl_lld_size1
|
||||
},
|
||||
{
|
||||
.desc = efl_lld_size2
|
||||
}
|
||||
};
|
||||
#else
|
||||
#error "This EFL driver does not support the selected device"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static inline void stm32_flash_lock(EFlashDriver *eflp) {
|
||||
|
||||
eflp->flash->CR |= FLASH_CR_LOCK;
|
||||
}
|
||||
|
||||
static inline void stm32_flash_unlock(EFlashDriver *eflp) {
|
||||
|
||||
eflp->flash->KEYR |= FLASH_KEY1;
|
||||
eflp->flash->KEYR |= FLASH_KEY2;
|
||||
}
|
||||
|
||||
static inline void stm32_flash_enable_pgm(EFlashDriver *eflp) {
|
||||
|
||||
/* Set parallelism. */
|
||||
eflp->flash->CR &= ~FLASH_CR_PSIZE;
|
||||
eflp->flash->CR |= STM32_FLASH_PSIZE << FLASH_CR_PSIZE_Pos;
|
||||
|
||||
/* Enable programming. */
|
||||
eflp->flash->CR |= FLASH_CR_PG;
|
||||
}
|
||||
|
||||
static inline void stm32_flash_disable_pgm(EFlashDriver *eflp) {
|
||||
|
||||
eflp->flash->CR &= ~FLASH_CR_PG;
|
||||
}
|
||||
|
||||
static inline void stm32_flash_clear_status(EFlashDriver *eflp) {
|
||||
|
||||
eflp->flash->SR = 0x0000FFFFU;
|
||||
}
|
||||
|
||||
static inline void stm32_flash_wait_busy(EFlashDriver *eflp) {
|
||||
|
||||
/* Wait for busy bit clear.*/
|
||||
while ((eflp->flash->SR & FLASH_SR_BSY) != 0U) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline size_t stm32_flash_get_size(void) {
|
||||
return *(uint16_t*)((uint32_t) STM32_FLASH_SIZE_REGISTER) * STM32_FLASH_SIZE_SCALE;
|
||||
}
|
||||
|
||||
static inline bool stm32_flash_dual_bank(EFlashDriver *eflp) {
|
||||
|
||||
#if STM32_FLASH_NUMBER_OF_BANKS > 1
|
||||
return ((eflp->flash->OPTCR & FLASH_OPTCR_DB1M) != 0U);
|
||||
#endif
|
||||
(void)eflp;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline flash_error_t stm32_flash_check_errors(EFlashDriver *eflp) {
|
||||
uint32_t sr = eflp->flash->SR;
|
||||
|
||||
/* Clearing error conditions.*/
|
||||
eflp->flash->SR = sr & 0x0000FFFFU;
|
||||
|
||||
/* Some errors are only caught by assertion.*/
|
||||
osalDbgAssert((sr & 0) == 0U, "unexpected flash error");
|
||||
|
||||
/* Decoding relevant errors.*/
|
||||
if ((sr & FLASH_SR_WRPERR) != 0U) {
|
||||
return FLASH_ERROR_HW_FAILURE;
|
||||
}
|
||||
|
||||
if ((sr & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_OPERR)) != 0U) {
|
||||
return eflp->state == FLASH_PGM ? FLASH_ERROR_PROGRAM : FLASH_ERROR_ERASE;
|
||||
}
|
||||
|
||||
return FLASH_NO_ERROR;
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level Embedded Flash driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void efl_lld_init(void) {
|
||||
|
||||
/* Driver initialization.*/
|
||||
eflObjectInit(&EFLD1);
|
||||
EFLD1.flash = FLASH;
|
||||
/* Find the size of the flash and set descriptor reference. */
|
||||
uint8_t i;
|
||||
for (i = 0; i < (sizeof(efl_lld_flash_sizes) / sizeof(efl_lld_size_t)); i++) {
|
||||
if (efl_lld_flash_sizes[i].desc->size == stm32_flash_get_size()) {
|
||||
EFLD1.descriptor = efl_lld_flash_sizes[i].desc;
|
||||
if (stm32_flash_dual_bank(&EFLD1)) {
|
||||
/* Point to the dual bank descriptor. */
|
||||
EFLD1.descriptor++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
osalDbgAssert(false, "invalid flash configuration");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the Embedded Flash peripheral.
|
||||
*
|
||||
* @param[in] eflp pointer to a @p EFlashDriver structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void efl_lld_start(EFlashDriver *eflp) {
|
||||
stm32_flash_unlock(eflp);
|
||||
FLASH->CR = 0x00000000U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the Embedded Flash peripheral.
|
||||
*
|
||||
* @param[in] eflp pointer to a @p EFlashDriver structure
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void efl_lld_stop(EFlashDriver *eflp) {
|
||||
|
||||
stm32_flash_lock(eflp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the flash descriptor structure.
|
||||
*
|
||||
* @param[in] ip pointer to a @p EFlashDriver instance
|
||||
* @return A flash device descriptor.
|
||||
* @retval Pointer to single bank if DBM not enabled.
|
||||
* @retval Pointer to bank1 if DBM enabled.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
const flash_descriptor_t *efl_lld_get_descriptor(void *instance) {
|
||||
EFlashDriver *devp = (EFlashDriver *)instance;
|
||||
return devp->descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read operation.
|
||||
*
|
||||
* @param[in] ip pointer to a @p EFlashDriver instance
|
||||
* @param[in] offset offset within full flash address space
|
||||
* @param[in] n number of bytes to be read
|
||||
* @param[out] rp pointer to the data buffer
|
||||
* @return An error code.
|
||||
* @retval FLASH_NO_ERROR if there is no erase operation in progress.
|
||||
* @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
|
||||
* @retval FLASH_ERROR_READ if the read operation failed.
|
||||
* @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
flash_error_t efl_lld_read(void *instance, flash_offset_t offset,
|
||||
size_t n, uint8_t *rp) {
|
||||
EFlashDriver *devp = (EFlashDriver *)instance;
|
||||
flash_error_t err = FLASH_NO_ERROR;
|
||||
|
||||
osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
|
||||
|
||||
const flash_descriptor_t *bank = efl_lld_get_descriptor(instance);
|
||||
osalDbgCheck((size_t)offset + n <= (size_t)bank->size);
|
||||
osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
|
||||
"invalid state");
|
||||
|
||||
/* No reading while erasing.*/
|
||||
if (devp->state == FLASH_ERASE) {
|
||||
return FLASH_BUSY_ERASING;
|
||||
}
|
||||
|
||||
/* FLASH_READ state while the operation is performed.*/
|
||||
devp->state = FLASH_READ;
|
||||
|
||||
/* Clearing error status bits.*/
|
||||
stm32_flash_clear_status(devp);
|
||||
|
||||
/* Actual read implementation.*/
|
||||
memcpy((void *)rp, (const void *)efl_lld_get_descriptor(instance)->address
|
||||
+ offset, n);
|
||||
|
||||
/* Checking for errors after reading.*/
|
||||
if ((devp->flash->SR & FLASH_SR_RDERR) != 0U) {
|
||||
err = FLASH_ERROR_READ;
|
||||
}
|
||||
|
||||
/* Ready state again.*/
|
||||
devp->state = FLASH_READY;
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Program operation.
|
||||
* @note Successive write operations are possible without the need of
|
||||
* an erase when changing bits from one to zero. Writing one requires
|
||||
* an erase operation.
|
||||
*
|
||||
* @param[in] ip pointer to a @p EFlashDriver instance
|
||||
* @param[in] offset offset within full flash address space
|
||||
* @param[in] n number of bytes to be programmed
|
||||
* @param[in] pp pointer to the data buffer
|
||||
* @return An error code.
|
||||
* @retval FLASH_NO_ERROR if there is no erase operation in progress.
|
||||
* @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
|
||||
* @retval FLASH_ERROR_PROGRAM if the program operation failed.
|
||||
* @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
flash_error_t efl_lld_program(void *instance, flash_offset_t offset,
|
||||
size_t n, const uint8_t *pp) {
|
||||
EFlashDriver *devp = (EFlashDriver *)instance;
|
||||
const flash_descriptor_t *bank = efl_lld_get_descriptor(instance);
|
||||
flash_error_t err = FLASH_NO_ERROR;
|
||||
|
||||
osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U));
|
||||
osalDbgCheck((size_t)offset + n <= (size_t)bank->size);
|
||||
osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
|
||||
"invalid state");
|
||||
|
||||
/* No programming while erasing.*/
|
||||
if (devp->state == FLASH_ERASE) {
|
||||
return FLASH_BUSY_ERASING;
|
||||
}
|
||||
|
||||
/* FLASH_PGM state while the operation is performed.*/
|
||||
devp->state = FLASH_PGM;
|
||||
|
||||
/* Clearing error status bits.*/
|
||||
stm32_flash_clear_status(devp);
|
||||
|
||||
/* Enabling PGM mode in the controller.*/
|
||||
stm32_flash_enable_pgm(devp);
|
||||
|
||||
/* Actual program implementation.*/
|
||||
while (n > 0U) {
|
||||
volatile uint32_t *address;
|
||||
|
||||
/* Create an array of sufficient size to hold line(s). */
|
||||
union {
|
||||
uint32_t w[STM32_FLASH_LINE_SIZE / sizeof(uint32_t)];
|
||||
uint16_t h[STM32_FLASH_LINE_SIZE / sizeof(uint16_t)];
|
||||
uint8_t b[STM32_FLASH_LINE_SIZE / sizeof(uint8_t)];
|
||||
} line;
|
||||
|
||||
/* Unwritten bytes are initialized to all ones.*/
|
||||
uint8_t i;
|
||||
for (i = 0; i < bank->page_size; i++) {
|
||||
line.b[i] = 0xFF;
|
||||
}
|
||||
|
||||
/* Programming address aligned to flash lines.*/
|
||||
address = (volatile uint32_t *)(bank->address +
|
||||
(offset & ~STM32_FLASH_LINE_MASK));
|
||||
|
||||
/* Copying data inside the prepared line(s).*/
|
||||
do {
|
||||
line.b[offset & STM32_FLASH_LINE_MASK] = *pp;
|
||||
offset++;
|
||||
n--;
|
||||
pp++;
|
||||
}
|
||||
while ((n > 0U) & ((offset & STM32_FLASH_LINE_MASK) != 0U));
|
||||
|
||||
/* Programming line according to parallelism.*/
|
||||
switch (STM32_FLASH_LINE_SIZE) {
|
||||
case 1:
|
||||
address[0] = line.b[0];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
address[0] = line.h[0];
|
||||
break;
|
||||
|
||||
case 4:
|
||||
address[0] = line.w[0];
|
||||
break;
|
||||
|
||||
case 8:
|
||||
address[0] = line.w[0];
|
||||
address[1] = line.w[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
osalDbgAssert(false, "invalid line size");
|
||||
break;
|
||||
}
|
||||
|
||||
stm32_flash_wait_busy(devp);
|
||||
err = stm32_flash_check_errors(devp);
|
||||
if (err != FLASH_NO_ERROR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disabling PGM mode in the controller.*/
|
||||
stm32_flash_disable_pgm(devp);
|
||||
|
||||
/* Ready state again.*/
|
||||
devp->state = FLASH_READY;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts a whole-device erase operation.
|
||||
* @note This function only erases bank 2 if it is present. Bank 1 is not
|
||||
* allowed since it is normally where the primary program is located.
|
||||
* Sectors on bank 1 can be individually erased.
|
||||
*
|
||||
* @param[in] ip pointer to a @p EFlashDriver instance
|
||||
* @return An error code.
|
||||
* @retval FLASH_NO_ERROR if there is no erase operation in progress.
|
||||
* @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
|
||||
* @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
flash_error_t efl_lld_start_erase_all(void *instance) {
|
||||
EFlashDriver *devp = (EFlashDriver *)instance;
|
||||
|
||||
osalDbgCheck(instance != NULL);
|
||||
osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
|
||||
"invalid state");
|
||||
|
||||
/* No erasing while erasing.*/
|
||||
if (devp->state == FLASH_ERASE) {
|
||||
return FLASH_BUSY_ERASING;
|
||||
}
|
||||
|
||||
#if defined(FLASH_CR_MER1)
|
||||
/* If dual bank is active then mass erase bank2. */
|
||||
if (stm32_flash_dual_bank(devp)) {
|
||||
|
||||
/* FLASH_ERASE state while the operation is performed.*/
|
||||
devp->state = FLASH_ERASE;
|
||||
|
||||
/* Clearing error status bits.*/
|
||||
stm32_flash_clear_status(devp);
|
||||
|
||||
devp->flash->CR |= FLASH_CR_MER1;
|
||||
devp->flash->CR |= FLASH_CR_STRT;
|
||||
return FLASH_NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Mass erase not allowed. */
|
||||
return FLASH_ERROR_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts an sector erase operation.
|
||||
*
|
||||
* @param[in] ip pointer to a @p EFlashDriver instance
|
||||
* @param[in] sector sector to be erased
|
||||
* this is an index within the total sectors
|
||||
* in a flash bank
|
||||
* @return An error code.
|
||||
* @retval FLASH_NO_ERROR if there is no erase operation in progress.
|
||||
* @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
|
||||
* @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
flash_error_t efl_lld_start_erase_sector(void *instance,
|
||||
flash_sector_t sector) {
|
||||
EFlashDriver *devp = (EFlashDriver *)instance;
|
||||
const flash_descriptor_t *bank = efl_lld_get_descriptor(instance);
|
||||
osalDbgCheck(instance != NULL);
|
||||
osalDbgCheck(sector < bank->sectors_count);
|
||||
osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
|
||||
"invalid state");
|
||||
|
||||
/* No erasing while erasing.*/
|
||||
if (devp->state == FLASH_ERASE) {
|
||||
return FLASH_BUSY_ERASING;
|
||||
}
|
||||
|
||||
/* FLASH_PGM state while the operation is performed.*/
|
||||
devp->state = FLASH_ERASE;
|
||||
|
||||
/* Clearing error status bits.*/
|
||||
stm32_flash_clear_status(devp);
|
||||
|
||||
/* Enable sector erase.*/
|
||||
devp->flash->CR |= FLASH_CR_SER;
|
||||
|
||||
/* Mask off the sector and parallelism selection bits.*/
|
||||
devp->flash->CR &= ~FLASH_CR_SNB;
|
||||
devp->flash->CR &= ~FLASH_CR_PSIZE;
|
||||
|
||||
/* Set sector and parallelism. */
|
||||
devp->flash->CR |= (sector << FLASH_CR_SNB_Pos) |
|
||||
(STM32_FLASH_PSIZE << FLASH_CR_PSIZE_Pos);
|
||||
|
||||
/* Start the erase.*/
|
||||
devp->flash->CR |= FLASH_CR_STRT;
|
||||
|
||||
return FLASH_NO_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Queries the driver for erase operation progress.
|
||||
*
|
||||
* @param[in] instance pointer to a @p EFlashDriver instance
|
||||
* @param[out] msec recommended time, in milliseconds, that
|
||||
* should be spent before calling this
|
||||
* function again, can be @p NULL
|
||||
* @return An error code.
|
||||
* @retval FLASH_NO_ERROR if there is no erase operation in progress.
|
||||
* @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
|
||||
* @retval FLASH_ERROR_ERASE if the erase operation failed.
|
||||
* @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
flash_error_t efl_lld_query_erase(void *instance, uint32_t *msec) {
|
||||
EFlashDriver *devp = (EFlashDriver *)instance;
|
||||
flash_error_t err;
|
||||
|
||||
/* If there is an erase in progress then the device must be checked.*/
|
||||
if (devp->state == FLASH_ERASE) {
|
||||
|
||||
/* Checking for operation in progress.*/
|
||||
if ((devp->flash->SR & FLASH_SR_BSY) == 0U) {
|
||||
|
||||
/* Disabling the various erase control bits.*/
|
||||
devp->flash->CR &= ~(FLASH_CR_MER |
|
||||
#if defined(FLASH_CR_MER1)
|
||||
FLASH_CR_MER1 |
|
||||
#endif
|
||||
FLASH_CR_SER);
|
||||
|
||||
/* No operation in progress, checking for errors.*/
|
||||
err = stm32_flash_check_errors(devp);
|
||||
|
||||
/* Back to ready state.*/
|
||||
devp->state = FLASH_READY;
|
||||
}
|
||||
else {
|
||||
/* Recommended time before polling again. This is a simplified
|
||||
implementation.*/
|
||||
if (msec != NULL) {
|
||||
*msec = (uint32_t)STM32_FLASH_WAIT_TIME_MS;
|
||||
}
|
||||
|
||||
err = FLASH_BUSY_ERASING;
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = FLASH_NO_ERROR;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the erase state of a sector.
|
||||
*
|
||||
* @param[in] ip pointer to a @p EFlashDriver instance
|
||||
* @param[in] sector sector to be verified
|
||||
* @return An error code.
|
||||
* @retval FLASH_NO_ERROR if the sector is erased.
|
||||
* @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
|
||||
* @retval FLASH_ERROR_VERIFY if the verify operation failed.
|
||||
* @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
flash_error_t efl_lld_verify_erase(void *instance, flash_sector_t sector) {
|
||||
EFlashDriver *devp = (EFlashDriver *)instance;
|
||||
uint32_t *address;
|
||||
const flash_descriptor_t *bank = efl_lld_get_descriptor(instance);
|
||||
flash_error_t err = FLASH_NO_ERROR;
|
||||
unsigned i;
|
||||
|
||||
osalDbgCheck(instance != NULL);
|
||||
osalDbgCheck(sector < bank->sectors_count);
|
||||
osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
|
||||
"invalid state");
|
||||
|
||||
/* No verifying while erasing.*/
|
||||
if (devp->state == FLASH_ERASE) {
|
||||
return FLASH_BUSY_ERASING;
|
||||
}
|
||||
|
||||
/* Address of the sector in the bank.*/
|
||||
address = (uint32_t *)(bank->address +
|
||||
flashGetSectorOffset(getBaseFlash(devp), sector));
|
||||
|
||||
/* FLASH_READ state while the operation is performed.*/
|
||||
devp->state = FLASH_READ;
|
||||
|
||||
/* Scanning the sector space.*/
|
||||
uint32_t sector_size = flashGetSectorSize(getBaseFlash(devp), sector);
|
||||
for (i = 0U; i < sector_size / sizeof(uint32_t); i++) {
|
||||
if (*address != 0xFFFFFFFFU) {
|
||||
err = FLASH_ERROR_VERIFY;
|
||||
break;
|
||||
}
|
||||
address++;
|
||||
}
|
||||
|
||||
/* Ready state again.*/
|
||||
devp->state = FLASH_READY;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_EFL == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file hal_efl_lld.h
|
||||
* @brief STM32F412/413 Embedded Flash subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup HAL_EFL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef HAL_EFL_LLD_H
|
||||
#define HAL_EFL_LLD_H
|
||||
|
||||
#if (HAL_USE_EFL == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name STM32F412/413 EFL driver configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Suggested wait time during erase operations polling.
|
||||
*/
|
||||
#if !defined(STM32_FLASH_WAIT_TIME_MS) || defined(__DOXYGEN__)
|
||||
#define STM32_FLASH_WAIT_TIME_MS 5
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if defined(STM32F413xx) || defined(STM32F412xx) || defined(__DOXYGEN__)
|
||||
|
||||
/* Flash size register. */
|
||||
#define STM32_FLASH_SIZE_REGISTER 0x1FFF7A22
|
||||
#define STM32_FLASH_SIZE_SCALE 1024U
|
||||
|
||||
/*
|
||||
* Device flash size...
|
||||
*
|
||||
*/
|
||||
#define STM32_FLASH_NUMBER_OF_BANKS 1
|
||||
#define STM32_FLASH1_SIZE 1536U
|
||||
#define STM32_FLASH2_SIZE 1024U
|
||||
#define STM32_FLASH1_SECTORS_TOTAL 16
|
||||
#define STM32_FLASH2_SECTORS_TOTAL 12
|
||||
#else
|
||||
#error "This EFL driver does not support the selected device"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* A flash size declaration. */
|
||||
typedef struct {
|
||||
const flash_descriptor_t* desc;
|
||||
} efl_lld_size_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level fields of the embedded flash driver structure.
|
||||
*/
|
||||
#define efl_lld_driver_fields \
|
||||
/* Flash registers.*/ \
|
||||
FLASH_TypeDef *flash; \
|
||||
const flash_descriptor_t *descriptor;
|
||||
|
||||
/**
|
||||
* @brief Low level fields of the embedded flash configuration structure.
|
||||
*/
|
||||
#define efl_lld_config_fields \
|
||||
/* Dummy configuration, it is not needed.*/ \
|
||||
uint32_t dummy
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
extern EFlashDriver EFLD1;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void efl_lld_init(void);
|
||||
void efl_lld_start(EFlashDriver *eflp);
|
||||
void efl_lld_stop(EFlashDriver *eflp);
|
||||
const flash_descriptor_t *efl_lld_get_descriptor(void *instance);
|
||||
flash_error_t efl_lld_read(void *instance, flash_offset_t offset,
|
||||
size_t n, uint8_t *rp);
|
||||
flash_error_t efl_lld_program(void *instance, flash_offset_t offset,
|
||||
size_t n, const uint8_t *pp);
|
||||
flash_error_t efl_lld_start_erase_all(void *instance);
|
||||
flash_error_t efl_lld_start_erase_sector(void *instance,
|
||||
flash_sector_t sector);
|
||||
flash_error_t efl_lld_query_erase(void *instance, uint32_t *wait_time);
|
||||
flash_error_t efl_lld_verify_erase(void *instance, flash_sector_t sector);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_EFL == TRUE */
|
||||
|
||||
#endif /* HAL_EFL_LLD_H */
|
||||
|
||||
/** @} */
|
|
@ -1,7 +1,8 @@
|
|||
# Required platform files.
|
||||
PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \
|
||||
$(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/stm32_isr.c \
|
||||
$(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/hal_lld.c
|
||||
$(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/hal_lld.c \
|
||||
$(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/hal_efl_lld.c
|
||||
|
||||
# Required include directories.
|
||||
PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \
|
||||
|
|
Loading…
Reference in New Issue