NUC123: EFL driver
This commit is contained in:
parent
09394a1b1a
commit
4cbc3250c0
|
@ -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
|
|
@ -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 */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -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 */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -43,6 +43,7 @@
|
||||||
#define PLATFORM_NAME "NUC123SD4AN0 NUC123 Cortex M0 USB Micro"
|
#define PLATFORM_NAME "NUC123SD4AN0 NUC123 Cortex M0 USB Micro"
|
||||||
#define NUC123xxxANx
|
#define NUC123xxxANx
|
||||||
#undef NUC123xxxAEx
|
#undef NUC123xxxAEx
|
||||||
|
#define NUC123_FLASH_SIZE 0x11000
|
||||||
#else
|
#else
|
||||||
#error "NUC123 device unsupported or not specified"
|
#error "NUC123 device unsupported or not specified"
|
||||||
#endif
|
#endif
|
||||||
|
@ -184,6 +185,13 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enables or disables data flash
|
* @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__)
|
#if !defined(NUC123_DATAFLASH_ENABLED) || defined(__DOXYGEN__)
|
||||||
#define NUC123_DATAFLASH_ENABLED FALSE
|
#define NUC123_DATAFLASH_ENABLED FALSE
|
||||||
|
@ -229,7 +237,7 @@
|
||||||
/*
|
/*
|
||||||
* Persistant configuration settings.
|
* Persistant configuration settings.
|
||||||
*/
|
*/
|
||||||
#if NUC123_DATAFLASH_ENABLE
|
#if (NUC123_DATAFLASH_ENABLED == TRUE)
|
||||||
|
|
||||||
#if (NUC123_DATAFLASH_SIZE == 4096)
|
#if (NUC123_DATAFLASH_SIZE == 4096)
|
||||||
/* DFVSEN = 1, nothing else matters */
|
/* DFVSEN = 1, nothing else matters */
|
||||||
|
|
|
@ -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/USBv1/driver.mk
|
||||||
include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/SERIALv1/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/I2Cv1/driver.mk
|
||||||
|
include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/FLASHv1/driver.mk
|
||||||
|
|
||||||
# Shared variables
|
# Shared variables
|
||||||
ALLCSRC += $(PLATFORMSRC)
|
ALLCSRC += $(PLATFORMSRC)
|
||||||
|
|
Loading…
Reference in New Issue