Merge pull request #324 from WestberryTech/chibios-21.11.x-wb

Add some processing to the WB32 MCU series.
This commit is contained in:
Fabien Poussin 2022-07-27 10:46:15 +02:00 committed by GitHub
commit d03aa9cc2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1328 additions and 5 deletions

View File

@ -945,8 +945,24 @@ typedef struct
#warning Not supported compiler type
#endif
static const uint32_t flash_size_code_map[16] = {
0x80000, /* 512kB */
0x8000, /* 32kB */
0x60000, /* 384kB */
0x40000, /* 256kB */
0x20000, /* 128kB */
0x8000, /* 32kB */
0x18000, /* 96kB */
0x10000, /* 64kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x30000, /* 192kB */
};
/* ================================================================================ */
/* ================ Peripheral memory map ================ */
@ -958,6 +974,9 @@ typedef struct
#define SRAM_BB_BASE ((uint32_t)0x22000000UL) /*!< SRAM base address in the bit-band region */
#define PERIPH_BB_BASE ((uint32_t)0x42000000UL) /*!< Peripheral base address in the bit-band region */
#define SYS_MEMSE ((uint32_t)0x40016404UL)
#define FLASH_SIZE flash_size_code_map[(*((volatile uint32_t *)(SYS_MEMSE))) & 0xFU]
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x08000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x10000)

View File

@ -890,6 +890,24 @@ typedef struct
#warning Not supported compiler type
#endif
static const uint32_t flash_size_code_map[16] = {
0x80000, /* 512kB */
0x8000, /* 32kB */
0x60000, /* 384kB */
0x40000, /* 256kB */
0x20000, /* 128kB */
0x8000, /* 32kB */
0x18000, /* 96kB */
0x10000, /* 64kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x8000, /* 32kB */
0x30000, /* 192kB */
};
/* ================================================================================ */
/* ================ Peripheral memory map ================ */
@ -901,6 +919,9 @@ typedef struct
#define SRAM_BB_BASE ((uint32_t)0x22000000UL) /*!< SRAM base address in the bit-band region */
#define PERIPH_BB_BASE ((uint32_t)0x42000000UL) /*!< Peripheral base address in the bit-band region */
#define SYS_MEMSE ((uint32_t)0x40016404UL)
#define FLASH_SIZE flash_size_code_map[(*((volatile uint32_t *)(SYS_MEMSE))) & 0xFU]
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x08000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x10000)

View File

@ -472,6 +472,7 @@ struct USBDriver {
WB32_USB->POWER |= USB_POWER_RESUME; \
osalThreadSleepMilliseconds(WB32_USB_HOST_WAKEUP_DURATION); \
WB32_USB->POWER &= ~USB_POWER_RESUME; \
_usb_wakeup(usbp); \
} while (false)
/*===========================================================================*/

View File

@ -0,0 +1,517 @@
/*
Copyright (C) 2021...2022 Westberry Technology (ChangZhou) Corp., Ltd
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 <string.h>
#include "hal.h"
#if (HAL_USE_EFL == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define WB32_FLASH_LINE_SIZE 8U
#define WB32_FLASH_LINE_MASK (WB32_FLASH_LINE_SIZE - 1U)
#define WB32_FLASH_PAGE_SIZE 256U
#define WB32_FLASH_PAGE_MASK (WB32_FLASH_PAGE_SIZE - 1U)
#define FLASH_OP_RAM_CODE {0xBF006008, 0x06006808, 0x4770D4FC}
static const uint32_t pre_op_code[] = {0x4FF0E92D, 0x21034832, 0x210C6281, 0xF8DF62C1, 0x2100C0C4, 0x1000F8CC, 0xF44F4608, 0x1C40767A, 0xDBFC42B0, 0xF8CC2201, 0x20002000, 0x42B01C40, 0x4829DBFC, 0xF0436803, 0x60030380, 0x302C4826, 0xF4436803, 0x60036320, 0x46104691, 0x323C4A22, 0x468A6010, 0x49214608, 0x48216008, 0x0340F8D0, 0x25004F1E, 0x5107F3C0, 0x3BFFF04F, 0x22001F3F, 0x4610465C, 0xEA5F683B, 0xD10678C0, 0xD10142A3, 0xE0002401, 0x44222400, 0x1C40461C, 0xDBF12814, 0xD91B2A02, 0xD9012910, 0xE0003910, 0x480D2100, 0x68021F00, 0x627FF022, 0x5201EA42, 0xF8CC6002, 0x2000A000, 0x42B01C40, 0xF8CCDBFC, 0x20009000, 0x42B01C40, 0x1C6DDBFC, 0xDBD02D05, 0x8FF0E8BD, 0x40010000, 0x40010438, 0x40010C20, 0x4000B804, 0x1FFFF000};
#define PRE_OP() ((void (*)(void))((unsigned int)(pre_op_code) | 0x01))()
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief EFL1 driver identifier.
*/
EFlashDriver EFLD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
static const flash_descriptor_t efl_lld_descriptor = {
.attributes = FLASH_ATTR_MEMORY_MAPPED,
.page_size = WB32_FLASH_LINE_SIZE,
.sectors_count = WB32_FLASH_NUMBER_OF_BANKS *
WB32_FLASH_SECTORS_PER_BANK,
.sectors = NULL,
.sectors_size = WB32_FLASH_SECTOR_SIZE,
.address = (uint8_t *)FLASH_BASE,
.size = WB32_FLASH_NUMBER_OF_BANKS *
WB32_FLASH_SECTORS_PER_BANK *
WB32_FLASH_SECTOR_SIZE
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static inline uint8_t wb32_flash_op_exec(EFlashDriver *eflp, uint32_t op) {
volatile uint32_t flash_op_ram_code[] = FLASH_OP_RAM_CODE;
/* Start FLASH operation and wait for a FLASH operation to complete */
RCC->PCLKENR = 0x01;
eflp->flash->CON = 0x7F5F0D40 | (op & 0x1F); /* [14:8]=0x0D, WREN=1, [4:0]=op */
eflp->flash->KEY = 0x5188DA08;
eflp->flash->KEY = 0x12586590;
((void(*)(uint32_t, uint32_t))((unsigned int)(flash_op_ram_code) | 0x01))(0x00800080, FMC_BASE);
RCC->PCLKENR = 0x00;
/* Clear WREN and OP[4:0] bits */
eflp->flash->CON = 0x005F0000;
if (eflp->flash->STAT & FMC_STAT_ERR)
return 1; /* Any error occur */
else
return 0; /* FLASH operation complete */
}
static inline flash_error_t wb32_flash_program_page(EFlashDriver *eflp, uint32_t page_addr) {
uint8_t ret;
int state;
state = __get_PRIMASK();
__disable_irq();
PRE_OP();
eflp->flash->ADDR = page_addr;
ret = wb32_flash_op_exec(eflp, 0x0C);
if (!state) {
__enable_irq();
}
if (ret)
return FLASH_ERROR_PROGRAM;
else
return FLASH_NO_ERROR;
}
static inline flash_error_t wb32_flash_erase_page(EFlashDriver *eflp, uint32_t page_addr) {
uint8_t ret;
int state;
state = __get_PRIMASK();
__disable_irq();
PRE_OP();
eflp->flash->ADDR = page_addr;
ret = wb32_flash_op_exec(eflp, 0x08);
if (!state) {
__enable_irq();
}
if (ret)
return FLASH_ERROR_ERASE;
else
return FLASH_NO_ERROR;
}
static inline flash_error_t wb32_flash_clear_page_latch(EFlashDriver *eflp) {
uint8_t ret;
int state;
state = __get_PRIMASK();
__disable_irq();
ret = wb32_flash_op_exec(eflp, 0x04);
if (!state) {
__enable_irq();
}
if (ret)
return FLASH_ERROR_PROGRAM;
else
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 = FMC;
}
/**
* @brief Configures and activates the Embedded Flash peripheral.
*
* @param[in] eflp pointer to a @p EFlashDriver structure
*
* @notapi
*/
void efl_lld_start(EFlashDriver *eflp) {
PWR->ANAKEY1 = 0x03;
PWR->ANAKEY2 = 0x0C;
/* Enables or disables the Internal 48MHz oscillator (FHSI). */
ANCTL->FHSIENR = ENABLE;
/* Locks write to ANCTL registers */
PWR->ANAKEY1 = 0x00;
PWR->ANAKEY2 = 0x00;
}
/**
* @brief Deactivates the Embedded Flash peripheral.
*
* @param[in] eflp pointer to a @p EFlashDriver structure
*
* @notapi
*/
void efl_lld_stop(EFlashDriver *eflp) {
/* Lock flash. */
eflp->flash->KEY = 0x00;
eflp->flash->KEY = 0x00;
}
/**
* @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;
/* Actual read implementation.*/
memcpy((void *)rp, (const void *)(efl_lld_descriptor.address + offset), n);
/* 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;
/* Actual program implementation.*/
while (n > 0U) {
volatile uint32_t *address;
union {
uint32_t w[WB32_FLASH_PAGE_SIZE / sizeof (uint32_t)];
uint8_t b[WB32_FLASH_PAGE_SIZE / sizeof (uint8_t)];
} line;
/* Programming address aligned to flash pages.*/
address = (volatile uint32_t *)(efl_lld_descriptor.address +
(offset & ~WB32_FLASH_PAGE_MASK));
memcpy((void *)&line.b[0], (const void *)address, WB32_FLASH_PAGE_SIZE);
#ifndef WB32_FLASH_PROGRAM_NO_ERASE
/* Erase page. */
err = wb32_flash_erase_page(devp, (uint32_t)address);
if (err != FLASH_NO_ERROR) {
break;
}
#endif
/* Clear page latch. */
err = wb32_flash_clear_page_latch(devp);
if (err != FLASH_NO_ERROR) {
break;
}
/* Copying data inside the prepared page.*/
do {
line.b[offset & WB32_FLASH_PAGE_MASK] = *pp;
offset++;
n--;
pp++;
}
while ((n > 0U) & ((offset & WB32_FLASH_PAGE_MASK) != 0U));
for (int i = 0; i < (WB32_FLASH_PAGE_SIZE / sizeof(uint32_t)); i++) {
devp->flash->BUF[i] = line.w[i];
}
/* Programming page.*/
err = wb32_flash_program_page(devp, (uint32_t)address);
if (err != FLASH_NO_ERROR) {
break;
}
/* Check for flash error.*/
if (address[0] != line.w[0]) {
err = FLASH_ERROR_PROGRAM;
break;
}
}
/* 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) {
(void) instance;
return FLASH_ERROR_UNIMPLEMENTED;
}
/**
* @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;
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 erasing while erasing.*/
if (devp->state == FLASH_ERASE) {
return FLASH_BUSY_ERASING;
}
/* FLASH_PGM state while the operation is performed.*/
devp->state = FLASH_ERASE;
/* Set the page.*/
err = wb32_flash_erase_page(devp, (uint32_t)(efl_lld_descriptor.address +
flashGetSectorOffset(getBaseFlash(devp), sector)));
return err;
}
/**
* @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) {
/* Checking for operation in progress.*/
if ((devp->flash->CON & FMC_CON_WR) == 0U) {
/* Back to ready state.*/
devp->state = FLASH_READY;
err = FLASH_NO_ERROR;
}
else {
/* Recommended time before polling again, this is a simplified
implementation.*/
if (msec != NULL) {
*msec = (uint32_t)WB32_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] 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;
uint32_t *address;
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;
}
/* Address of the sector.*/
address = (uint32_t *)(efl_lld_descriptor.address +
flashGetSectorOffset(getBaseFlash(devp), sector));
/* FLASH_READY state while the operation is performed.*/
devp->state = FLASH_READ;
/* Scanning the sector space.*/
for (int i = 0U; i < WB32_FLASH_SECTOR_SIZE / sizeof(uint32_t); i++) {
if (*address != 0x00) {
err = FLASH_ERROR_VERIFY;
break;
}
address++;
}
/* Ready state again.*/
devp->state = FLASH_READY;
return err;
}
#endif /* HAL_USE_EFL == TRUE */
/** @} */

View File

@ -0,0 +1,116 @@
/*
Copyright (C) 2021...2022 Westberry Technology (ChangZhou) Corp., Ltd
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 PLATFORM 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 WB32FQ95xx configuration options
* @{
*/
/**
* @brief Suggested wait time during erase operations polling.
*/
#if !defined(WB32_FLASH_WAIT_TIME_MS) || defined(__DOXYGEN__)
#define WB32_FLASH_WAIT_TIME_MS 20
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !defined(WB32_FLASH_NUMBER_OF_BANKS)
#error "WB32_FLASH_NUMBER_OF_BANKS not defined in registry"
#endif
#if !defined(WB32_FLASH_SECTORS_PER_BANK)
#error "WB32_FLASH_SECTORS_PER_BANK not defined in registry"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Low level fields of the embedded flash driver structure.
*/
#define efl_lld_driver_fields \
/* FMC registers.*/ \
FMC_TypeDef *flash
/**
* @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 *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 */
/** @} */

View File

@ -1,7 +1,8 @@
# Required platform files.
PLATFORMSRC_CONTRIB := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \
$(CHIBIOS_CONTRIB)/os/hal/ports/WB32/WB32F3G71xx/hal_lld.c \
$(CHIBIOS_CONTRIB)/os/hal/ports/WB32/WB32F3G71xx/wb32_isr.c
$(CHIBIOS_CONTRIB)/os/hal/ports/WB32/WB32F3G71xx/hal_lld.c \
$(CHIBIOS_CONTRIB)/os/hal/ports/WB32/WB32F3G71xx/wb32_isr.c \
$(CHIBIOS_CONTRIB)/os/hal/ports/WB32/WB32F3G71xx/hal_efl_lld.c
# Required include directories.
PLATFORMINC_CONTRIB := $(CHIBIOS)/os/hal/ports/common/ARMCMx \

View File

@ -69,6 +69,13 @@
#define WB32_HAS_EXTI15_10 TRUE
#define WB32_EXTI_NUM_LINES 19
/* Flash attributes.*/
#define WB32_FLASH_NUMBER_OF_BANKS 1
#define WB32_FLASH_SECTOR_SIZE 256U
#if !defined(WB32_FLASH_SECTORS_PER_BANK) || defined(__DOXYGEN__)
#define WB32_FLASH_SECTORS_PER_BANK 1024 /* Maximum, can be redefined.*/
#endif
/* DMAC1 attributes */
#define WB32_HAS_DMAC TRUE
#define WB32_HAS_DMAC1 TRUE

View File

@ -0,0 +1,517 @@
/*
Copyright (C) 2021...2022 Westberry Technology (ChangZhou) Corp., Ltd
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 <string.h>
#include "hal.h"
#if (HAL_USE_EFL == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define WB32_FLASH_LINE_SIZE 8U
#define WB32_FLASH_LINE_MASK (WB32_FLASH_LINE_SIZE - 1U)
#define WB32_FLASH_PAGE_SIZE 256U
#define WB32_FLASH_PAGE_MASK (WB32_FLASH_PAGE_SIZE - 1U)
#define FLASH_OP_RAM_CODE {0xBF006008, 0x06006808, 0x4770D4FC}
static const uint32_t pre_op_code[] = {0x4FF0E92D, 0x21034832, 0x210C6281, 0xF8DF62C1, 0x2100C0C4, 0x1000F8CC, 0xF44F4608, 0x1C40767A, 0xDBFC42B0, 0xF8CC2201, 0x20002000, 0x42B01C40, 0x4829DBFC, 0xF0436803, 0x60030380, 0x302C4826, 0xF4436803, 0x60036320, 0x46104691, 0x323C4A22, 0x468A6010, 0x49214608, 0x48216008, 0x0340F8D0, 0x25004F1E, 0x5107F3C0, 0x3BFFF04F, 0x22001F3F, 0x4610465C, 0xEA5F683B, 0xD10678C0, 0xD10142A3, 0xE0002401, 0x44222400, 0x1C40461C, 0xDBF12814, 0xD91B2A02, 0xD9012910, 0xE0003910, 0x480D2100, 0x68021F00, 0x627FF022, 0x5201EA42, 0xF8CC6002, 0x2000A000, 0x42B01C40, 0xF8CCDBFC, 0x20009000, 0x42B01C40, 0x1C6DDBFC, 0xDBD02D05, 0x8FF0E8BD, 0x40010000, 0x40010438, 0x40010C20, 0x4000B804, 0x1FFFF000};
#define PRE_OP() ((void (*)(void))((unsigned int)(pre_op_code) | 0x01))()
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief EFL1 driver identifier.
*/
EFlashDriver EFLD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
static const flash_descriptor_t efl_lld_descriptor = {
.attributes = FLASH_ATTR_MEMORY_MAPPED,
.page_size = WB32_FLASH_LINE_SIZE,
.sectors_count = WB32_FLASH_NUMBER_OF_BANKS *
WB32_FLASH_SECTORS_PER_BANK,
.sectors = NULL,
.sectors_size = WB32_FLASH_SECTOR_SIZE,
.address = (uint8_t *)FLASH_BASE,
.size = WB32_FLASH_NUMBER_OF_BANKS *
WB32_FLASH_SECTORS_PER_BANK *
WB32_FLASH_SECTOR_SIZE
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static inline uint8_t wb32_flash_op_exec(EFlashDriver *eflp, uint32_t op) {
volatile uint32_t flash_op_ram_code[] = FLASH_OP_RAM_CODE;
/* Start FLASH operation and wait for a FLASH operation to complete */
RCC->PCLKENR = 0x01;
eflp->flash->CON = 0x7F5F0D40 | (op & 0x1F); /* [14:8]=0x0D, WREN=1, [4:0]=op */
eflp->flash->KEY = 0x5188DA08;
eflp->flash->KEY = 0x12586590;
((void(*)(uint32_t, uint32_t))((unsigned int)(flash_op_ram_code) | 0x01))(0x00800080, FMC_BASE);
RCC->PCLKENR = 0x00;
/* Clear WREN and OP[4:0] bits */
eflp->flash->CON = 0x005F0000;
if (eflp->flash->STAT & FMC_STAT_ERR)
return 1; /* Any error occur */
else
return 0; /* FLASH operation complete */
}
static inline flash_error_t wb32_flash_program_page(EFlashDriver *eflp, uint32_t page_addr) {
uint8_t ret;
int state;
state = __get_PRIMASK();
__disable_irq();
PRE_OP();
eflp->flash->ADDR = page_addr;
ret = wb32_flash_op_exec(eflp, 0x0C);
if (!state) {
__enable_irq();
}
if (ret)
return FLASH_ERROR_PROGRAM;
else
return FLASH_NO_ERROR;
}
static inline flash_error_t wb32_flash_erase_page(EFlashDriver *eflp, uint32_t page_addr) {
uint8_t ret;
int state;
state = __get_PRIMASK();
__disable_irq();
PRE_OP();
eflp->flash->ADDR = page_addr;
ret = wb32_flash_op_exec(eflp, 0x08);
if (!state) {
__enable_irq();
}
if (ret)
return FLASH_ERROR_ERASE;
else
return FLASH_NO_ERROR;
}
static inline flash_error_t wb32_flash_clear_page_latch(EFlashDriver *eflp) {
uint8_t ret;
int state;
state = __get_PRIMASK();
__disable_irq();
ret = wb32_flash_op_exec(eflp, 0x04);
if (!state) {
__enable_irq();
}
if (ret)
return FLASH_ERROR_PROGRAM;
else
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 = FMC;
}
/**
* @brief Configures and activates the Embedded Flash peripheral.
*
* @param[in] eflp pointer to a @p EFlashDriver structure
*
* @notapi
*/
void efl_lld_start(EFlashDriver *eflp) {
PWR->ANAKEY1 = 0x03;
PWR->ANAKEY2 = 0x0C;
/* Enables or disables the Internal 48MHz oscillator (FHSI). */
ANCTL->FHSIENR = ENABLE;
/* Locks write to ANCTL registers */
PWR->ANAKEY1 = 0x00;
PWR->ANAKEY2 = 0x00;
}
/**
* @brief Deactivates the Embedded Flash peripheral.
*
* @param[in] eflp pointer to a @p EFlashDriver structure
*
* @notapi
*/
void efl_lld_stop(EFlashDriver *eflp) {
/* Lock flash. */
eflp->flash->KEY = 0x00;
eflp->flash->KEY = 0x00;
}
/**
* @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;
/* Actual read implementation.*/
memcpy((void *)rp, (const void *)(efl_lld_descriptor.address + offset), n);
/* 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;
/* Actual program implementation.*/
while (n > 0U) {
volatile uint32_t *address;
union {
uint32_t w[WB32_FLASH_PAGE_SIZE / sizeof (uint32_t)];
uint8_t b[WB32_FLASH_PAGE_SIZE / sizeof (uint8_t)];
} line;
/* Programming address aligned to flash pages.*/
address = (volatile uint32_t *)(efl_lld_descriptor.address +
(offset & ~WB32_FLASH_PAGE_MASK));
memcpy((void *)&line.b[0], (const void *)address, WB32_FLASH_PAGE_SIZE);
#ifndef WB32_FLASH_PROGRAM_NO_ERASE
/* Erase page. */
err = wb32_flash_erase_page(devp, (uint32_t)address);
if (err != FLASH_NO_ERROR) {
break;
}
#endif
/* Clear page latch. */
err = wb32_flash_clear_page_latch(devp);
if (err != FLASH_NO_ERROR) {
break;
}
/* Copying data inside the prepared page.*/
do {
line.b[offset & WB32_FLASH_PAGE_MASK] = *pp;
offset++;
n--;
pp++;
}
while ((n > 0U) & ((offset & WB32_FLASH_PAGE_MASK) != 0U));
for (int i = 0; i < (WB32_FLASH_PAGE_SIZE / sizeof(uint32_t)); i++) {
devp->flash->BUF[i] = line.w[i];
}
/* Programming page.*/
err = wb32_flash_program_page(devp, (uint32_t)address);
if (err != FLASH_NO_ERROR) {
break;
}
/* Check for flash error.*/
if (address[0] != line.w[0]) {
err = FLASH_ERROR_PROGRAM;
break;
}
}
/* 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) {
(void) instance;
return FLASH_ERROR_UNIMPLEMENTED;
}
/**
* @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;
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 erasing while erasing.*/
if (devp->state == FLASH_ERASE) {
return FLASH_BUSY_ERASING;
}
/* FLASH_PGM state while the operation is performed.*/
devp->state = FLASH_ERASE;
/* Set the page.*/
err = wb32_flash_erase_page(devp, (uint32_t)(efl_lld_descriptor.address +
flashGetSectorOffset(getBaseFlash(devp), sector)));
return err;
}
/**
* @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) {
/* Checking for operation in progress.*/
if ((devp->flash->CON & FMC_CON_WR) == 0U) {
/* Back to ready state.*/
devp->state = FLASH_READY;
err = FLASH_NO_ERROR;
}
else {
/* Recommended time before polling again, this is a simplified
implementation.*/
if (msec != NULL) {
*msec = (uint32_t)WB32_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] 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;
uint32_t *address;
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;
}
/* Address of the sector.*/
address = (uint32_t *)(efl_lld_descriptor.address +
flashGetSectorOffset(getBaseFlash(devp), sector));
/* FLASH_READY state while the operation is performed.*/
devp->state = FLASH_READ;
/* Scanning the sector space.*/
for (int i = 0U; i < WB32_FLASH_SECTOR_SIZE / sizeof(uint32_t); i++) {
if (*address != 0x00) {
err = FLASH_ERROR_VERIFY;
break;
}
address++;
}
/* Ready state again.*/
devp->state = FLASH_READY;
return err;
}
#endif /* HAL_USE_EFL == TRUE */
/** @} */

View File

@ -0,0 +1,116 @@
/*
Copyright (C) 2021...2022 Westberry Technology (ChangZhou) Corp., Ltd
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 PLATFORM 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 WB32FQ95xx configuration options
* @{
*/
/**
* @brief Suggested wait time during erase operations polling.
*/
#if !defined(WB32_FLASH_WAIT_TIME_MS) || defined(__DOXYGEN__)
#define WB32_FLASH_WAIT_TIME_MS 20
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !defined(WB32_FLASH_NUMBER_OF_BANKS)
#error "WB32_FLASH_NUMBER_OF_BANKS not defined in registry"
#endif
#if !defined(WB32_FLASH_SECTORS_PER_BANK)
#error "WB32_FLASH_SECTORS_PER_BANK not defined in registry"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Low level fields of the embedded flash driver structure.
*/
#define efl_lld_driver_fields \
/* FMC registers.*/ \
FMC_TypeDef *flash
/**
* @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 *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 */
/** @} */

View File

@ -1,7 +1,8 @@
# Required platform files.
PLATFORMSRC_CONTRIB := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \
$(CHIBIOS_CONTRIB)/os/hal/ports/WB32/WB32FQ95xx/hal_lld.c \
$(CHIBIOS_CONTRIB)/os/hal/ports/WB32/WB32FQ95xx/wb32_isr.c
$(CHIBIOS_CONTRIB)/os/hal/ports/WB32/WB32FQ95xx/wb32_isr.c \
$(CHIBIOS_CONTRIB)/os/hal/ports/WB32/WB32FQ95xx/hal_efl_lld.c
# Required include directories.
PLATFORMINC_CONTRIB := $(CHIBIOS)/os/hal/ports/common/ARMCMx \

View File

@ -69,6 +69,13 @@
#define WB32_HAS_EXTI15_10 TRUE
#define WB32_EXTI_NUM_LINES 19
/* Flash attributes.*/
#define WB32_FLASH_NUMBER_OF_BANKS 1
#define WB32_FLASH_SECTOR_SIZE 256U
#if !defined(WB32_FLASH_SECTORS_PER_BANK) || defined(__DOXYGEN__)
#define WB32_FLASH_SECTORS_PER_BANK 1024 /* Maximum, can be redefined.*/
#endif
/* DMAC1 attributes */
#define WB32_HAS_DMAC TRUE
#define WB32_HAS_DMAC1 TRUE