fc10ef2e10
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
1376 lines
34 KiB
C++
1376 lines
34 KiB
C++
#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;
|
||
}
|