Files
lishanpi/bsp/device/flash/flash_driver.cpp
T
hm fc10ef2e10 Initial commit: LSPi (LiangShanPi) project
GD32F470ZGT6 based project with full peripheral support:
- SDRAM (W9825G6KH) via EXMC
- LCD NT35510 (480x800) via EXMC NOR/PSRAM
- Flash (W25Q64) via SPI
- UART (USART0) debug console
- LED indicators
- CMSIS-DAP debug interface
- CMake + ARM GCC toolchain build system
2026-04-26 16:24:42 +08:00

1376 lines
34 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}