You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
366 lines
12 KiB
C
366 lines
12 KiB
C
/*
|
|
ChibiOS - Copyright (C) 2006..2018 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 PLATFORM Embedded Flash subsystem low level driver source.
|
|
*
|
|
* @addtogroup HAL_EFL
|
|
* @{
|
|
*/
|
|
|
|
#include "hal.h"
|
|
|
|
#if (HAL_USE_EFL == TRUE) || defined(__DOXYGEN__)
|
|
|
|
/*===========================================================================*/
|
|
/* Driver local definitions. */
|
|
/*===========================================================================*/
|
|
|
|
/*===========================================================================*/
|
|
/* Driver exported variables. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @brief EFL1 driver identifier.
|
|
*/
|
|
#if (PLATFORM_EFL_USE_EFL1 == TRUE) || defined(__DOXYGEN__)
|
|
EFlashDriver EFLD1;
|
|
#endif
|
|
|
|
/*===========================================================================*/
|
|
/* Driver local variables and types. */
|
|
/*===========================================================================*/
|
|
|
|
static const flash_descriptor_t efl_lld_descriptor = {
|
|
.attributes = FLASH_ATTR_ERASED_IS_ONE |
|
|
FLASH_ATTR_MEMORY_MAPPED |
|
|
FLASH_ATTR_ECC_CAPABLE |
|
|
FLASH_ATTR_ECC_ZERO_LINE_CAPABLE,
|
|
.page_size = 0,
|
|
.sectors_count = 0,
|
|
.sectors = NULL,
|
|
.sectors_size = 0,
|
|
.address = (uint8_t *)0,
|
|
.size = 0
|
|
};
|
|
|
|
/*===========================================================================*/
|
|
/* Driver local functions. */
|
|
/*===========================================================================*/
|
|
|
|
/*===========================================================================*/
|
|
/* Driver interrupt handlers. */
|
|
/*===========================================================================*/
|
|
|
|
/*===========================================================================*/
|
|
/* Driver exported functions. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @brief Low level Embedded Flash driver initialization.
|
|
*
|
|
* @notapi
|
|
*/
|
|
void efl_lld_init(void) {
|
|
|
|
#if PLATFORM_EFL_USE_EFL1 == TRUE
|
|
/* Driver initialization.*/
|
|
eflObjectInit(&EFLD1);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Configures and activates the Embedded Flash peripheral.
|
|
*
|
|
* @param[in] eflp pointer to a @p EFlashDriver structure
|
|
*
|
|
* @notapi
|
|
*/
|
|
void efl_lld_start(EFlashDriver *eflp) {
|
|
|
|
if (eflp->state == FLASH_STOP) {
|
|
/* Enables the peripheral.*/
|
|
#if PLATFORM_EFL_USE_EFL1 == TRUE
|
|
if (&EFLD1 == eflp) {
|
|
|
|
}
|
|
#endif
|
|
}
|
|
/* Configures the peripheral.*/
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief Deactivates the Embedded Flash peripheral.
|
|
*
|
|
* @param[in] eflp pointer to a @p EFlashDriver structure
|
|
*
|
|
* @notapi
|
|
*/
|
|
void efl_lld_stop(EFlashDriver *eflp) {
|
|
|
|
if (eflp->state == FLASH_READY) {
|
|
/* Resets the peripheral.*/
|
|
|
|
/* Disables the peripheral.*/
|
|
#if PLATFORM_EFL_USE_EFL1 == TRUE
|
|
if (&EFLD1 == eflp) {
|
|
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the flash descriptor structure.
|
|
*
|
|
* @param[in] instance pointer to a @p EFlashDriver instance
|
|
* @return A flash device descriptor.
|
|
*
|
|
* @notapi
|
|
*/
|
|
const flash_descriptor_t *efl_lld_get_descriptor(void *instance) {
|
|
|
|
(void)instance;
|
|
|
|
return &efl_lld_descriptor;
|
|
}
|
|
|
|
/**
|
|
* @brief Read operation.
|
|
*
|
|
* @param[in] instance pointer to a @p EFlashDriver instance
|
|
* @param[in] offset flash offset
|
|
* @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));
|
|
osalDbgCheck(((size_t)offset + n) <= (size_t)efl_lld_descriptor.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_READY state while the operation is performed.*/
|
|
devp->state = FLASH_READ;
|
|
|
|
/* IMPLEMENT */
|
|
|
|
/* Ready state again.*/
|
|
devp->state = FLASH_READY;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
/**
|
|
* @brief Program operation.
|
|
* @note The device supports ECC, it is only possible to write erased
|
|
* pages once except when writing all zeroes.
|
|
*
|
|
* @param[in] instance pointer to a @p EFlashDriver instance
|
|
* @param[in] offset flash offset
|
|
* @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;
|
|
flash_error_t err = FLASH_NO_ERROR;
|
|
|
|
osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U));
|
|
osalDbgCheck(((size_t)offset + n) <= (size_t)efl_lld_descriptor.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;
|
|
|
|
/* IMPLEMENT */
|
|
|
|
/* 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
|
|
* touched because it is where the program is running on.
|
|
* Pages on bank 1 can be individually erased.
|
|
*
|
|
* @param[in] instance 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;
|
|
}
|
|
|
|
/* FLASH_PGM state while the operation is performed.*/
|
|
devp->state = FLASH_ERASE;
|
|
|
|
/* IMPLEMENT */
|
|
|
|
return FLASH_NO_ERROR;
|
|
}
|
|
|
|
/**
|
|
* @brief Starts an sector erase operation.
|
|
*
|
|
* @param[in] instance pointer to a @p EFlashDriver instance
|
|
* @param[in] sector sector to be erased
|
|
* @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;
|
|
|
|
osalDbgCheck(instance != NULL);
|
|
osalDbgCheck(sector < efl_lld_descriptor.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;
|
|
|
|
/* IMPLEMENT */
|
|
|
|
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 = FLASH_NO_ERROR;
|
|
|
|
(void)msec;
|
|
|
|
/* If there is an erase in progress then the device must be checked.*/
|
|
if (devp->state == FLASH_ERASE) {
|
|
|
|
/* IMPLEMENT */
|
|
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the erase state of a sector.
|
|
*
|
|
* @param[in] instance 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;
|
|
flash_error_t err = FLASH_NO_ERROR;
|
|
|
|
osalDbgCheck(instance != NULL);
|
|
osalDbgCheck(sector < efl_lld_descriptor.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;
|
|
}
|
|
|
|
/* IMPLEMENT */
|
|
|
|
/* Ready state again.*/
|
|
devp->state = FLASH_READY;
|
|
|
|
return err;
|
|
}
|
|
|
|
#endif /* HAL_USE_EFL == TRUE */
|
|
|
|
/** @} */
|