PY32F406K1CU6 FLASH模拟EEPROM

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!
相关推荐
恒锐丰小吕1 小时前
无锡黑锋 HF6306 高性能超低静态电流低压差稳压器技术解析
嵌入式硬件·硬件工程
云山工作室1 小时前
血糖浓度测试仪设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
sam-zy1 小时前
PY32F403K1CU6定时器1~6基本配置,1ms中断,每隔1秒打印
单片机·嵌入式硬件·fpga开发
三佛科技-134163842122 小时前
脉冲清洗机MCU方案开发设计
单片机·嵌入式硬件·智能家居·pcb工艺
Saniffer_SH2 小时前
【每日一题】PCIe 里的 RefClk (Reference Clock) 到底是干什么的?
服务器·驱动开发·单片机·嵌入式硬件·fpga开发·计算机外设·硬件架构
测试专家3 小时前
FPGA在TSN板卡应用
fpga开发
Darken033 小时前
基于 STM32 ——GPIO输入
stm32·单片机·嵌入式硬件·gpio
影阴3 小时前
stm32 硬件i2c + hal库
stm32·单片机·嵌入式硬件
阿拉斯攀登3 小时前
在STM32上使用FreeRTOS
stm32·单片机·嵌入式硬件