diff --git a/os/hal/ports/NUMICRO/LLD/FLASHv1/driver.mk b/os/hal/ports/NUMICRO/LLD/FLASHv1/driver.mk new file mode 100644 index 00000000..3fa4c992 --- /dev/null +++ b/os/hal/ports/NUMICRO/LLD/FLASHv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_EFL TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/FLASHv1/hal_efl_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/FLASHv1/hal_efl_lld.c +endif + +PLATFORMINC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/FLASHv1 diff --git a/os/hal/ports/NUMICRO/LLD/FLASHv1/hal_efl_lld.c b/os/hal/ports/NUMICRO/LLD/FLASHv1/hal_efl_lld.c new file mode 100644 index 00000000..a2206e75 --- /dev/null +++ b/os/hal/ports/NUMICRO/LLD/FLASHv1/hal_efl_lld.c @@ -0,0 +1,648 @@ +/* + ChibiOS - Copyright (C) 2020 Alex Lewontin + + 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 NUC123 Embedded Flash subsystem low level driver source. + * + * @addtogroup HAL_EFL + * @{ + */ + +#include "hal.h" + +#if HAL_USE_EFL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define NUC123_LFOM_UPPERBOUND 25000000UL +#define NUC123_MFOM_UPPERBOUND 50000000UL + +#define FMC_FATCON_LFOM_Pos FMC_FATCON_FOMSEL0_Pos +#define FMC_FATCON_LFOM_Msk FMC_FATCON_FOMSEL0_Msk +#define FMC_FATCON_MFOM_Pos FMC_FATCON_FOMSEL1_Pos +#define FMC_FATCON_MFOM_Msk FMC_FATCON_FOMSEL1_Msk + +#define NUC123_PAGE_SIZE 4UL +#define NUC123_SECTOR_SIZE 0x200UL + +#define NUC123_LDROM_SIZE 0x1000UL +#define NUC123_APROM_SIZE (NUC123_FLASH_SIZE - NUC123_DATAFLASH_SIZE) + +#define NUC123_EFL_CMD_ERASE 0x22UL +#define NUC123_EFL_CMD_PROG 0x21UL +#define NUC123_EFL_CMD_READ 0UL +#define NUC123_EFL_CMD_CHIPERASE 0x26UL /* Undocumented */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief EFL1 driver identifier. + */ +#if (NUC123_EFL_USE_EFL1 == TRUE) || defined(__DOXYGEN__) +EFlashDriver EFLD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const flash_descriptor_t efl_lld_descriptors[] = { +#if (NUC123_EFL_ACCESS_APROM == TRUE) || defined(__DOXYGEN__) + {.attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_MEMORY_MAPPED | + FLASH_ATTR_REWRITABLE, + .page_size = NUC123_PAGE_SIZE, + .sectors_count = NUC123_APROM_SIZE / NUC123_SECTOR_SIZE, + .sectors = NULL, + .sectors_size = NUC123_SECTOR_SIZE, + .address = (uint8_t *)0, + .size = NUC123_APROM_SIZE}, +#endif +#if (NUC123_EFL_ACCESS_DATAFLASH == TRUE) || defined(__DOXYGEN__) + {.attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_MEMORY_MAPPED | + FLASH_ATTR_REWRITABLE, + .page_size = NUC123_PAGE_SIZE, + .sectors_count = NUC123_DATAFLASH_SIZE / NUC123_SECTOR_SIZE, + .sectors = NULL, + .sectors_size = NUC123_SECTOR_SIZE, + .address = (uint8_t *)NUC123_DFBADDR, + .size = NUC123_DATAFLASH_SIZE}, +#endif +#if (NUC123_EFL_ACCESS_LDROM == TRUE) || defined(__DOXYGEN__) + {.attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_MEMORY_MAPPED | + FLASH_ATTR_REWRITABLE, + .page_size = NUC123_PAGE_SIZE, + .sectors_count = NUC123_LDROM_SIZE / NUC123_SECTOR_SIZE, + .sectors = NULL, + .sectors_size = NUC123_SECTOR_SIZE, + .address = (uint8_t *)0x100000, + .size = NUC123_LDROM_SIZE}, +#endif +#if (NUC123_EFL_ACCESS_CONFIG == TRUE) || defined(__DOXYGEN__) + {.attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_MEMORY_MAPPED | + FLASH_ATTR_REWRITABLE, + .page_size = NUC123_PAGE_SIZE, + .sectors_count = 1, + .sectors = NULL, + .sectors_size = NUC123_SECTOR_SIZE, + .address = (uint8_t *)0x300000, + .size = 8}, +#endif +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/* Starts the ISP function, does not block */ +static inline void start_ISP(void) +{ + SystemUnlockReg(); + FMC->ISPTRG |= FMC_ISPTRG_ISPGO_Msk; + __ISB(); + LOCKREG(); +} + +/* Starts the ISP function and blocks til conclusion */ +static inline flash_error_t do_ISP(void) +{ + start_ISP(); + while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) + ; + if (FMC->ISPCON & FMC_ISPCON_ISPFF_Msk) { + return FLASH_ERROR_HW_FAILURE; + } + + return FLASH_NO_ERROR; +} + +/** + * @brief Returns the minimum of two unsigned values. A safer implementation + * of the classic macro + * + * @param[in] x An unsigned value + * @param[in] y An unsigned value + * + * @return The smaller of x and y + * + * @notapi + */ +static inline unsigned min(unsigned x, unsigned y) +{ + return ((x > y) ? y : x); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level Embedded Flash driver initialization. + * + * @notapi + */ +void efl_lld_init(void) +{ + +#if (NUC123_EFL_USE_EFL1 == TRUE) + eflObjectInit(&EFLD1); + EFLD1.bank = 0; +#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) +{ + uint32_t ispcon; + if (eflp->state == FLASH_STOP) { + SystemUnlockReg(); + ispcon = FMC->ISPCON; + + ispcon |= (FMC_ISPCON_ISPEN_Msk); + /* Enables the peripheral.*/ + CLK->APBCLK |= CLK_AHBCLK_ISP_EN_Msk; + +#if NUC123_HCLK < NUC123_LFOM_UPPERBOUND + FMC->FATCON |= FMC_FATCON_LFOM_Msk; +#elif NUC123_HCLK < NUC123_MFOM_UPPERBOUND + FMC->FATCON |= FMC_FATCON_MFOM_Msk; +#endif + +#if (NUC123_EFL_ACCESS_APROM == TRUE) || (NUC123_EFL_ACCESS_DATAFLASH == TRUE) + ispcon |= FMC_ISPCON_APUEN_Msk; +#endif + +#if (NUC123_EFL_ACCESS_LDROM == TRUE) + ispcon |= FMC_ISPCON_LDUEN_Msk; +#endif + +#if (NUC123_EFL_ACCESS_CONFIG == TRUE) + ispcon |= FMC_ISPCON_CFGUEN_Msk; +#endif + + FMC->ISPCON = ispcon; + LOCKREG(); + } +} + +/** + * @brief Deactivates the Embedded Flash peripheral. + * + * @param[in] eflp pointer to a @p EFlashDriver structure + * + * @notapi + */ +void efl_lld_stop(EFlashDriver* eflp) +{ + uint32_t ispcon; + if (eflp->state == FLASH_READY) { + SystemUnlockReg(); + ispcon = FMC->ISPCON; + + ispcon &= ~FMC_ISPCON_ISPEN_Msk; + /* Disables the peripheral.*/ + +#if (NUC123_EFL_ACCESS_APROM == TRUE) || (NUC123_EFL_ACCESS_DATAFLASH == TRUE) + ispcon &= ~FMC_ISPCON_APUEN_Msk; +#endif +#if (NUC123_EFL_ACCESS_LDROM == TRUE) + ispcon &= ~FMC_ISPCON_LDUEN_Msk; +#endif +#if (NUC123_EFL_ACCESS_CONFIG == TRUE) + ispcon &= ~FMC_ISPCON_CFGUEN_Msk; +#endif + + FMC->ISPCON = ispcon; + CLK->APBCLK &= ~CLK_AHBCLK_ISP_EN_Msk; + LOCKREG(); + } +} + +/** + * @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) +{ + return efl_lld_descriptors + ((EFlashDriver *)instance)->bank; +} + +/** + * @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; + const flash_descriptor_t *desc = efl_lld_get_descriptor(instance); + flash_error_t err = FLASH_NO_ERROR; + uint32_t data; + + osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U)); + osalDbgCheck(((size_t)offset + n) <= (size_t)desc->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; + + FMC->ISPCMD = NUC123_EFL_CMD_READ; + + while (n) { + FMC->ISPADR = (uint32_t)desc->address + (offset & ~3); + err = do_ISP(); + if (err) { + break; + } + data = FMC->ISPDAT; + /* For most iterations, the switch doesn't do anything, but it doesn't + hurt, and it allows us to consolidate the leading partial word + with the rest, which compiles smaller. The compiler is pretty good + at pulling things out of the loop, if speed is more important. */ + switch (offset % 4) { + case 0: + *(rp++) = (uint8_t)((data >> 0) & 0xFF); + if (!(--n)) { break; } + /* fallthrough */ + case 1: + *(rp++) = (uint8_t)((data >> 8) & 0xFF); + if (!(--n)) { break; } + /* fallthrough */ + case 2: + *(rp++) = (uint8_t)((data >> 16) & 0xFF); + if (!(--n)) { break; } + /* fallthrough */ + case 3: + *(rp++) = (uint8_t)((data >> 24) & 0xFF); + if (!(--n)) { break; } + } + offset += (4 - (offset % 4)); + } + + /* Ready state again.*/ + devp->state = FLASH_READY; + + return err; +} + +/** + * @brief Program operation. + * + * @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; + const flash_descriptor_t *desc = efl_lld_get_descriptor(instance); + flash_error_t err = FLASH_NO_ERROR; + uint32_t data; + + osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U)); + osalDbgCheck(((size_t)offset + n) <= (size_t)desc->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; + + if (offset % 4) { + FMC->ISPCMD = NUC123_EFL_CMD_READ; + FMC->ISPADR = (uint32_t)desc->address + (offset & ~3); + err = do_ISP(); + if (err) { + /* Ready state again.*/ + devp->state = FLASH_READY; + return err; + } + data = FMC->ISPDAT; + switch (offset % 4) { + case 1: + data &= 0xFFFF00FF; + data |= (*(pp++) << 8); + if (!(--n)) { + break; + } + /* fallthrough */ + case 2: + data &= 0xFF00FFFF; + data |= (*(pp++) << 16); + if (!(--n)) { + break; + } + /* fallthrough */ + case 3: + data &= 0x00FFFFFF; + data |= (*(pp++) << 24); + if (!(--n)) { + break; + } + } + + FMC->ISPDAT = data; + FMC->ISPCMD = NUC123_EFL_CMD_PROG; + err = do_ISP(); + if (err) { + /* Ready state again.*/ + devp->state = FLASH_READY; + return err; + } + + offset += 4 - (offset % 4); + } + + FMC->ISPCMD = NUC123_EFL_CMD_PROG; + + while (n >= 4) { + FMC->ISPADR = (uint32_t)desc->address + offset; + FMC->ISPDAT = (*(pp + 0)) | (*(pp + 1) << 8) | + (*(pp + 2) << 16) | (*(pp + 3) << 24); + err = do_ISP(); + if (err) { + /* Ready state again.*/ + devp->state = FLASH_READY; + return err; + } + n -= 4; + pp += 4; + offset += 4; + } + + if (n) { + FMC->ISPCMD = NUC123_EFL_CMD_READ; + FMC->ISPADR = (uint32_t)desc->address + offset; + err = do_ISP(); + if (err) { + /* Ready state again.*/ + devp->state = FLASH_READY; + return err; + } + data = FMC->ISPDAT; + + switch (n) { + case 3: + data &= 0xFF00FFFF; + data |= (pp[2] << 16); + /* fallthrough */ + case 2: + data &= 0xFFFF00FF; + data |= (pp[1] << 8); + /* fallthrough */ + case 1: + data &= 0xFFFFFF00; + data |= (pp[0] << 0); + } + FMC->ISPDAT = data; + FMC->ISPCMD = NUC123_EFL_CMD_PROG; + err = do_ISP(); + } + + /* Ready state again.*/ + devp->state = FLASH_READY; + return err; +} + +/** + * @brief Starts a whole-device erase operation. + * @note This operation erases the entirety of the bank associated with + * the driver indicated by @p instance. Calling this function on + * the bank that contains the code that is currently executing + * will result in undefined behavior. + * @note This operation is not supported asynchronously, so this will + * not return until all erases have been completed. + * + * @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; + const flash_descriptor_t *desc = efl_lld_get_descriptor(instance); + flash_error_t err = FLASH_NO_ERROR; + + 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; + + FMC->ISPCMD = NUC123_EFL_CMD_ERASE; + + for (uint8_t i = 0; i < desc->sectors_count; ++i) + { + FMC->ISPADR = (uint32_t)((i * (desc->sectors_size)) + + desc->address); + err = do_ISP(); + if (err) { + break; + } + } + + devp->state = FLASH_READY; + return err; +} + +/** + * @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; + const flash_descriptor_t *desc = efl_lld_get_descriptor(instance); + + osalDbgCheck(instance != NULL); + osalDbgCheck(sector < desc->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_ERASE state while the operation is performed.*/ + devp->state = FLASH_ERASE; + + FMC->ISPCMD = NUC123_EFL_CMD_ERASE; + FMC->ISPADR = (uint32_t)((sector * (desc->sectors_size)) + + desc->address); + start_ISP(); + + 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; + + /* TODO: figure out an actual amount of time */ + *msec = 0UL; + + /* If there is an erase in progress then the device must be checked.*/ + if (devp->state == FLASH_ERASE) { + if (FMC->ISPSTA & FMC_ISPSTA_ISPGO_Msk) { + return FLASH_BUSY_ERASING; + } + + if (FMC->ISPCON & FMC_ISPCON_ISPFF_Msk) { + return FLASH_ERROR_HW_FAILURE; + } + + devp->state = FLASH_READY; + } + + return FLASH_NO_ERROR; +} + +/** + * @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; + const flash_descriptor_t *desc = efl_lld_get_descriptor(instance); + flash_error_t err = FLASH_NO_ERROR; + + osalDbgCheck(instance != NULL); + osalDbgCheck(sector < desc->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; + } + + devp->state = FLASH_READ; + + FMC->ISPCMD = NUC123_EFL_CMD_READ; + + for (size_t i = 0; i < desc->sectors_size; i = i + 4) { + FMC->ISPADR = (uint32_t)desc->address + (desc->sectors_size * sector) + i; + err = do_ISP(); + if (err) { + break; + } + if (FMC->ISPDAT != 0xFFFFFFFF) { + err = FLASH_ERROR_VERIFY; + break; + } + } + + /* Ready state again.*/ + devp->state = FLASH_READY; + return err; +} + +#endif /* HAL_USE_EFL == TRUE */ + +/** @} */ diff --git a/os/hal/ports/NUMICRO/LLD/FLASHv1/hal_efl_lld.h b/os/hal/ports/NUMICRO/LLD/FLASHv1/hal_efl_lld.h new file mode 100644 index 00000000..200955c2 --- /dev/null +++ b/os/hal/ports/NUMICRO/LLD/FLASHv1/hal_efl_lld.h @@ -0,0 +1,167 @@ +/* + ChibiOS - Copyright (C) 2020 Alex Lewontin + + 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 NUC123 Embedded Flash subsystem low level driver header. + * @note This driver only supports management of APROM. LDROM, config + * registers, and data flash (not yet supported by the platform driver) + * are not supported. + * @addtogroup HAL_EFL + * @{ + */ + +#ifndef HAL_EFL_LLD_H +#define HAL_EFL_LLD_H + +#if HAL_USE_EFL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name NUC123 configuration options + * @{ + */ +/** + * @brief EFL1 driver enable switch. + * @details If set to @p TRUE the support for EFL1 is included. + * + * @note The default is @p TRUE. + */ +#if !defined(NUC123_EFL_USE_EFL1) || defined(__DOXYGEN__) +#define NUC123_EFL_USE_EFL1 TRUE +#endif + +/** + * @brief APROM access enable switch. + * @details If set to @p TRUE the support for APROM access is included. + * + * @note The default is @p FALSE. + */ +#if !defined(NUC123_EFL_ACCESS_APROM) || defined(__DOXYGEN__) +#define NUC123_EFL_ACCESS_APROM FALSE +#endif + +/** + * @brief Data flash access enable switch. + * @details If set to @p TRUE the support for data flash access is included. + * + * @note The default is @p FALSE. + */ +#if !defined(NUC123_EFL_ACCESS_DATAFLASH) || defined(__DOXYGEN__) +#define NUC123_EFL_ACCESS_DATAFLASH FALSE +#endif + +/** + * @brief LDROM access enable switch. + * @details If set to @p FALSE the support for LDROM access is included. + * + * @note The default is @p FALSE. + */ +#if !defined(NUC123_EFL_ACCESS_LDROM) || defined(__DOXYGEN__) +#define NUC123_EFL_ACCESS_LDROM FALSE +#endif + +/** + * @brief CONFIG0/1 access enable switch. + * @details If set to @p FALSE the support for CONFIG0/1 access is included. + * + * @note The default is @p FALSE. + */ +#if !defined(NUC123_EFL_ACCESS_CONFIG) || defined(__DOXYGEN__) +#define NUC123_EFL_ACCESS_CONFIG FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +typedef enum { +#if (NUC123_EFL_ACCESS_APROM == TRUE) || defined(__DOXYGEN__) + NUC123_EFL_BANK_APROM, +#endif +#if (NUC123_EFL_ACCESS_DATAFLASH == TRUE) || defined(__DOXYGEN__) + NUC123_EFL_BANK_DATAFLASH, +#endif +#if (NUC123_EFL_ACCESS_LDROM == TRUE) || defined(__DOXYGEN__) + NUC123_EFL_BANK_LDROM, +#endif +#if (NUC123_EFL_ACCESS_CONFIG == TRUE) || defined(__DOXYGEN__) + NUC123_EFL_BANK_CONFIG, +#endif + NUC123_EFL_BANK_NONE +} nuc123_eflbank_t; +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the embedded flash driver structure. + */ +#define efl_lld_driver_fields \ + /* The currently used bank.*/ \ + nuc123_eflbank_t bank + +/** + * @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 (NUC123_EFL_USE_EFL1 == TRUE) && !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 *msec); +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 */ + +/** @} */ diff --git a/os/hal/ports/NUMICRO/NUC123/hal_lld.h b/os/hal/ports/NUMICRO/NUC123/hal_lld.h index 8c14bcd9..7154ff55 100644 --- a/os/hal/ports/NUMICRO/NUC123/hal_lld.h +++ b/os/hal/ports/NUMICRO/NUC123/hal_lld.h @@ -43,6 +43,7 @@ #define PLATFORM_NAME "NUC123SD4AN0 NUC123 Cortex M0 USB Micro" #define NUC123xxxANx #undef NUC123xxxAEx +#define NUC123_FLASH_SIZE 0x11000 #else #error "NUC123 device unsupported or not specified" #endif @@ -184,6 +185,13 @@ /** * @brief Enables or disables data flash + * @warning If data this is set to @p TRUE, the data flash + * is subtracted from the APROM. The linker script is not aware + * of this, so therefore it is the responsiblity of the user to ensure + * that the combination of the data flash & the text section still fit + * into ROM. + + * @note The default is @p FALSE. */ #if !defined(NUC123_DATAFLASH_ENABLED) || defined(__DOXYGEN__) #define NUC123_DATAFLASH_ENABLED FALSE @@ -229,7 +237,7 @@ /* * Persistant configuration settings. */ -#if NUC123_DATAFLASH_ENABLE +#if (NUC123_DATAFLASH_ENABLED == TRUE) #if (NUC123_DATAFLASH_SIZE == 4096) /* DFVSEN = 1, nothing else matters */ diff --git a/os/hal/ports/NUMICRO/NUC123/platform.mk b/os/hal/ports/NUMICRO/NUC123/platform.mk index 5fc04b14..741d66c8 100644 --- a/os/hal/ports/NUMICRO/NUC123/platform.mk +++ b/os/hal/ports/NUMICRO/NUC123/platform.mk @@ -17,6 +17,7 @@ include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/driver.mk include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/USBv1/driver.mk include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/SERIALv1/driver.mk include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/I2Cv1/driver.mk +include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/FLASHv1/driver.mk # Shared variables ALLCSRC += $(PLATFORMSRC)