refactor: 完整C++面向对象重构(FlashManager)
This commit is contained in:
@@ -1,1375 +0,0 @@
|
||||
#include "flash_driver.h"
|
||||
#include "config.h"
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
/* GD32F4xx头文件 */
|
||||
#include "gd32f4xx.h"
|
||||
#include "gd32f4xx_fmc.h"
|
||||
|
||||
/* SPI驱动层接口 */
|
||||
#include "spi_driver.h"
|
||||
|
||||
/* 内部Flash私有数据结构体 */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t base_address; /* Flash基地址 */
|
||||
bool write_enabled; /* 写使能状态 */
|
||||
} internal_flash_private_t;
|
||||
|
||||
/* 外部SPI Flash私有数据结构体 */
|
||||
typedef struct
|
||||
{
|
||||
bool write_enabled; /* 写使能状态 */
|
||||
uint32_t manufacturer_id; /* 制造商ID */
|
||||
uint32_t device_id; /* 设备ID */
|
||||
} external_spi_flash_private_t;
|
||||
|
||||
/* 外部NOR Flash私有数据结构体 */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t exmc_bank; /* EXMC Bank编号 */
|
||||
uint32_t base_address; /* 基地址 */
|
||||
bool write_enabled; /* 写使能状态 */
|
||||
} external_nor_flash_private_t;
|
||||
|
||||
/* 通用Flash私有数据联合体 */
|
||||
typedef union
|
||||
{
|
||||
internal_flash_private_t internal;
|
||||
external_spi_flash_private_t external_spi;
|
||||
external_nor_flash_private_t external_nor;
|
||||
} flash_private_data_t;
|
||||
|
||||
/* 静态函数声明 */
|
||||
static ret_code_t init_external_spi_flash(flash_handle_t *handle);
|
||||
static ret_code_t read_external_spi_flash(flash_handle_t *handle, uint32_t address, void *buffer, uint32_t length);
|
||||
static ret_code_t write_external_spi_flash(flash_handle_t *handle, uint32_t address, const void *data, uint32_t length);
|
||||
static ret_code_t erase_external_spi_flash_sector(flash_handle_t *handle, uint32_t address);
|
||||
|
||||
/* SPI辅助函数声明 */
|
||||
static ret_code_t spi_flash_select(void);
|
||||
static ret_code_t spi_flash_deselect(void);
|
||||
static ret_code_t spi_flash_send_command(uint8_t cmd);
|
||||
static ret_code_t spi_flash_read_status(uint8_t *status);
|
||||
static ret_code_t spi_flash_wait_idle(void);
|
||||
static ret_code_t spi_flash_write_enable(void);
|
||||
|
||||
/* 外部NOR Flash静态函数声明 */
|
||||
static ret_code_t init_external_nor_flash(flash_handle_t *handle);
|
||||
static ret_code_t read_external_nor_flash(flash_handle_t *handle, uint32_t address, void *buffer, uint32_t length);
|
||||
static ret_code_t write_external_nor_flash(flash_handle_t *handle, uint32_t address, const void *data, uint32_t length);
|
||||
static ret_code_t erase_external_nor_flash_sector(flash_handle_t *handle, uint32_t address);
|
||||
|
||||
/* 内部Flash定义 */
|
||||
#define INTERNAL_FLASH_BASE_ADDR 0x08000000U
|
||||
|
||||
/* GD32F470ZGT6 Flash信息(1MB) */
|
||||
#define INTERNAL_FLASH_TOTAL_SIZE (1024 * 1024) /* 1MB */
|
||||
#define INTERNAL_FLASH_SECTOR_SIZE (16 * 1024) /* 16KB扇区 */
|
||||
#define INTERNAL_FLASH_PAGE_SIZE 256 /* 256字节页 */
|
||||
#define INTERNAL_FLASH_BLOCK_SIZE (64 * 1024) /* 64KB块 */
|
||||
|
||||
/* Flash操作超时 */
|
||||
#define FLASH_TIMEOUT 50000000U /* 进一步增加超时值,Flash扇区擦除可能需要200ms以上 */
|
||||
|
||||
/* 外部SPI Flash定义 (W25Qxx系列) */
|
||||
#define EXTERNAL_SPI_FLASH_BASE_ADDR 0x00000000U
|
||||
|
||||
/* W25Qxx系列SPI Flash命令 */
|
||||
#define SPI_FLASH_CMD_WRITE_ENABLE 0x06
|
||||
#define SPI_FLASH_CMD_WRITE_DISABLE 0x04
|
||||
#define SPI_FLASH_CMD_READ_STATUS_REG 0x05
|
||||
#define SPI_FLASH_CMD_WRITE_STATUS_REG 0x01
|
||||
#define SPI_FLASH_CMD_READ_DATA 0x03
|
||||
#define SPI_FLASH_CMD_FAST_READ 0x0B
|
||||
#define SPI_FLASH_CMD_PAGE_PROGRAM 0x02
|
||||
#define SPI_FLASH_CMD_SECTOR_ERASE 0x20
|
||||
#define SPI_FLASH_CMD_BLOCK_ERASE_32K 0x52
|
||||
#define SPI_FLASH_CMD_BLOCK_ERASE_64K 0xD8
|
||||
#define SPI_FLASH_CMD_CHIP_ERASE 0xC7
|
||||
#define SPI_FLASH_CMD_POWER_DOWN 0xB9
|
||||
#define SPI_FLASH_CMD_RELEASE_POWER_DOWN 0xAB
|
||||
#define SPI_FLASH_CMD_READ_MANUFACTURER_ID 0x90
|
||||
#define SPI_FLASH_CMD_READ_JEDEC_ID 0x9F
|
||||
#define SPI_FLASH_CMD_READ_UNIQUE_ID 0x4B
|
||||
|
||||
/* W25Qxx状态寄存器位 */
|
||||
#define SPI_FLASH_STATUS_BUSY (1 << 0)
|
||||
#define SPI_FLASH_STATUS_WRITE_ENABLE (1 << 1)
|
||||
#define SPI_FLASH_STATUS_BP0 (1 << 2)
|
||||
#define SPI_FLASH_STATUS_BP1 (1 << 3)
|
||||
#define SPI_FLASH_STATUS_BP2 (1 << 4)
|
||||
#define SPI_FLASH_STATUS_BP3 (1 << 5)
|
||||
#define SPI_FLASH_STATUS_SRWD (1 << 7)
|
||||
|
||||
/* 默认SPI Flash配置 (W25Q128FV - 16MB) */
|
||||
#define EXTERNAL_SPI_FLASH_TOTAL_SIZE (16 * 1024 * 1024) /* 16MB */
|
||||
#define EXTERNAL_SPI_FLASH_SECTOR_SIZE (4 * 1024) /* 4KB扇区 */
|
||||
#define EXTERNAL_SPI_FLASH_PAGE_SIZE 256 /* 256字节页 */
|
||||
#define EXTERNAL_SPI_FLASH_BLOCK_SIZE (64 * 1024) /* 64KB块 */
|
||||
|
||||
/* SPI Flash操作超时 */
|
||||
#define SPI_FLASH_TIMEOUT 20000000U /* 增加超时时间,扇区擦除可能需要100ms以上 */
|
||||
|
||||
/* 默认内部Flash句柄 */
|
||||
static flash_handle_t internal_flash_handle = {
|
||||
.type = FLASH_TYPE_INTERNAL,
|
||||
.config = {
|
||||
.type = FLASH_TYPE_INTERNAL,
|
||||
.base_address = INTERNAL_FLASH_BASE_ADDR,
|
||||
.clock_freq = 0,
|
||||
.cs_pin = 0,
|
||||
.spi_port = 0,
|
||||
.exmc_bank = 0},
|
||||
.info = {
|
||||
.total_size = INTERNAL_FLASH_TOTAL_SIZE, .sector_size = INTERNAL_FLASH_SECTOR_SIZE, .page_size = INTERNAL_FLASH_PAGE_SIZE, .block_size = INTERNAL_FLASH_BLOCK_SIZE, .manufacturer_id = 0x20, /* GD32制造商ID */
|
||||
.device_id = 0x470 /* GD32F470 */
|
||||
},
|
||||
.initialized = false,
|
||||
.private_data = NULL};
|
||||
|
||||
/* 默认外部SPI Flash句柄 (基于梁山派开发板实际硬件 - SPI4连接) */
|
||||
static flash_handle_t external_spi_flash_handle = {
|
||||
.type = FLASH_TYPE_EXTERNAL_SPI,
|
||||
.config = {
|
||||
.type = FLASH_TYPE_EXTERNAL_SPI,
|
||||
.base_address = EXTERNAL_SPI_FLASH_BASE_ADDR,
|
||||
.clock_freq = 1562500, /* APB2(100MHz)/64 = 1.5625MHz */
|
||||
.cs_pin = GPIO_PIN_6, /* GPIOF PIN_6 (PF6 - 梁山派开发板硬件CS) */
|
||||
.spi_port = 4, /* SPI4 (PF6-PF9复用映射) */
|
||||
.exmc_bank = 0},
|
||||
.info = {
|
||||
.total_size = EXTERNAL_SPI_FLASH_TOTAL_SIZE, .sector_size = EXTERNAL_SPI_FLASH_SECTOR_SIZE, .page_size = EXTERNAL_SPI_FLASH_PAGE_SIZE, .block_size = EXTERNAL_SPI_FLASH_BLOCK_SIZE, .manufacturer_id = 0xEF, /* Winbond制造商ID */
|
||||
.device_id = 0x4017 /* W25Q64设备ID (8MB,实际检测时修正) */
|
||||
},
|
||||
.initialized = false,
|
||||
.private_data = NULL};
|
||||
|
||||
/* SPI Flash硬件引脚定义 (梁山派: PF6-CS, PF7-SCK, PF8-MISO, PF9-MOSI, SPI4, AF5) */
|
||||
#define SPI_FLASH_CS_PORT GPIOF
|
||||
#define SPI_FLASH_CS_PIN GPIO_PIN_6
|
||||
|
||||
/* SPI驱动对象 */
|
||||
static SpiBus s_spi_flash_bus(SpiPort::_4);
|
||||
static SpiDevice s_spi_flash_device(SPI_FLASH_CS_PORT, SPI_FLASH_CS_PIN);
|
||||
|
||||
/* 私有数据实例 */
|
||||
static flash_private_data_t internal_flash_private;
|
||||
static flash_private_data_t external_spi_flash_private;
|
||||
|
||||
/**
|
||||
* @brief 等待Flash操作完成
|
||||
* @param 无
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t wait_flash_operation(void)
|
||||
{
|
||||
uint32_t timeout = FLASH_TIMEOUT;
|
||||
|
||||
while (fmc_flag_get(FMC_FLAG_BUSY) != RESET)
|
||||
{
|
||||
if (timeout-- == 0)
|
||||
{
|
||||
return RET_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/* 检查错误标志 */
|
||||
if (fmc_flag_get(FMC_FLAG_OPERR) != RESET)
|
||||
{
|
||||
fmc_flag_clear(FMC_FLAG_OPERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
if (fmc_flag_get(FMC_FLAG_WPERR) != RESET)
|
||||
{
|
||||
fmc_flag_clear(FMC_FLAG_WPERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
if (fmc_flag_get(FMC_FLAG_PGMERR) != RESET)
|
||||
{
|
||||
fmc_flag_clear(FMC_FLAG_PGMERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
if (fmc_flag_get(FMC_FLAG_PGSERR) != RESET)
|
||||
{
|
||||
fmc_flag_clear(FMC_FLAG_PGSERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
if (fmc_flag_get(FMC_FLAG_RDDERR) != RESET)
|
||||
{
|
||||
fmc_flag_clear(FMC_FLAG_RDDERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
if (fmc_flag_get(FMC_FLAG_END) != RESET)
|
||||
{
|
||||
fmc_flag_clear(FMC_FLAG_END);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解锁内部Flash
|
||||
* @param 无
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t unlock_internal_flash(void)
|
||||
{
|
||||
/* 解锁主Flash */
|
||||
fmc_unlock();
|
||||
|
||||
/* 解锁选项字节 */
|
||||
ob_unlock();
|
||||
|
||||
/* 等待解锁完成 */
|
||||
return wait_flash_operation();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 锁定内部Flash
|
||||
* @param 无
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t lock_internal_flash(void)
|
||||
{
|
||||
fmc_lock();
|
||||
ob_lock();
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将内存地址转换为FMC扇区编号编码
|
||||
* @param address 绝对内存地址 (如0x08000000)
|
||||
* @return CTL_SN编码的扇区号,无效地址返回0xFFFFFFFF
|
||||
*/
|
||||
static uint32_t address_to_sector_code(uint32_t address)
|
||||
{
|
||||
uint32_t offset = address - INTERNAL_FLASH_BASE_ADDR;
|
||||
uint32_t sector_num;
|
||||
|
||||
if (offset >= INTERNAL_FLASH_TOTAL_SIZE) {
|
||||
return 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
if (offset < 0x10000U) {
|
||||
sector_num = offset / 0x4000U;
|
||||
} else if (offset < 0x20000U) {
|
||||
sector_num = 4;
|
||||
} else {
|
||||
sector_num = 5 + (offset - 0x20000U) / 0x20000U;
|
||||
if (sector_num > 11) {
|
||||
sector_num = 11;
|
||||
}
|
||||
}
|
||||
|
||||
return CTL_SN(sector_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 擦除内部Flash扇区
|
||||
* @param sector_address 扇区起始地址
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t erase_internal_flash_sector(uint32_t sector_address)
|
||||
{
|
||||
ret_code_t ret;
|
||||
uint32_t sector_code;
|
||||
|
||||
sector_code = address_to_sector_code(sector_address);
|
||||
if (sector_code == 0xFFFFFFFFU) {
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
ret = unlock_internal_flash();
|
||||
if (ret != RET_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR |
|
||||
FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
|
||||
|
||||
fmc_sector_erase(sector_code);
|
||||
|
||||
ret = wait_flash_operation();
|
||||
|
||||
lock_internal_flash();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 写入内部Flash数据
|
||||
* @param address 写入地址
|
||||
* @param data 数据指针
|
||||
* @param length 数据长度(字节)
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t write_internal_flash(uint32_t address, const void *data, uint32_t length)
|
||||
{
|
||||
ret_code_t ret;
|
||||
const uint8_t *src = (const uint8_t *)data;
|
||||
uint32_t bytes_written = 0;
|
||||
|
||||
/* 检查地址对齐(字对齐,4字节) */
|
||||
if ((address % 4) != 0)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 检查数据长度对齐 */
|
||||
if ((length % 4) != 0)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 解锁Flash */
|
||||
ret = unlock_internal_flash();
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 逐字写入 */
|
||||
while (bytes_written < length)
|
||||
{
|
||||
uint32_t word_data;
|
||||
|
||||
/* 组装32位字 */
|
||||
word_data = (uint32_t)src[bytes_written] |
|
||||
((uint32_t)src[bytes_written + 1] << 8) |
|
||||
((uint32_t)src[bytes_written + 2] << 16) |
|
||||
((uint32_t)src[bytes_written + 3] << 24);
|
||||
|
||||
/* 写入Flash */
|
||||
fmc_word_program(address + bytes_written, word_data);
|
||||
|
||||
/* 等待写入完成 */
|
||||
ret = wait_flash_operation();
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
lock_internal_flash();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bytes_written += 4;
|
||||
}
|
||||
|
||||
/* 锁定Flash */
|
||||
lock_internal_flash();
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化内部Flash
|
||||
* @param handle Flash句柄指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t init_internal_flash(flash_handle_t *handle)
|
||||
{
|
||||
(void)handle; /* 目前不需要句柄特定配置 */
|
||||
|
||||
/* 解锁Flash以进行初始化 */
|
||||
ret_code_t ret = unlock_internal_flash();
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 锁定Flash */
|
||||
lock_internal_flash();
|
||||
|
||||
/* 初始化私有数据 */
|
||||
internal_flash_private.internal.base_address = INTERNAL_FLASH_BASE_ADDR;
|
||||
internal_flash_private.internal.write_enabled = false;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/* 公共函数实现 */
|
||||
|
||||
ret_code_t flash_init(flash_handle_t *handle)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
return init_internal_flash(handle);
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
return init_external_spi_flash(handle);
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
return init_external_nor_flash(handle);
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_deinit(flash_handle_t *handle)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!handle->initialized)
|
||||
{
|
||||
return RET_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
/* 锁定Flash */
|
||||
lock_internal_flash();
|
||||
break;
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
break;
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
break;
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
handle->initialized = false;
|
||||
handle->private_data = NULL;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
ret_code_t flash_read(flash_handle_t *handle, uint32_t address, void *buffer, uint32_t length)
|
||||
{
|
||||
if (handle == NULL || buffer == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
{
|
||||
/* 内部Flash直接内存读取 */
|
||||
uint32_t actual_address;
|
||||
|
||||
if (address < INTERNAL_FLASH_BASE_ADDR)
|
||||
{
|
||||
/* 相对地址 */
|
||||
actual_address = INTERNAL_FLASH_BASE_ADDR + address;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 绝对地址 */
|
||||
actual_address = address;
|
||||
}
|
||||
|
||||
/* 检查地址范围 */
|
||||
if (actual_address < INTERNAL_FLASH_BASE_ADDR ||
|
||||
actual_address + length > INTERNAL_FLASH_BASE_ADDR + INTERNAL_FLASH_TOTAL_SIZE)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 直接内存复制 */
|
||||
memcpy(buffer, (void *)actual_address, length);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
return read_external_spi_flash(handle, address, buffer, length);
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
return read_external_nor_flash(handle, address, buffer, length);
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_write(flash_handle_t *handle, uint32_t address, const void *data, uint32_t length)
|
||||
{
|
||||
if (handle == NULL || data == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
{
|
||||
uint32_t actual_address;
|
||||
|
||||
if (address < INTERNAL_FLASH_BASE_ADDR)
|
||||
{
|
||||
/* 相对地址 */
|
||||
actual_address = INTERNAL_FLASH_BASE_ADDR + address;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 绝对地址 */
|
||||
actual_address = address;
|
||||
}
|
||||
|
||||
/* 检查地址范围 */
|
||||
if (actual_address < INTERNAL_FLASH_BASE_ADDR ||
|
||||
actual_address + length > INTERNAL_FLASH_BASE_ADDR + INTERNAL_FLASH_TOTAL_SIZE)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 检查地址对齐 */
|
||||
if ((actual_address % 4) != 0 || (length % 4) != 0)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 写入Flash */
|
||||
return write_internal_flash(actual_address, data, length);
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
return write_external_spi_flash(handle, address, data, length);
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
return write_external_nor_flash(handle, address, data, length);
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_erase(flash_handle_t *handle, uint32_t address, uint32_t size)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
{
|
||||
uint32_t actual_address;
|
||||
|
||||
if (address < INTERNAL_FLASH_BASE_ADDR)
|
||||
{
|
||||
/* 相对地址 */
|
||||
actual_address = INTERNAL_FLASH_BASE_ADDR + address;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 绝对地址 */
|
||||
actual_address = address;
|
||||
}
|
||||
|
||||
/* 检查地址范围 */
|
||||
if (actual_address < INTERNAL_FLASH_BASE_ADDR ||
|
||||
actual_address + size > INTERNAL_FLASH_BASE_ADDR + INTERNAL_FLASH_TOTAL_SIZE)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 检查大小对齐(扇区对齐) */
|
||||
if ((actual_address % INTERNAL_FLASH_SECTOR_SIZE) != 0 ||
|
||||
(size % INTERNAL_FLASH_SECTOR_SIZE) != 0)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 擦除扇区 */
|
||||
uint32_t sector_count = size / INTERNAL_FLASH_SECTOR_SIZE;
|
||||
ret_code_t ret = RET_OK;
|
||||
|
||||
for (uint32_t i = 0; i < sector_count; i++)
|
||||
{
|
||||
ret = erase_internal_flash_sector(actual_address + i * INTERNAL_FLASH_SECTOR_SIZE);
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
{
|
||||
/* 检查大小对齐(扇区对齐) */
|
||||
if ((address % EXTERNAL_SPI_FLASH_SECTOR_SIZE) != 0 ||
|
||||
(size % EXTERNAL_SPI_FLASH_SECTOR_SIZE) != 0)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 擦除扇区 */
|
||||
uint32_t sector_count = size / EXTERNAL_SPI_FLASH_SECTOR_SIZE;
|
||||
ret_code_t ret = RET_OK;
|
||||
|
||||
for (uint32_t i = 0; i < sector_count; i++)
|
||||
{
|
||||
ret = erase_external_spi_flash_sector(handle, address + i * EXTERNAL_SPI_FLASH_SECTOR_SIZE);
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
/* 外部NOR Flash暂不支持 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_erase_all(flash_handle_t *handle)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
/* 擦除整个Flash */
|
||||
return flash_erase(handle, INTERNAL_FLASH_BASE_ADDR, INTERNAL_FLASH_TOTAL_SIZE);
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
/* 擦除整个SPI Flash */
|
||||
return flash_erase(handle, 0, EXTERNAL_SPI_FLASH_TOTAL_SIZE);
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
/* 外部NOR Flash暂不支持 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_read_status(flash_handle_t *handle, uint32_t *status)
|
||||
{
|
||||
if (handle == NULL || status == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
{
|
||||
/* 读取FMC状态寄存器 */
|
||||
*status = FMC_STAT;
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
{
|
||||
uint8_t status_byte;
|
||||
ret_code_t ret = spi_flash_read_status(&status_byte);
|
||||
if (ret == RET_OK)
|
||||
{
|
||||
*status = status_byte;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
/* 外部NOR Flash暂不支持 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_write_enable(flash_handle_t *handle)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
{
|
||||
/* 内部Flash解锁即为写使能 */
|
||||
return unlock_internal_flash();
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
{
|
||||
return spi_flash_write_enable();
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
/* 外部NOR Flash暂不支持 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_write_disable(flash_handle_t *handle)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
{
|
||||
/* 内部Flash锁定即为写禁用 */
|
||||
return lock_internal_flash();
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
{
|
||||
ret_code_t ret = spi_flash_send_command(SPI_FLASH_CMD_WRITE_DISABLE);
|
||||
if (ret == RET_OK)
|
||||
{
|
||||
external_spi_flash_private.external_spi.write_enabled = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
/* 外部NOR Flash暂不支持 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_get_info(flash_handle_t *handle, flash_info_t *info)
|
||||
{
|
||||
if (handle == NULL || info == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
/* 复制内部Flash信息 */
|
||||
*info = internal_flash_handle.info;
|
||||
return RET_OK;
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
/* 复制外部SPI Flash信息 */
|
||||
*info = external_spi_flash_handle.info;
|
||||
return RET_OK;
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
/* 外部NOR Flash暂不支持 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_self_test(flash_handle_t *handle, uint32_t test_size)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
switch (handle->type)
|
||||
{
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
{
|
||||
/* 选择测试区域(使用Flash末尾的16KB扇区) */
|
||||
uint32_t test_address = INTERNAL_FLASH_BASE_ADDR + INTERNAL_FLASH_TOTAL_SIZE - INTERNAL_FLASH_SECTOR_SIZE;
|
||||
|
||||
/* 限制测试大小 */
|
||||
if (test_size > INTERNAL_FLASH_SECTOR_SIZE)
|
||||
{
|
||||
test_size = INTERNAL_FLASH_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
/* 对齐到4字节 */
|
||||
test_size = (test_size + 3) & ~3;
|
||||
|
||||
/* 测试缓冲区 */
|
||||
uint8_t write_buffer[256];
|
||||
uint8_t read_buffer[256];
|
||||
|
||||
/* 生成测试数据 */
|
||||
for (uint32_t i = 0; i < sizeof(write_buffer); i++)
|
||||
{
|
||||
write_buffer[i] = (uint8_t)(i & 0xFF);
|
||||
}
|
||||
|
||||
/* 擦除测试扇区 */
|
||||
ret_code_t ret = flash_erase(handle, test_address, INTERNAL_FLASH_SECTOR_SIZE);
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 写入测试数据 */
|
||||
ret = flash_write(handle, test_address, write_buffer, sizeof(write_buffer));
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 读取测试数据 */
|
||||
ret = flash_read(handle, test_address, read_buffer, sizeof(read_buffer));
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 验证数据 */
|
||||
if (memcmp(write_buffer, read_buffer, sizeof(write_buffer)) != 0)
|
||||
{
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
/* 外部Flash暂不支持 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t flash_internal_default_init(void)
|
||||
{
|
||||
/* 使用默认句柄进行初始化 */
|
||||
ret_code_t ret = flash_init(&internal_flash_handle);
|
||||
if (ret == RET_OK)
|
||||
{
|
||||
internal_flash_handle.initialized = true;
|
||||
internal_flash_handle.private_data = &internal_flash_private;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* SPI Flash辅助函数 */
|
||||
|
||||
/**
|
||||
* @brief 选择SPI Flash芯片
|
||||
* @param private_data 私有数据指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t spi_flash_select(void)
|
||||
{
|
||||
gpio_bit_reset(SPI_FLASH_CS_PORT, SPI_FLASH_CS_PIN);
|
||||
|
||||
for (volatile uint32_t i = 0; i < 5000; i++)
|
||||
;
|
||||
|
||||
printf("[SPI Flash] CS拉低 (选择芯片)\r\n");
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_code_t spi_flash_deselect(void)
|
||||
{
|
||||
gpio_bit_set(SPI_FLASH_CS_PORT, SPI_FLASH_CS_PIN);
|
||||
|
||||
for (volatile uint32_t i = 0; i < 5000; i++)
|
||||
;
|
||||
|
||||
printf("[SPI Flash] CS拉高 (取消选择芯片)\r\n");
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_code_t spi_flash_send_command(uint8_t cmd)
|
||||
{
|
||||
printf("[SPI Flash] 发送命令: 0x%02X\r\n", cmd);
|
||||
|
||||
spi_flash_select();
|
||||
BusTransfer tr = {&cmd, nullptr, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr);
|
||||
spi_flash_deselect();
|
||||
|
||||
for (volatile uint32_t i = 0; i < 1000; i++)
|
||||
;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_code_t spi_flash_read_status(uint8_t *status)
|
||||
{
|
||||
if (status == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
spi_flash_select();
|
||||
|
||||
uint8_t cmd = SPI_FLASH_CMD_READ_STATUS_REG;
|
||||
BusTransfer tr_cmd = {&cmd, nullptr, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_cmd);
|
||||
|
||||
uint8_t dummy = 0x00;
|
||||
BusTransfer tr_data = {&dummy, status, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_data);
|
||||
|
||||
spi_flash_deselect();
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_code_t spi_flash_wait_idle(void)
|
||||
{
|
||||
uint32_t timeout = SPI_FLASH_TIMEOUT;
|
||||
uint8_t status = 0;
|
||||
uint32_t last_report = timeout;
|
||||
|
||||
printf("[SPI Flash] 开始等待Flash空闲 (超时: %lu)\r\n", timeout);
|
||||
|
||||
while (timeout-- > 0)
|
||||
{
|
||||
ret_code_t ret = spi_flash_read_status(&status);
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
printf("[SPI Flash] 读取状态寄存器失败: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((status & SPI_FLASH_STATUS_BUSY) == 0)
|
||||
{
|
||||
printf("[SPI Flash] Flash已空闲,状态: 0x%02X, 剩余超时: %lu\r\n", status, timeout);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
if ((timeout % 10000) == 0 && timeout != last_report)
|
||||
{
|
||||
printf("[SPI Flash] 等待Flash空闲,状态: 0x%02X, 剩余超时: %lu\r\n", status, timeout);
|
||||
last_report = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[SPI Flash] 等待Flash空闲超时,最终状态: 0x%02X\r\n", status);
|
||||
return RET_TIMEOUT;
|
||||
}
|
||||
|
||||
static ret_code_t spi_flash_write_enable(void)
|
||||
{
|
||||
spi_flash_select();
|
||||
|
||||
uint8_t cmd = SPI_FLASH_CMD_WRITE_ENABLE;
|
||||
BusTransfer tr = {&cmd, nullptr, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr);
|
||||
|
||||
spi_flash_deselect();
|
||||
|
||||
for (volatile uint32_t i = 0; i < 1000; i++)
|
||||
;
|
||||
|
||||
external_spi_flash_private.external_spi.write_enabled = true;
|
||||
|
||||
printf("[SPI Flash] 写使能命令已发送\r\n");
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化外部SPI Flash
|
||||
* @param handle Flash句柄指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t init_external_spi_flash(flash_handle_t *handle)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
external_spi_flash_private_t *private_data = &external_spi_flash_private.external_spi;
|
||||
private_data->write_enabled = false;
|
||||
|
||||
printf("[SPI Flash] 配置SPI4引脚: PF6(CS), PF8(MISO), PF7(CLK), PF9(MOSI)\r\n");
|
||||
printf("[SPI Flash] 使用AF5配置 (SPI4)\r\n");
|
||||
|
||||
SpiConfig config;
|
||||
config.speed_hz = handle->config.clock_freq;
|
||||
config.mode = 0;
|
||||
config.data_width = 8;
|
||||
|
||||
ret_code_t ret = s_spi_flash_bus.init(config);
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
printf("[SPI Flash] SPI4初始化失败: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s_spi_flash_device.init();
|
||||
|
||||
for (volatile uint32_t i = 0; i < 10000; i++)
|
||||
;
|
||||
|
||||
printf("[SPI Flash] SPI4初始化完成\r\n");
|
||||
|
||||
printf("[SPI Flash] 执行SPI基本功能测试...\r\n");
|
||||
uint8_t test_tx = 0x5A;
|
||||
uint8_t test_rx = 0xFF;
|
||||
|
||||
BusTransfer tr_test = {&test_tx, &test_rx, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_test);
|
||||
printf("[SPI Flash] SPI测试: 发送=0x%02X, 接收=0x%02X\r\n", test_tx, test_rx);
|
||||
if (test_rx == 0xFF)
|
||||
{
|
||||
printf("[SPI Flash] 警告: 接收到0xFF,可能MISO线被拉高或未连接\r\n");
|
||||
}
|
||||
|
||||
uint8_t tx_data[4] = {SPI_FLASH_CMD_READ_JEDEC_ID, 0x00, 0x00, 0x00};
|
||||
uint8_t rx_data[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
printf("[SPI Flash] 开始读取设备ID,命令: 0x%02X\r\n", SPI_FLASH_CMD_READ_JEDEC_ID);
|
||||
|
||||
spi_flash_select();
|
||||
for (volatile uint32_t i = 0; i < 5000; i++)
|
||||
;
|
||||
BusTransfer tr_jedec = {tx_data, rx_data, 4, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_jedec);
|
||||
for (volatile uint32_t i = 0; i < 1000; i++)
|
||||
;
|
||||
spi_flash_deselect();
|
||||
for (volatile uint32_t i = 0; i < 1000; i++)
|
||||
;
|
||||
|
||||
private_data->manufacturer_id = rx_data[1];
|
||||
private_data->device_id = (rx_data[2] << 8) | rx_data[3];
|
||||
|
||||
printf("[SPI Flash] 读取结果 - 制造商ID: 0x%02lX, 设备ID: 0x%04lX\r\n",
|
||||
private_data->manufacturer_id, private_data->device_id);
|
||||
|
||||
handle->info.manufacturer_id = private_data->manufacturer_id;
|
||||
handle->info.device_id = private_data->device_id;
|
||||
|
||||
switch (private_data->device_id)
|
||||
{
|
||||
case 0x4017:
|
||||
handle->info.total_size = 8 * 1024 * 1024;
|
||||
printf("[SPI Flash] 检测到 W25Q64 (8MB)\r\n");
|
||||
break;
|
||||
case 0x4018:
|
||||
handle->info.total_size = 16 * 1024 * 1024;
|
||||
printf("[SPI Flash] 检测到 W25Q128 (16MB)\r\n");
|
||||
break;
|
||||
case 0x4019:
|
||||
handle->info.total_size = 32 * 1024 * 1024;
|
||||
printf("[SPI Flash] 检测到 W25Q256 (32MB)\r\n");
|
||||
break;
|
||||
default:
|
||||
handle->info.total_size = EXTERNAL_SPI_FLASH_TOTAL_SIZE;
|
||||
printf("[SPI Flash] 未知设备ID: 0x%04lX,使用默认容量 %lu MB\r\n",
|
||||
private_data->device_id, handle->info.total_size / (1024 * 1024));
|
||||
break;
|
||||
}
|
||||
|
||||
handle->info.sector_size = EXTERNAL_SPI_FLASH_SECTOR_SIZE;
|
||||
handle->info.page_size = EXTERNAL_SPI_FLASH_PAGE_SIZE;
|
||||
handle->info.block_size = EXTERNAL_SPI_FLASH_BLOCK_SIZE;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static ret_code_t read_external_spi_flash(flash_handle_t *handle, uint32_t address, void *buffer, uint32_t length)
|
||||
{
|
||||
if (handle == NULL || buffer == NULL || length == 0)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
ret_code_t ret = spi_flash_wait_idle();
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t tx_buffer[4];
|
||||
tx_buffer[0] = SPI_FLASH_CMD_READ_DATA;
|
||||
tx_buffer[1] = (address >> 16) & 0xFF;
|
||||
tx_buffer[2] = (address >> 8) & 0xFF;
|
||||
tx_buffer[3] = address & 0xFF;
|
||||
|
||||
spi_flash_select();
|
||||
BusTransfer tr_addr = {tx_buffer, nullptr, 4, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_addr);
|
||||
BusTransfer tr_data = {nullptr, (uint8_t *)buffer, length, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_data);
|
||||
spi_flash_deselect();
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 写入外部SPI Flash数据
|
||||
* @param handle Flash句柄指针
|
||||
* @param address 地址(相对地址)
|
||||
* @param data 数据指针
|
||||
* @param length 数据长度
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t write_external_spi_flash(flash_handle_t *handle, uint32_t address, const void *data, uint32_t length)
|
||||
{
|
||||
if (handle == NULL || data == NULL || length == 0)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
const uint8_t *src = (const uint8_t *)data;
|
||||
|
||||
uint32_t page_size = EXTERNAL_SPI_FLASH_PAGE_SIZE;
|
||||
uint32_t page_offset = address % page_size;
|
||||
|
||||
if (page_offset + length > page_size)
|
||||
{
|
||||
return RET_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
ret_code_t ret = spi_flash_wait_idle();
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = spi_flash_write_enable();
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t tx_buffer[4 + page_size];
|
||||
tx_buffer[0] = SPI_FLASH_CMD_PAGE_PROGRAM;
|
||||
tx_buffer[1] = (address >> 16) & 0xFF;
|
||||
tx_buffer[2] = (address >> 8) & 0xFF;
|
||||
tx_buffer[3] = address & 0xFF;
|
||||
|
||||
for (uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
tx_buffer[4 + i] = src[i];
|
||||
}
|
||||
|
||||
spi_flash_select();
|
||||
BusTransfer tr_write = {tx_buffer, nullptr, 4 + length, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_write);
|
||||
spi_flash_deselect();
|
||||
|
||||
ret = spi_flash_wait_idle();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 擦除外部SPI Flash扇区
|
||||
* @param handle Flash句柄指针
|
||||
* @param address 扇区地址
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t erase_external_spi_flash_sector(flash_handle_t *handle, uint32_t address)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
printf("[SPI Flash] 开始擦除扇区 0x%06lX\r\n", address);
|
||||
|
||||
ret_code_t ret = spi_flash_wait_idle();
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
printf("[SPI Flash] 等待空闲失败: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
printf("[SPI Flash] Flash空闲,开始写使能\r\n");
|
||||
|
||||
ret = spi_flash_write_enable();
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
printf("[SPI Flash] 写使能失败: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t tx_buffer[4];
|
||||
tx_buffer[0] = SPI_FLASH_CMD_SECTOR_ERASE;
|
||||
tx_buffer[1] = (address >> 16) & 0xFF;
|
||||
tx_buffer[2] = (address >> 8) & 0xFF;
|
||||
tx_buffer[3] = address & 0xFF;
|
||||
|
||||
printf("[SPI Flash] 发送扇区擦除命令: 0x%02X 0x%02X 0x%02X 0x%02X\r\n",
|
||||
tx_buffer[0], tx_buffer[1], tx_buffer[2], tx_buffer[3]);
|
||||
|
||||
spi_flash_select();
|
||||
BusTransfer tr_erase = {tx_buffer, nullptr, 4, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_erase);
|
||||
spi_flash_deselect();
|
||||
|
||||
printf("[SPI Flash] 扇区擦除命令已发送,等待擦除完成...\r\n");
|
||||
|
||||
ret = spi_flash_wait_idle();
|
||||
if (ret != RET_OK)
|
||||
{
|
||||
printf("[SPI Flash] 等待擦除完成失败: %d\r\n", ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[SPI Flash] 扇区擦除完成\r\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret_code_t flash_external_spi_default_init(void)
|
||||
{
|
||||
/* 使用默认句柄进行初始化 */
|
||||
ret_code_t ret = flash_init(&external_spi_flash_handle);
|
||||
if (ret == RET_OK)
|
||||
{
|
||||
external_spi_flash_handle.initialized = true;
|
||||
external_spi_flash_handle.private_data = &external_spi_flash_private;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
flash_handle_t *flash_get_external_spi_handle(void)
|
||||
{
|
||||
if (!external_spi_flash_handle.initialized)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &external_spi_flash_handle;
|
||||
}
|
||||
|
||||
uint32_t flash_get_internal_base_address(void)
|
||||
{
|
||||
return INTERNAL_FLASH_BASE_ADDR;
|
||||
}
|
||||
|
||||
uint32_t flash_get_internal_total_size(void)
|
||||
{
|
||||
return INTERNAL_FLASH_TOTAL_SIZE;
|
||||
}
|
||||
|
||||
uint32_t flash_get_internal_sector_size(void)
|
||||
{
|
||||
return INTERNAL_FLASH_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
/* =============== 外部NOR Flash驱动实现 =============== */
|
||||
|
||||
/**
|
||||
* @brief 初始化外部NOR Flash
|
||||
* @param handle Flash句柄指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t init_external_nor_flash(flash_handle_t *handle)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 外部NOR Flash暂未实现,返回成功以允许编译 */
|
||||
handle->initialized = true;
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取外部NOR Flash数据
|
||||
* @param handle Flash句柄指针
|
||||
* @param address 地址(相对地址)
|
||||
* @param buffer 数据缓冲区
|
||||
* @param length 数据长度
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t read_external_nor_flash(flash_handle_t *handle, uint32_t address, void *buffer, uint32_t length)
|
||||
{
|
||||
if (handle == NULL || buffer == NULL || length == 0)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 外部NOR Flash暂未实现 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 写入外部NOR Flash数据
|
||||
* @param handle Flash句柄指针
|
||||
* @param address 地址(相对地址)
|
||||
* @param data 数据指针
|
||||
* @param length 数据长度
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t write_external_nor_flash(flash_handle_t *handle, uint32_t address, const void *data, uint32_t length)
|
||||
{
|
||||
if (handle == NULL || data == NULL || length == 0)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 外部NOR Flash暂未实现 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 擦除外部NOR Flash扇区
|
||||
* @param handle Flash句柄指针
|
||||
* @param address 扇区地址
|
||||
* @return 操作结果
|
||||
*/
|
||||
static ret_code_t erase_external_nor_flash_sector(flash_handle_t *handle, uint32_t address)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* 外部NOR Flash暂未实现 */
|
||||
return RET_NOT_SUPPORTED;
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
#ifndef __FLASH_DRIVER_H__
|
||||
#define __FLASH_DRIVER_H__
|
||||
|
||||
#include <cstdint>
|
||||
#include "common_types.h"
|
||||
|
||||
/* Flash类型定义 */
|
||||
typedef enum {
|
||||
FLASH_TYPE_INTERNAL = 0, /* 内部Flash(片上Flash) */
|
||||
FLASH_TYPE_EXTERNAL_SPI, /* 外部SPI Flash */
|
||||
FLASH_TYPE_EXTERNAL_NOR, /* 外部并行NOR Flash(通过EXMC) */
|
||||
FLASH_TYPE_MAX
|
||||
} flash_type_t;
|
||||
|
||||
/* Flash操作模式定义 */
|
||||
typedef enum {
|
||||
FLASH_OP_READ = 0, /* 读取操作 */
|
||||
FLASH_OP_WRITE, /* 写入操作 */
|
||||
FLASH_OP_ERASE, /* 擦除操作 */
|
||||
FLASH_OP_READ_STATUS, /* 读取状态寄存器 */
|
||||
FLASH_OP_WRITE_ENABLE, /* 写使能 */
|
||||
FLASH_OP_WRITE_DISABLE, /* 写禁用 */
|
||||
FLASH_OP_MAX
|
||||
} flash_operation_t;
|
||||
|
||||
/* Flash容量信息结构体 */
|
||||
typedef struct {
|
||||
uint32_t total_size; /* 总容量(字节) */
|
||||
uint32_t sector_size; /* 扇区大小(字节) */
|
||||
uint32_t page_size; /* 页大小(字节) */
|
||||
uint32_t block_size; /* 块大小(字节) */
|
||||
uint32_t manufacturer_id; /* 制造商ID */
|
||||
uint32_t device_id; /* 设备ID */
|
||||
} flash_info_t;
|
||||
|
||||
/* Flash配置结构体 */
|
||||
typedef struct {
|
||||
flash_type_t type; /* Flash类型 */
|
||||
uint32_t base_address; /* 基地址(对于内部Flash是0x08000000) */
|
||||
uint32_t clock_freq; /* 时钟频率(Hz,仅对外部Flash有效) */
|
||||
uint32_t cs_pin; /* 片选引脚(仅对外部SPI Flash有效) */
|
||||
uint32_t spi_port; /* SPI端口(仅对外部SPI Flash有效) */
|
||||
uint32_t exmc_bank; /* EXMC Bank(仅对外部NOR Flash有效) */
|
||||
} flash_config_t;
|
||||
|
||||
/* Flash句柄结构体 */
|
||||
typedef struct {
|
||||
flash_type_t type; /* Flash类型 */
|
||||
flash_config_t config; /* Flash配置 */
|
||||
flash_info_t info; /* Flash信息 */
|
||||
bool initialized; /* 初始化标志 */
|
||||
void *private_data; /* 私有数据指针 */
|
||||
} flash_handle_t;
|
||||
|
||||
/* 函数声明 */
|
||||
|
||||
/**
|
||||
* @brief 初始化Flash
|
||||
* @param handle Flash句柄指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_init(flash_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief 反初始化Flash
|
||||
* @param handle Flash句柄指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_deinit(flash_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief 读取Flash数据
|
||||
* @param handle Flash句柄指针
|
||||
* @param address 地址(绝对地址或相对地址,取决于Flash类型)
|
||||
* @param buffer 数据缓冲区
|
||||
* @param length 数据长度(字节)
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_read(flash_handle_t *handle, uint32_t address, void *buffer, uint32_t length);
|
||||
|
||||
/**
|
||||
* @brief 写入Flash数据
|
||||
* @param handle Flash句柄指针
|
||||
* @param address 地址(绝对地址或相对地址,取决于Flash类型)
|
||||
* @param data 数据指针
|
||||
* @param length 数据长度(字节)
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_write(flash_handle_t *handle, uint32_t address, const void *data, uint32_t length);
|
||||
|
||||
/**
|
||||
* @brief 擦除Flash扇区
|
||||
* @param handle Flash句柄指针
|
||||
* @param address 扇区起始地址
|
||||
* @param size 擦除大小(字节),必须为扇区大小的整数倍
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_erase(flash_handle_t *handle, uint32_t address, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief 擦除整个Flash
|
||||
* @param handle Flash句柄指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_erase_all(flash_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief 读取Flash状态寄存器
|
||||
* @param handle Flash句柄指针
|
||||
* @param status 状态值输出指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_read_status(flash_handle_t *handle, uint32_t *status);
|
||||
|
||||
/**
|
||||
* @brief 写使能
|
||||
* @param handle Flash句柄指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_write_enable(flash_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief 写禁用
|
||||
* @param handle Flash句柄指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_write_disable(flash_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief 读取Flash信息
|
||||
* @param handle Flash句柄指针
|
||||
* @param info Flash信息输出指针
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_get_info(flash_handle_t *handle, flash_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief 验证Flash读写功能
|
||||
* @param handle Flash句柄指针
|
||||
* @param test_size 测试数据大小(字节)
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_self_test(flash_handle_t *handle, uint32_t test_size);
|
||||
|
||||
/**
|
||||
* @brief 默认内部Flash初始化
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_internal_default_init(void);
|
||||
|
||||
/**
|
||||
* @brief 默认外部SPI Flash初始化
|
||||
* @return 操作结果
|
||||
*/
|
||||
ret_code_t flash_external_spi_default_init(void);
|
||||
|
||||
/**
|
||||
* @brief 获取内部Flash基地址
|
||||
* @return 内部Flash基地址(0x08000000)
|
||||
*/
|
||||
uint32_t flash_get_internal_base_address(void);
|
||||
|
||||
/**
|
||||
* @brief 获取内部Flash总大小
|
||||
* @return 内部Flash总大小(字节)
|
||||
*/
|
||||
uint32_t flash_get_internal_total_size(void);
|
||||
|
||||
/**
|
||||
* @brief 获取内部Flash扇区大小
|
||||
* @return 内部Flash扇区大小(字节)
|
||||
*/
|
||||
uint32_t flash_get_internal_sector_size(void);
|
||||
|
||||
/**
|
||||
* @brief 获取默认外部SPI Flash句柄指针
|
||||
* @return Flash句柄指针,如果未初始化则返回NULL
|
||||
*/
|
||||
flash_handle_t *flash_get_external_spi_handle(void);
|
||||
|
||||
#endif /* __FLASH_DRIVER_H__ */
|
||||
@@ -1,6 +1,56 @@
|
||||
#include "flash_manager.h"
|
||||
#include "config.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "gd32f4xx.h"
|
||||
#include "gd32f4xx_fmc.h"
|
||||
#include "spi_driver.h"
|
||||
|
||||
#define INTERNAL_FLASH_BASE_ADDR 0x08000000U
|
||||
#define INTERNAL_FLASH_TOTAL_SIZE (1024 * 1024)
|
||||
#define INTERNAL_FLASH_SECTOR_SIZE (16 * 1024)
|
||||
#define INTERNAL_FLASH_PAGE_SIZE 256
|
||||
#define INTERNAL_FLASH_BLOCK_SIZE (64 * 1024)
|
||||
#define FLASH_TIMEOUT 50000000U
|
||||
|
||||
#define EXTERNAL_SPI_FLASH_BASE_ADDR 0x00000000U
|
||||
|
||||
#define SPI_FLASH_CMD_WRITE_ENABLE 0x06
|
||||
#define SPI_FLASH_CMD_WRITE_DISABLE 0x04
|
||||
#define SPI_FLASH_CMD_READ_STATUS_REG 0x05
|
||||
#define SPI_FLASH_CMD_WRITE_STATUS_REG 0x01
|
||||
#define SPI_FLASH_CMD_READ_DATA 0x03
|
||||
#define SPI_FLASH_CMD_FAST_READ 0x0B
|
||||
#define SPI_FLASH_CMD_PAGE_PROGRAM 0x02
|
||||
#define SPI_FLASH_CMD_SECTOR_ERASE 0x20
|
||||
#define SPI_FLASH_CMD_BLOCK_ERASE_32K 0x52
|
||||
#define SPI_FLASH_CMD_BLOCK_ERASE_64K 0xD8
|
||||
#define SPI_FLASH_CMD_CHIP_ERASE 0xC7
|
||||
#define SPI_FLASH_CMD_POWER_DOWN 0xB9
|
||||
#define SPI_FLASH_CMD_RELEASE_POWER_DOWN 0xAB
|
||||
#define SPI_FLASH_CMD_READ_MANUFACTURER_ID 0x90
|
||||
#define SPI_FLASH_CMD_READ_JEDEC_ID 0x9F
|
||||
#define SPI_FLASH_CMD_READ_UNIQUE_ID 0x4B
|
||||
|
||||
#define SPI_FLASH_STATUS_BUSY (1 << 0)
|
||||
#define SPI_FLASH_STATUS_WRITE_ENABLE (1 << 1)
|
||||
#define SPI_FLASH_STATUS_BP0 (1 << 2)
|
||||
#define SPI_FLASH_STATUS_BP1 (1 << 3)
|
||||
#define SPI_FLASH_STATUS_BP2 (1 << 4)
|
||||
#define SPI_FLASH_STATUS_BP3 (1 << 5)
|
||||
#define SPI_FLASH_STATUS_SRWD (1 << 7)
|
||||
|
||||
#define EXTERNAL_SPI_FLASH_TOTAL_SIZE (16 * 1024 * 1024)
|
||||
#define EXTERNAL_SPI_FLASH_SECTOR_SIZE (4 * 1024)
|
||||
#define EXTERNAL_SPI_FLASH_PAGE_SIZE 256
|
||||
#define EXTERNAL_SPI_FLASH_BLOCK_SIZE (64 * 1024)
|
||||
#define SPI_FLASH_TIMEOUT 20000000U
|
||||
|
||||
#define SPI_FLASH_CS_PORT GPIOF
|
||||
#define SPI_FLASH_CS_PIN GPIO_PIN_6
|
||||
|
||||
static SpiBus s_spi_flash_bus(SpiPort::_4);
|
||||
static SpiDevice s_spi_flash_device(SPI_FLASH_CS_PORT, SPI_FLASH_CS_PIN);
|
||||
|
||||
FlashManager &FlashManager::instance()
|
||||
{
|
||||
@@ -9,35 +59,165 @@ FlashManager &FlashManager::instance()
|
||||
}
|
||||
|
||||
FlashManager::FlashManager()
|
||||
: handle_{
|
||||
.type = FLASH_TYPE_INTERNAL,
|
||||
.config = {
|
||||
.type = FLASH_TYPE_INTERNAL,
|
||||
.base_address = flash_get_internal_base_address(),
|
||||
.clock_freq = 0,
|
||||
.cs_pin = 0,
|
||||
.spi_port = 0,
|
||||
.exmc_bank = 0},
|
||||
.info = {
|
||||
.total_size = flash_get_internal_total_size(),
|
||||
.sector_size = flash_get_internal_sector_size(),
|
||||
.page_size = 256,
|
||||
.block_size = 64 * 1024,
|
||||
.manufacturer_id = 0x20,
|
||||
.device_id = 0x470},
|
||||
.initialized = false,
|
||||
.private_data = nullptr
|
||||
},
|
||||
info_{
|
||||
.total_size = flash_get_internal_total_size(),
|
||||
.sector_size = flash_get_internal_sector_size(),
|
||||
.page_size = 256,
|
||||
.block_size = 64 * 1024,
|
||||
.manufacturer_id = 0x20,
|
||||
.device_id = 0x470}
|
||||
: type_(FLASH_TYPE_INTERNAL)
|
||||
, info_{
|
||||
.total_size = INTERNAL_FLASH_TOTAL_SIZE,
|
||||
.sector_size = INTERNAL_FLASH_SECTOR_SIZE,
|
||||
.page_size = INTERNAL_FLASH_PAGE_SIZE,
|
||||
.block_size = INTERNAL_FLASH_BLOCK_SIZE,
|
||||
.manufacturer_id = 0x20,
|
||||
.device_id = 0x470
|
||||
}
|
||||
, total_size_(INTERNAL_FLASH_TOTAL_SIZE)
|
||||
, sector_size_(INTERNAL_FLASH_SECTOR_SIZE)
|
||||
, initialized_(false)
|
||||
, write_enabled_(false)
|
||||
{
|
||||
}
|
||||
|
||||
RetCode FlashManager::waitFlashOperation()
|
||||
{
|
||||
uint32_t timeout = FLASH_TIMEOUT;
|
||||
|
||||
while (fmc_flag_get(FMC_FLAG_BUSY) != RESET) {
|
||||
if (timeout-- == 0) {
|
||||
return RET_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (fmc_flag_get(FMC_FLAG_OPERR) != RESET) {
|
||||
fmc_flag_clear(FMC_FLAG_OPERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
if (fmc_flag_get(FMC_FLAG_WPERR) != RESET) {
|
||||
fmc_flag_clear(FMC_FLAG_WPERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
if (fmc_flag_get(FMC_FLAG_PGMERR) != RESET) {
|
||||
fmc_flag_clear(FMC_FLAG_PGMERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
if (fmc_flag_get(FMC_FLAG_PGSERR) != RESET) {
|
||||
fmc_flag_clear(FMC_FLAG_PGSERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
if (fmc_flag_get(FMC_FLAG_RDDERR) != RESET) {
|
||||
fmc_flag_clear(FMC_FLAG_RDDERR);
|
||||
return RET_ERROR;
|
||||
}
|
||||
if (fmc_flag_get(FMC_FLAG_END) != RESET) {
|
||||
fmc_flag_clear(FMC_FLAG_END);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::unlockInternalFlash()
|
||||
{
|
||||
fmc_unlock();
|
||||
ob_unlock();
|
||||
return waitFlashOperation();
|
||||
}
|
||||
|
||||
RetCode FlashManager::lockInternalFlash()
|
||||
{
|
||||
fmc_lock();
|
||||
ob_lock();
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
uint32_t FlashManager::addressToSectorCode(uint32_t address)
|
||||
{
|
||||
uint32_t offset = address - INTERNAL_FLASH_BASE_ADDR;
|
||||
uint32_t sector_num;
|
||||
|
||||
if (offset >= INTERNAL_FLASH_TOTAL_SIZE) {
|
||||
return 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
if (offset < 0x10000U) {
|
||||
sector_num = offset / 0x4000U;
|
||||
} else if (offset < 0x20000U) {
|
||||
sector_num = 4;
|
||||
} else {
|
||||
sector_num = 5 + (offset - 0x20000U) / 0x20000U;
|
||||
if (sector_num > 11) {
|
||||
sector_num = 11;
|
||||
}
|
||||
}
|
||||
|
||||
return CTL_SN(sector_num);
|
||||
}
|
||||
|
||||
RetCode FlashManager::eraseInternalFlashSector(uint32_t sector_address)
|
||||
{
|
||||
uint32_t sector_code = addressToSectorCode(sector_address);
|
||||
if (sector_code == 0xFFFFFFFFU) {
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
RetCode ret = unlockInternalFlash();
|
||||
if (ret != RET_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR |
|
||||
FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
|
||||
|
||||
fmc_sector_erase(sector_code);
|
||||
|
||||
ret = waitFlashOperation();
|
||||
|
||||
lockInternalFlash();
|
||||
return ret;
|
||||
}
|
||||
|
||||
RetCode FlashManager::writeInternalFlash(uint32_t address, const void *data, uint32_t length)
|
||||
{
|
||||
const uint8_t *src = (const uint8_t *)data;
|
||||
uint32_t bytes_written = 0;
|
||||
|
||||
if ((address % 4) != 0 || (length % 4) != 0) {
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
|
||||
RetCode ret = unlockInternalFlash();
|
||||
if (ret != RET_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (bytes_written < length) {
|
||||
uint32_t word_data = (uint32_t)src[bytes_written] |
|
||||
((uint32_t)src[bytes_written + 1] << 8) |
|
||||
((uint32_t)src[bytes_written + 2] << 16) |
|
||||
((uint32_t)src[bytes_written + 3] << 24);
|
||||
|
||||
fmc_word_program(address + bytes_written, word_data);
|
||||
|
||||
ret = waitFlashOperation();
|
||||
if (ret != RET_OK) {
|
||||
lockInternalFlash();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bytes_written += 4;
|
||||
}
|
||||
|
||||
lockInternalFlash();
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::initInternalFlash()
|
||||
{
|
||||
RetCode ret = unlockInternalFlash();
|
||||
if (ret != RET_OK) {
|
||||
return ret;
|
||||
}
|
||||
lockInternalFlash();
|
||||
write_enabled_ = false;
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::init()
|
||||
{
|
||||
if (initialized_) {
|
||||
@@ -45,49 +225,485 @@ RetCode FlashManager::init()
|
||||
}
|
||||
|
||||
printf("[FlashManager] Initializing...\r\n");
|
||||
RetCode ret = flash_init(&handle_);
|
||||
if (ret == RET_OK) {
|
||||
flash_get_info(&handle_, &info_);
|
||||
initialized_ = true;
|
||||
printf("[FlashManager] Init OK: %lu KB, sector=%lu KB\r\n",
|
||||
info_.total_size / 1024, info_.sector_size / 1024);
|
||||
} else {
|
||||
printf("[FlashManager] Init failed: %d\r\n", ret);
|
||||
|
||||
RetCode ret = RET_OK;
|
||||
|
||||
switch (type_) {
|
||||
case FLASH_TYPE_INTERNAL:
|
||||
ret = initInternalFlash();
|
||||
break;
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
ret = initExternalSpiFlash();
|
||||
break;
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
ret = initExternalNorFlash();
|
||||
break;
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
RetCode FlashManager::erase(uint32_t address, uint32_t size)
|
||||
{
|
||||
if (!initialized_) return RET_NOT_INITIALIZED;
|
||||
return flash_erase(&handle_, address, size);
|
||||
}
|
||||
if (ret != RET_OK) {
|
||||
printf("[FlashManager] Init failed: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
RetCode FlashManager::write(uint32_t address, const void *data, uint32_t length)
|
||||
{
|
||||
if (!initialized_) return RET_NOT_INITIALIZED;
|
||||
return flash_write(&handle_, address, data, length);
|
||||
initialized_ = true;
|
||||
printf("[FlashManager] Init OK: %lu KB, sector=%lu KB\r\n",
|
||||
total_size_ / 1024, sector_size_ / 1024);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::read(uint32_t address, void *buffer, uint32_t length)
|
||||
{
|
||||
if (!initialized_) return RET_NOT_INITIALIZED;
|
||||
return flash_read(&handle_, address, buffer, length);
|
||||
if (buffer == NULL || length == 0) return RET_INVALID_PARAM;
|
||||
|
||||
switch (type_) {
|
||||
case FLASH_TYPE_INTERNAL: {
|
||||
uint32_t actual_address;
|
||||
if (address < INTERNAL_FLASH_BASE_ADDR) {
|
||||
actual_address = INTERNAL_FLASH_BASE_ADDR + address;
|
||||
} else {
|
||||
actual_address = address;
|
||||
}
|
||||
if (actual_address < INTERNAL_FLASH_BASE_ADDR ||
|
||||
actual_address + length > INTERNAL_FLASH_BASE_ADDR + INTERNAL_FLASH_TOTAL_SIZE) {
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
memcpy(buffer, (void *)actual_address, length);
|
||||
return RET_OK;
|
||||
}
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
return readExternalSpiFlash(address, buffer, length);
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
return readExternalNorFlash(address, buffer, length);
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
RetCode FlashManager::write(uint32_t address, const void *data, uint32_t length)
|
||||
{
|
||||
if (!initialized_) return RET_NOT_INITIALIZED;
|
||||
if (data == NULL || length == 0) return RET_INVALID_PARAM;
|
||||
|
||||
switch (type_) {
|
||||
case FLASH_TYPE_INTERNAL: {
|
||||
uint32_t actual_address;
|
||||
if (address < INTERNAL_FLASH_BASE_ADDR) {
|
||||
actual_address = INTERNAL_FLASH_BASE_ADDR + address;
|
||||
} else {
|
||||
actual_address = address;
|
||||
}
|
||||
if (actual_address < INTERNAL_FLASH_BASE_ADDR ||
|
||||
actual_address + length > INTERNAL_FLASH_BASE_ADDR + INTERNAL_FLASH_TOTAL_SIZE) {
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
if ((actual_address % 4) != 0 || (length % 4) != 0) {
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
return writeInternalFlash(actual_address, data, length);
|
||||
}
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
return writeExternalSpiFlash(address, data, length);
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
return writeExternalNorFlash(address, data, length);
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
RetCode FlashManager::erase(uint32_t address, uint32_t size)
|
||||
{
|
||||
if (!initialized_) return RET_NOT_INITIALIZED;
|
||||
if (size == 0) return RET_OK;
|
||||
|
||||
switch (type_) {
|
||||
case FLASH_TYPE_INTERNAL: {
|
||||
uint32_t actual_address;
|
||||
if (address < INTERNAL_FLASH_BASE_ADDR) {
|
||||
actual_address = INTERNAL_FLASH_BASE_ADDR + address;
|
||||
} else {
|
||||
actual_address = address;
|
||||
}
|
||||
if (actual_address < INTERNAL_FLASH_BASE_ADDR ||
|
||||
actual_address + size > INTERNAL_FLASH_BASE_ADDR + INTERNAL_FLASH_TOTAL_SIZE) {
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
if ((actual_address % INTERNAL_FLASH_SECTOR_SIZE) != 0 ||
|
||||
(size % INTERNAL_FLASH_SECTOR_SIZE) != 0) {
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
uint32_t sector_count = size / INTERNAL_FLASH_SECTOR_SIZE;
|
||||
for (uint32_t i = 0; i < sector_count; i++) {
|
||||
RetCode ret = eraseInternalFlashSector(actual_address + i * INTERNAL_FLASH_SECTOR_SIZE);
|
||||
if (ret != RET_OK) return ret;
|
||||
}
|
||||
return RET_OK;
|
||||
}
|
||||
case FLASH_TYPE_EXTERNAL_SPI: {
|
||||
if ((address % EXTERNAL_SPI_FLASH_SECTOR_SIZE) != 0 ||
|
||||
(size % EXTERNAL_SPI_FLASH_SECTOR_SIZE) != 0) {
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
uint32_t sector_count = size / EXTERNAL_SPI_FLASH_SECTOR_SIZE;
|
||||
for (uint32_t i = 0; i < sector_count; i++) {
|
||||
RetCode ret = eraseExternalSpiFlashSector(address + i * EXTERNAL_SPI_FLASH_SECTOR_SIZE);
|
||||
if (ret != RET_OK) return ret;
|
||||
}
|
||||
return RET_OK;
|
||||
}
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
return RET_NOT_SUPPORTED;
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
RetCode FlashManager::self_test(uint32_t test_size)
|
||||
{
|
||||
if (!initialized_) return RET_NOT_INITIALIZED;
|
||||
printf("[FlashManager] Running self-test (%lu bytes)...\r\n", test_size);
|
||||
return flash_self_test(&handle_, test_size);
|
||||
|
||||
switch (type_) {
|
||||
case FLASH_TYPE_INTERNAL: {
|
||||
uint32_t test_address = INTERNAL_FLASH_BASE_ADDR + total_size_ - sector_size_;
|
||||
|
||||
if (test_size > sector_size_) {
|
||||
test_size = sector_size_;
|
||||
}
|
||||
test_size = (test_size + 3) & ~3;
|
||||
|
||||
uint8_t write_buffer[256];
|
||||
uint8_t read_buffer[256];
|
||||
|
||||
for (uint32_t i = 0; i < sizeof(write_buffer); i++) {
|
||||
write_buffer[i] = (uint8_t)(i & 0xFF);
|
||||
}
|
||||
|
||||
RetCode ret = erase(test_address, sector_size_);
|
||||
if (ret != RET_OK) return ret;
|
||||
|
||||
ret = write(test_address, write_buffer, sizeof(write_buffer));
|
||||
if (ret != RET_OK) return ret;
|
||||
|
||||
ret = read(test_address, read_buffer, sizeof(read_buffer));
|
||||
if (ret != RET_OK) return ret;
|
||||
|
||||
if (memcmp(write_buffer, read_buffer, sizeof(write_buffer)) != 0) {
|
||||
return RET_ERROR;
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
case FLASH_TYPE_EXTERNAL_SPI:
|
||||
case FLASH_TYPE_EXTERNAL_NOR:
|
||||
return RET_NOT_SUPPORTED;
|
||||
default:
|
||||
return RET_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t FlashManager::total_size() const
|
||||
RetCode FlashManager::spiFlashSelect()
|
||||
{
|
||||
return info_.total_size;
|
||||
gpio_bit_reset(SPI_FLASH_CS_PORT, SPI_FLASH_CS_PIN);
|
||||
for (volatile uint32_t i = 0; i < 5000; i++);
|
||||
printf("[SPI Flash] CS拉低 (选择芯片)\r\n");
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
uint32_t FlashManager::sector_size() const
|
||||
RetCode FlashManager::spiFlashDeselect()
|
||||
{
|
||||
return info_.sector_size;
|
||||
gpio_bit_set(SPI_FLASH_CS_PORT, SPI_FLASH_CS_PIN);
|
||||
for (volatile uint32_t i = 0; i < 5000; i++);
|
||||
printf("[SPI Flash] CS拉高 (取消选择芯片)\r\n");
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::spiFlashSendCommand(uint8_t cmd)
|
||||
{
|
||||
printf("[SPI Flash] 发送命令: 0x%02X\r\n", cmd);
|
||||
spiFlashSelect();
|
||||
BusTransfer tr = {&cmd, nullptr, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr);
|
||||
spiFlashDeselect();
|
||||
for (volatile uint32_t i = 0; i < 1000; i++);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::spiFlashReadStatus(uint8_t *status)
|
||||
{
|
||||
if (status == NULL) return RET_INVALID_PARAM;
|
||||
|
||||
spiFlashSelect();
|
||||
|
||||
uint8_t cmd = SPI_FLASH_CMD_READ_STATUS_REG;
|
||||
BusTransfer tr_cmd = {&cmd, nullptr, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_cmd);
|
||||
|
||||
uint8_t dummy = 0x00;
|
||||
BusTransfer tr_data = {&dummy, status, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_data);
|
||||
|
||||
spiFlashDeselect();
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::spiFlashWaitIdle()
|
||||
{
|
||||
uint32_t timeout = SPI_FLASH_TIMEOUT;
|
||||
uint8_t status = 0;
|
||||
uint32_t last_report = timeout;
|
||||
|
||||
printf("[SPI Flash] 开始等待Flash空闲 (超时: %lu)\r\n", timeout);
|
||||
|
||||
while (timeout-- > 0) {
|
||||
RetCode ret = spiFlashReadStatus(&status);
|
||||
if (ret != RET_OK) {
|
||||
printf("[SPI Flash] 读取状态寄存器失败: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if ((status & SPI_FLASH_STATUS_BUSY) == 0) {
|
||||
printf("[SPI Flash] Flash已空闲,状态: 0x%02X, 剩余超时: %lu\r\n", status, timeout);
|
||||
return RET_OK;
|
||||
}
|
||||
if ((timeout % 10000) == 0 && timeout != last_report) {
|
||||
printf("[SPI Flash] 等待Flash空闲,状态: 0x%02X, 剩余超时: %lu\r\n", status, timeout);
|
||||
last_report = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[SPI Flash] 等待Flash空闲超时,最终状态: 0x%02X\r\n", status);
|
||||
return RET_TIMEOUT;
|
||||
}
|
||||
|
||||
RetCode FlashManager::spiFlashWriteEnable()
|
||||
{
|
||||
spiFlashSelect();
|
||||
|
||||
uint8_t cmd = SPI_FLASH_CMD_WRITE_ENABLE;
|
||||
BusTransfer tr = {&cmd, nullptr, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr);
|
||||
|
||||
spiFlashDeselect();
|
||||
|
||||
for (volatile uint32_t i = 0; i < 1000; i++);
|
||||
|
||||
write_enabled_ = true;
|
||||
printf("[SPI Flash] 写使能命令已发送\r\n");
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::initExternalSpiFlash()
|
||||
{
|
||||
write_enabled_ = false;
|
||||
|
||||
printf("[SPI Flash] 配置SPI4引脚: PF6(CS), PF8(MISO), PF7(CLK), PF9(MOSI)\r\n");
|
||||
printf("[SPI Flash] 使用AF5配置 (SPI4)\r\n");
|
||||
|
||||
SpiConfig config;
|
||||
config.speed_hz = 1562500;
|
||||
config.mode = 0;
|
||||
config.data_width = 8;
|
||||
|
||||
RetCode ret = s_spi_flash_bus.init(config);
|
||||
if (ret != RET_OK) {
|
||||
printf("[SPI Flash] SPI4初始化失败: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s_spi_flash_device.init();
|
||||
|
||||
for (volatile uint32_t i = 0; i < 10000; i++);
|
||||
|
||||
printf("[SPI Flash] SPI4初始化完成\r\n");
|
||||
|
||||
printf("[SPI Flash] 执行SPI基本功能测试...\r\n");
|
||||
uint8_t test_tx = 0x5A;
|
||||
uint8_t test_rx = 0xFF;
|
||||
|
||||
BusTransfer tr_test = {&test_tx, &test_rx, 1, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_test);
|
||||
printf("[SPI Flash] SPI测试: 发送=0x%02X, 接收=0x%02X\r\n", test_tx, test_rx);
|
||||
if (test_rx == 0xFF) {
|
||||
printf("[SPI Flash] 警告: 接收到0xFF,可能MISO线被拉高或未连接\r\n");
|
||||
}
|
||||
|
||||
uint8_t tx_data[4] = {SPI_FLASH_CMD_READ_JEDEC_ID, 0x00, 0x00, 0x00};
|
||||
uint8_t rx_data[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
printf("[SPI Flash] 开始读取设备ID,命令: 0x%02X\r\n", SPI_FLASH_CMD_READ_JEDEC_ID);
|
||||
|
||||
spiFlashSelect();
|
||||
for (volatile uint32_t i = 0; i < 5000; i++);
|
||||
BusTransfer tr_jedec = {tx_data, rx_data, 4, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_jedec);
|
||||
for (volatile uint32_t i = 0; i < 1000; i++);
|
||||
spiFlashDeselect();
|
||||
for (volatile uint32_t i = 0; i < 1000; i++);
|
||||
|
||||
uint32_t manufacturer_id = rx_data[1];
|
||||
uint32_t device_id = (rx_data[2] << 8) | rx_data[3];
|
||||
|
||||
info_.manufacturer_id = manufacturer_id;
|
||||
info_.device_id = device_id;
|
||||
|
||||
printf("[SPI Flash] 读取结果 - 制造商ID: 0x%02lX, 设备ID: 0x%04lX\r\n",
|
||||
manufacturer_id, device_id);
|
||||
|
||||
switch (device_id) {
|
||||
case 0x4017:
|
||||
total_size_ = 8 * 1024 * 1024;
|
||||
info_.total_size = total_size_;
|
||||
printf("[SPI Flash] 检测到 W25Q64 (8MB)\r\n");
|
||||
break;
|
||||
case 0x4018:
|
||||
total_size_ = 16 * 1024 * 1024;
|
||||
info_.total_size = total_size_;
|
||||
printf("[SPI Flash] 检测到 W25Q128 (16MB)\r\n");
|
||||
break;
|
||||
case 0x4019:
|
||||
total_size_ = 32 * 1024 * 1024;
|
||||
info_.total_size = total_size_;
|
||||
printf("[SPI Flash] 检测到 W25Q256 (32MB)\r\n");
|
||||
break;
|
||||
default:
|
||||
total_size_ = EXTERNAL_SPI_FLASH_TOTAL_SIZE;
|
||||
info_.total_size = total_size_;
|
||||
printf("[SPI Flash] 未知设备ID: 0x%04lX,使用默认容量 %lu MB\r\n",
|
||||
device_id, total_size_ / (1024 * 1024));
|
||||
break;
|
||||
}
|
||||
|
||||
info_.sector_size = EXTERNAL_SPI_FLASH_SECTOR_SIZE;
|
||||
info_.page_size = EXTERNAL_SPI_FLASH_PAGE_SIZE;
|
||||
info_.block_size = EXTERNAL_SPI_FLASH_BLOCK_SIZE;
|
||||
sector_size_ = info_.sector_size;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::readExternalSpiFlash(uint32_t address, void *buffer, uint32_t length)
|
||||
{
|
||||
if (buffer == NULL || length == 0) return RET_INVALID_PARAM;
|
||||
|
||||
RetCode ret = spiFlashWaitIdle();
|
||||
if (ret != RET_OK) return ret;
|
||||
|
||||
uint8_t tx_buffer[4];
|
||||
tx_buffer[0] = SPI_FLASH_CMD_READ_DATA;
|
||||
tx_buffer[1] = (address >> 16) & 0xFF;
|
||||
tx_buffer[2] = (address >> 8) & 0xFF;
|
||||
tx_buffer[3] = address & 0xFF;
|
||||
|
||||
spiFlashSelect();
|
||||
BusTransfer tr_addr = {tx_buffer, nullptr, 4, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_addr);
|
||||
BusTransfer tr_data = {nullptr, (uint8_t *)buffer, length, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_data);
|
||||
spiFlashDeselect();
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::writeExternalSpiFlash(uint32_t address, const void *data, uint32_t length)
|
||||
{
|
||||
if (data == NULL || length == 0) return RET_INVALID_PARAM;
|
||||
|
||||
const uint8_t *src = (const uint8_t *)data;
|
||||
uint32_t page_size = EXTERNAL_SPI_FLASH_PAGE_SIZE;
|
||||
uint32_t page_offset = address % page_size;
|
||||
|
||||
if (page_offset + length > page_size) {
|
||||
return RET_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
RetCode ret = spiFlashWaitIdle();
|
||||
if (ret != RET_OK) return ret;
|
||||
|
||||
ret = spiFlashWriteEnable();
|
||||
if (ret != RET_OK) return ret;
|
||||
|
||||
uint8_t tx_buffer[4 + EXTERNAL_SPI_FLASH_PAGE_SIZE];
|
||||
tx_buffer[0] = SPI_FLASH_CMD_PAGE_PROGRAM;
|
||||
tx_buffer[1] = (address >> 16) & 0xFF;
|
||||
tx_buffer[2] = (address >> 8) & 0xFF;
|
||||
tx_buffer[3] = address & 0xFF;
|
||||
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
tx_buffer[4 + i] = src[i];
|
||||
}
|
||||
|
||||
spiFlashSelect();
|
||||
BusTransfer tr_write = {tx_buffer, nullptr, 4 + length, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_write);
|
||||
spiFlashDeselect();
|
||||
|
||||
ret = spiFlashWaitIdle();
|
||||
return ret;
|
||||
}
|
||||
|
||||
RetCode FlashManager::eraseExternalSpiFlashSector(uint32_t address)
|
||||
{
|
||||
printf("[SPI Flash] 开始擦除扇区 0x%06lX\r\n", address);
|
||||
|
||||
RetCode ret = spiFlashWaitIdle();
|
||||
if (ret != RET_OK) {
|
||||
printf("[SPI Flash] 等待空闲失败: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
printf("[SPI Flash] Flash空闲,开始写使能\r\n");
|
||||
|
||||
ret = spiFlashWriteEnable();
|
||||
if (ret != RET_OK) {
|
||||
printf("[SPI Flash] 写使能失败: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t tx_buffer[4];
|
||||
tx_buffer[0] = SPI_FLASH_CMD_SECTOR_ERASE;
|
||||
tx_buffer[1] = (address >> 16) & 0xFF;
|
||||
tx_buffer[2] = (address >> 8) & 0xFF;
|
||||
tx_buffer[3] = address & 0xFF;
|
||||
|
||||
printf("[SPI Flash] 发送扇区擦除命令: 0x%02X 0x%02X 0x%02X 0x%02X\r\n",
|
||||
tx_buffer[0], tx_buffer[1], tx_buffer[2], tx_buffer[3]);
|
||||
|
||||
spiFlashSelect();
|
||||
BusTransfer tr_erase = {tx_buffer, nullptr, 4, 0};
|
||||
s_spi_flash_bus.transfer(&s_spi_flash_device, &tr_erase);
|
||||
spiFlashDeselect();
|
||||
|
||||
printf("[SPI Flash] 扇区擦除命令已发送,等待擦除完成...\r\n");
|
||||
|
||||
ret = spiFlashWaitIdle();
|
||||
if (ret != RET_OK) {
|
||||
printf("[SPI Flash] 等待擦除完成失败: %d\r\n", ret);
|
||||
} else {
|
||||
printf("[SPI Flash] 扇区擦除完成\r\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
RetCode FlashManager::initExternalNorFlash()
|
||||
{
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
RetCode FlashManager::readExternalNorFlash(uint32_t address, void *buffer, uint32_t length)
|
||||
{
|
||||
(void)address; (void)buffer; (void)length;
|
||||
return RET_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
RetCode FlashManager::writeExternalNorFlash(uint32_t address, const void *data, uint32_t length)
|
||||
{
|
||||
(void)address; (void)data; (void)length;
|
||||
return RET_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
RetCode FlashManager::eraseExternalNorFlashSector(uint32_t address)
|
||||
{
|
||||
(void)address;
|
||||
return RET_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include "common_types.h"
|
||||
#include "flash_driver.h"
|
||||
|
||||
class FlashManager {
|
||||
public:
|
||||
@@ -15,8 +14,8 @@ public:
|
||||
RetCode read(uint32_t address, void *buffer, uint32_t length);
|
||||
RetCode self_test(uint32_t test_size);
|
||||
|
||||
uint32_t total_size() const;
|
||||
uint32_t sector_size() const;
|
||||
uint32_t total_size() const { return total_size_; }
|
||||
uint32_t sector_size() const { return sector_size_; }
|
||||
bool is_initialized() const { return initialized_; }
|
||||
|
||||
private:
|
||||
@@ -25,9 +24,51 @@ private:
|
||||
FlashManager(const FlashManager &) = delete;
|
||||
FlashManager &operator=(const FlashManager &) = delete;
|
||||
|
||||
flash_handle_t handle_;
|
||||
flash_info_t info_;
|
||||
bool initialized_ = false;
|
||||
enum FlashType : uint8_t {
|
||||
FLASH_TYPE_INTERNAL = 0,
|
||||
FLASH_TYPE_EXTERNAL_SPI,
|
||||
FLASH_TYPE_EXTERNAL_NOR,
|
||||
};
|
||||
|
||||
struct FlashInfo {
|
||||
uint32_t total_size;
|
||||
uint32_t sector_size;
|
||||
uint32_t page_size;
|
||||
uint32_t block_size;
|
||||
uint32_t manufacturer_id;
|
||||
uint32_t device_id;
|
||||
};
|
||||
|
||||
RetCode waitFlashOperation();
|
||||
RetCode unlockInternalFlash();
|
||||
RetCode lockInternalFlash();
|
||||
uint32_t addressToSectorCode(uint32_t address);
|
||||
RetCode eraseInternalFlashSector(uint32_t sector_address);
|
||||
RetCode writeInternalFlash(uint32_t address, const void *data, uint32_t length);
|
||||
RetCode initInternalFlash();
|
||||
|
||||
RetCode spiFlashSelect();
|
||||
RetCode spiFlashDeselect();
|
||||
RetCode spiFlashSendCommand(uint8_t cmd);
|
||||
RetCode spiFlashReadStatus(uint8_t *status);
|
||||
RetCode spiFlashWaitIdle();
|
||||
RetCode spiFlashWriteEnable();
|
||||
RetCode initExternalSpiFlash();
|
||||
RetCode readExternalSpiFlash(uint32_t address, void *buffer, uint32_t length);
|
||||
RetCode writeExternalSpiFlash(uint32_t address, const void *data, uint32_t length);
|
||||
RetCode eraseExternalSpiFlashSector(uint32_t address);
|
||||
|
||||
RetCode initExternalNorFlash();
|
||||
RetCode readExternalNorFlash(uint32_t address, void *buffer, uint32_t length);
|
||||
RetCode writeExternalNorFlash(uint32_t address, const void *data, uint32_t length);
|
||||
RetCode eraseExternalNorFlashSector(uint32_t address);
|
||||
|
||||
FlashType type_;
|
||||
FlashInfo info_;
|
||||
uint32_t total_size_;
|
||||
uint32_t sector_size_;
|
||||
bool initialized_;
|
||||
bool write_enabled_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user