flash.h
c
#ifndef __FLASH_H
#define __FLASH_H
#include "main.h"
#ifdef __cplusplus
extern "C" {
#endif
// FLASH页大小(默认256字节,系统未定义时生效)
#ifndef FLASH_PAGE_SIZE
#define FLASH_PAGE_SIZE 256U
#endif
// EEPROM核心配置(FLASH模拟)
#define FLASH_USER_START 0x08010000U // 起始地址
#define FLASH_USER_PAGES 4U // 占用页数
#define FLASH_USER_END (FLASH_USER_START + FLASH_USER_PAGES * FLASH_PAGE_SIZE) // 结束地址
#define EEPROM_SIZE (FLASH_USER_END - FLASH_USER_START) // 总容量
// 等待周期定义(系统头文件缺失时补充)
#ifndef FLASH_ACR_LATENCY_0
#define FLASH_ACR_LATENCY_0 0x00000000U
#endif
#ifndef FLASH_ACR_LATENCY_1
#define FLASH_ACR_LATENCY_1 0x00000001U
#endif
#ifndef FLASH_ACR_LATENCY_2
#define FLASH_ACR_LATENCY_2 0x00000002U
#endif
#ifndef FLASH_ACR_LATENCY_3
#define FLASH_ACR_LATENCY_3 0x00000003U
#endif
// 预取指使能位定义
#ifndef FLASH_ACR_PRFTEN
#define FLASH_ACR_PRFTEN 0x00000010U
#endif
// 等待周期掩码定义
#ifndef FLASH_ACR_LATENCY_Msk
#define FLASH_ACR_LATENCY_Msk 0x00000007U
#endif
// 地址有效性检查宏
#define IS_FLASH_ADDR_VALID(addr) (((addr) >= FLASH_USER_START) && ((addr) < FLASH_USER_END))
#define IS_EEPROM_ADDR(addr) ((addr) < EEPROM_SIZE)
// 公开函数声明
HAL_StatusTypeDef EEPROM_Init(void); // EEPROM初始化
HAL_StatusTypeDef EEPROM_WriteByte(uint16_t addr, uint8_t data); // 字节写入
HAL_StatusTypeDef EEPROM_ReadByte(uint16_t addr, uint8_t *data); // 字节读取
HAL_StatusTypeDef EEPROM_WriteBuf(uint16_t addr, const uint8_t *pbuf, uint16_t len); // 缓冲区写入
HAL_StatusTypeDef EEPROM_ReadBuf(uint16_t addr, uint8_t *pbuf, uint16_t len); // 缓冲区读取
HAL_StatusTypeDef EEPROM_Test(void); // 读写测试
#ifdef __cplusplus
}
#endif
#endif /* __FLASH_H */
flash.c
c
#include "flash.h"
#include <string.h>
typedef struct { uint32_t data[64]; } FlashPage_t; // 页数据结构(64*4=256字节)
// 配置FLASH等待周期(144MHz需3WS,预取指使能)
static HAL_StatusTypeDef FlashCfgWaitStates(void) {
uint32_t clk = HAL_RCC_GetHCLKFreq();
if (clk > 72000000U) { // 时钟>72MHz时配置3个等待周期
uint32_t acr = FLASH->ACR;
acr &= ~FLASH_ACR_LATENCY_Msk; // 清除原有配置
acr |= FLASH_ACR_LATENCY_3 | FLASH_ACR_PRFTEN; // 3WS+预取指
FLASH->ACR = acr;
volatile uint32_t to = 100000; // 超时计数
while (to-- && ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != FLASH_ACR_LATENCY_3)); // 等待配置生效
return to ? HAL_OK : HAL_ERROR; // 超时返回错误
}
return HAL_OK; // 低时钟无需配置
}
// 读取FLASH页数据到缓冲区
static void FlashReadPage(uint32_t pageAddr, FlashPage_t *page) {
uint32_t *src = (uint32_t *)pageAddr;
uint32_t *dst = page->data;
for (int i = 0; i < 64; i++) dst[i] = src[i]; // 32位对齐拷贝
}
// 编程缓冲区数据到FLASH页(地址需页对齐)
static HAL_StatusTypeDef FlashProgPage(uint32_t pageAddr, const FlashPage_t *page) {
if (pageAddr % FLASH_PAGE_SIZE != 0) { printf("[FLASH] 地址未页对齐\n"); return HAL_ERROR; }
return HAL_FLASH_Program(FLASH_TYPEPROGRAM_PAGE, pageAddr, (uint32_t *)page->data); // HAL页编程
}
// 擦除单个FLASH页
static HAL_StatusTypeDef FlashErasePage(uint32_t pageAddr) {
FLASH_EraseInitTypeDef erase = {0};
uint32_t pageErr;
erase.TypeErase = FLASH_TYPEERASE_PAGEERASE; // 页擦除模式
erase.PageAddress = pageAddr; // 目标页地址
erase.NbPages = 1; // 擦除页数
HAL_StatusTypeDef ret = HAL_FLASHEx_Erase(&erase, &pageErr); // HAL擦除函数
if (ret != HAL_OK) printf("[FLASH] 擦除失败! 页0x%08X\n", pageErr);
return ret;
}
// 验证FLASH页是否擦除(全0xFF)
static HAL_StatusTypeDef FlashVerifyErased(uint32_t pageAddr) {
uint32_t *ptr = (uint32_t *)pageAddr;
for (int i = 0; i < 64; i++) if (ptr[i] != 0xFFFFFFFF) return HAL_ERROR; // 非0xFF则失败
return HAL_OK;
}
/************************ 公开函数实现 ************************/
// EEPROM初始化(配置时序+解锁+擦除+验证+锁定)
HAL_StatusTypeDef EEPROM_Init(void) {
HAL_StatusTypeDef ret = FlashCfgWaitStates(); // 配置等待周期
if (ret != HAL_OK) return ret;
ret = HAL_FLASH_Unlock(); // 解锁FLASH
if (ret != HAL_OK) { printf("[EEPROM] 解锁失败\n"); return ret; }
for (uint32_t i = 0; i < FLASH_USER_PAGES; i++) { // 擦除所有用户页
ret = FlashErasePage(FLASH_USER_START + i * FLASH_PAGE_SIZE);
if (ret != HAL_OK) { HAL_FLASH_Lock(); return ret; }
}
for (uint32_t i = 0; i < FLASH_USER_PAGES; i++) { // 验证擦除结果
ret = FlashVerifyErased(FLASH_USER_START + i * FLASH_PAGE_SIZE);
if (ret != HAL_OK) { HAL_FLASH_Lock(); return ret; }
}
HAL_FLASH_Lock(); // 锁定FLASH
return HAL_OK;
}
// 字节写入(复用缓冲区写入函数)
HAL_StatusTypeDef EEPROM_WriteByte(uint16_t addr, uint8_t data) {
return EEPROM_WriteBuf(addr, &data, 1); // 1字节写入
}
// 字节读取(地址校验+直接读取)
HAL_StatusTypeDef EEPROM_ReadByte(uint16_t addr, uint8_t *data) {
if (addr >= EEPROM_SIZE || data == NULL) return HAL_ERROR; // 参数校验
*data = *(volatile uint8_t *)(FLASH_USER_START + addr); // 直接内存读取
return HAL_OK;
}
// 缓冲区写入(页管理:读页→更新→擦除→编程)
HAL_StatusTypeDef EEPROM_WriteBuf(uint16_t addr, const uint8_t *pbuf, uint16_t len) {
if (addr + len > EEPROM_SIZE || !pbuf || len == 0) { printf("[EEPROM] 写入参数错误\n"); return HAL_ERROR; }
uint32_t flashAddr = FLASH_USER_START + addr;
uint32_t pageStart = flashAddr - (flashAddr % FLASH_PAGE_SIZE); // 计算页起始地址
uint16_t pageOff = flashAddr % FLASH_PAGE_SIZE; // 页内偏移
FlashPage_t page;
FlashReadPage(pageStart, &page); // 读取整页数据
memcpy((uint8_t *)page.data + pageOff, pbuf, len); // 更新目标区域
HAL_StatusTypeDef ret = HAL_FLASH_Unlock(); // 解锁FLASH
if (ret != HAL_OK) { printf("[EEPROM] 解锁失败\n"); return ret; }
ret = FlashErasePage(pageStart); // 擦除目标页
if (ret != HAL_OK) { HAL_FLASH_Lock(); return ret; }
ret = FlashProgPage(pageStart, &page); // 编程更新后的数据
HAL_FLASH_Lock(); // 锁定FLASH
return ret;
}
// 缓冲区读取(地址校验+直接拷贝)
HAL_StatusTypeDef EEPROM_ReadBuf(uint16_t addr, uint8_t *pbuf, uint16_t len) {
if (addr + len > EEPROM_SIZE || !pbuf || len == 0) { printf("[EEPROM] 读取参数错误\n"); return HAL_ERROR; }
memcpy(pbuf, (void *)(FLASH_USER_START + addr), len); // 直接内存拷贝
return HAL_OK;
}
// EEPROM读写测试(字符串读写验证)
HAL_StatusTypeDef EEPROM_Test(void) {
HAL_Delay(10);
const char *testStr = "PY32F403 EEPROM Test!";
uint8_t wBuf[32] = {0}, rBuf[32] = {0};
strncpy((char *)wBuf, testStr, sizeof(wBuf)-1); // 填充写入数据
printf("写入: %s\n", wBuf);
HAL_StatusTypeDef ret = EEPROM_WriteBuf(64, wBuf, strlen(testStr)+1); // 写入字符串(含结束符)
if (ret != HAL_OK) { printf("写入失败\n"); return ret; }
HAL_Delay(10);
ret = EEPROM_ReadBuf(64, rBuf, strlen(testStr)+1); // 读取字符串
if (ret != HAL_OK) { printf("读取失败\n"); return ret; }
printf("读取: %s\n", rBuf);
return memcmp(wBuf, rBuf, strlen(testStr)+1) ? HAL_ERROR : HAL_OK; // 校验结果
}
执行结果:
bash
写入: PY32F403 EEPROM Test!
读取: PY32F403 EEPROM Test!