STM32F103C8T6芯片FLASH功能详细描述+通用模板+关键代码参数修改解析

FLASH模块提供了灵活的非易失存储能力,支持高效的程序存储与数据保存。其保护机制(读/写保护)和选项字节配置增强了系统安全性,而编程与擦除操作的硬件流程需严格遵循时序和电源要求。合理使用FLASH功能,可满足嵌入式系统对代码存储、参数保存及固件升级的核心需求。


1. ​FLASH存储器容量与结构
  • 容量:STM32F103C8T6内置64KB的FLASH存储器,用于存储用户程序代码和常量数据。
  • 架构
    • 主存储块(Main Memory)​:包含64KB的存储空间,分为若干页。对于中容量产品(如C8T6),每页大小为1KB,共64页(0x0800 0000 - 0x0800 FFFF)。
    • 系统存储器(System Memory)​:位于独立区域(0x1FFF F000起),存储出厂预置的BootLoader程序,用于通过串口/USB等接口下载程序。
    • 选项字节(Option Bytes)​:位于0x1FFF F800,用于配置芯片的保护机制和功能参数(如读保护、写保护、硬件看门狗等)。

2. ​FLASH访问模式
  • CPU直接访问:FLASH支持通过总线接口直接读取数据,CPU可像访问RAM一样读取FLASH中的代码或常量。
  • 编程与擦除:需通过控制寄存器(FLASH_CR)发送特定命令,操作期间CPU暂停执行或等待操作完成。

3. ​编程与擦除操作
  • 页擦除:最小擦除单位为1页(1KB),擦除操作将整页数据置为全1(0xFF)。
  • 编程操作:以半字(16位)或字(32位)为单位写入数据。写入前需确保目标区域已擦除。
  • 操作流程
    1. 解锁FLASH:向FLASH_KEYR寄存器写入特定密钥(0x45670123和0xCDEF89AB)以解除写保护。
    2. 发送命令:通过FLASH_CR寄存器选择擦除或编程操作。
    3. 等待完成:轮询FLASH_SR寄存器的BSY位,直到操作结束。
    4. 锁定FLASH:操作完成后重新锁定FLASH_CR寄存器,防止误操作。

4. ​保护机制
  • 读保护(RDP, Read Protection)​
    • 激活后禁止通过调试接口(如JTAG/SWD)读取FLASH内容。
    • 通过选项字节的RDP位配置,解除保护需执行全片擦除。
  • 写保护(WRP, Write Protection)​
    • 防止意外修改FLASH内容,可针对特定页设置写保护。
    • 通过选项字节的WRPx位配置受保护的页范围。
  • 硬件看门狗:选项字节可配置硬件看门狗在程序启动后自动启用。

5. ​选项字节(Option Bytes)​
  • 功能配置
    • RDP(读保护级别)​:0xAA表示禁用读保护,其他值激活保护。
    • USER:配置硬件看门狗、停机/待机模式复位等。
    • WRPx:设置受写保护的页范围(如WRP0~WRP3对应不同的页组)。
  • 修改流程
    1. 解锁选项字节(向FLASH_OPTKEYR写入密钥)。
    2. 擦除选项字节(触发全片擦除)。
    3. 重新编程选项字节并锁定。

6. ​关键特性与限制
  • 操作时间
    • 页擦除时间约40ms,半字编程时间约40μs。
    • 操作期间需保持电源稳定,否则可能导致数据损坏。
  • 耐久性:FLASH支持约10,000次擦写循环,超出后可能导致存储单元失效。
  • 数据保留:在-40°C至85°C环境下,数据可保存至少10年。

7. ​应用场景
  • 程序存储:存放用户代码和常量数据(如查找表、配置参数)。
  • 数据存储:通过编程操作保存运行时数据(需注意擦写次数限制)。
  • 固件升级:结合BootLoader实现远程固件更新。
8.上完整程序模版,复制可用,已详细注释
#include "stm32f10x.h"                  // STM32标准库头文件
#include "stm32f10x_flash.h"            // FLASH库头文件

/*======== 用户配置区 ========*/
#define FLASH_START_ADDR    0x08008000    // FLASH操作起始地址(需对齐页地址)
#define FLASH_PAGE_SIZE     0x400         // 页大小(1KB,STM32F103C8T6中容量型号)
#define FLASH_DATA_SIZE     256           // 待写入数据长度(单位:半字,即16位)

uint16_t flashWriteData[FLASH_DATA_SIZE] = {0x1234, 0x5678}; // 示例数据(需为半字数组)
uint16_t flashReadData[FLASH_DATA_SIZE];                    // 数据读取缓冲区

/*======== FLASH解锁函数 ========*/
void FLASH_Unlock(void) {
    FLASH_Unlock();                      // 解锁FLASH控制寄存器(必须调用)
    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); // 清除所有错误标志
}

/*======== FLASH页擦除函数 ========*/
uint8_t FLASH_ErasePage(uint32_t pageAddress) {
    FLASH_Status status;

    // 检查地址是否页对齐(地址必须能被FLASH_PAGE_SIZE整除)
    if (pageAddress % FLASH_PAGE_SIZE != 0) return 1; // 地址错误

    status = FLASH_ErasePage(pageAddress);  // 执行页擦除
    if (status != FLASH_COMPLETE) return 2; // 擦除失败

    return 0; // 成功
}

/*======== FLASH数据写入函数 ========*/
uint8_t FLASH_WriteData(uint32_t startAddr, uint16_t *data, uint16_t len) {
    uint16_t i;
    FLASH_Status status;

    // 检查地址和长度有效性(地址需为偶数字节,长度不超过FLASH容量)
    if (startAddr < 0x08000000 || startAddr + len*2 > 0x0800FFFF) return 1;
    if (len == 0) return 2;

    for (i = 0; i < len; i++) {
        status = FLASH_ProgramHalfWord(startAddr + i*2, data[i]); // 半字写入
        if (status != FLASH_COMPLETE) return 3;                  // 写入失败
    }
    return 0; // 成功
}

/*======== FLASH数据读取函数 ========*/
void FLASH_ReadData(uint32_t startAddr, uint16_t *buffer, uint16_t len) {
    uint16_t i;
    for (i = 0; i < len; i++) {
        buffer[i] = *(__IO uint16_t*)(startAddr + i*2); // 强制转换为半字指针读取
    }
}

/*======== 主函数示例 ========*/
int main(void) {
    uint8_t ret;

    // 1. 初始化系统时钟(需根据实际情况配置)
    SystemInit();

    // 2. 解锁FLASH并擦除目标页
    FLASH_Unlock();
    ret = FLASH_ErasePage(FLASH_START_ADDR);
    if (ret != 0) {
        // 擦除失败处理(如记录错误码)
        while(1);
    }

    // 3. 写入数据到FLASH
    ret = FLASH_WriteData(FLASH_START_ADDR, flashWriteData, FLASH_DATA_SIZE);
    if (ret != 0) {
        // 写入失败处理
        while(1);
    }

    // 4. 锁定FLASH以防止意外修改
    FLASH_Lock();

    // 5. 验证数据:读取FLASH并比较
    FLASH_ReadData(FLASH_START_ADDR, flashReadData, FLASH_DATA_SIZE);
    if (memcmp(flashWriteData, flashReadData, FLASH_DATA_SIZE*2) != 0) {
        // 数据校验失败处理
        while(1);
    }

    while(1) {
        // 主程序逻辑(如使用存储的数据)
    }
}

9.关键参数详解
  1. FLASH_START_ADDR

    • 操作地址:必须为页对齐地址(如0x08008000),建议避开程序代码区(通常从0x08000000开始存放程序)。
  2. FLASH_PAGE_SIZE

    • 页大小:STM32F103C8T6为中容量型号,页大小为1KB(0x400)。高容量型号(如1MB FLASH)页大小为2KB。
  3. FLASH_ProgramHalfWord

    • 写入单位:STM32 FLASH仅支持半字(16位)或字(32位)写入,需避免单字节操作。
  4. FLASH_FLAG_EOP

    • 操作完成标志:每次FLASH操作(擦除/写入)完成后需检查此标志,或调用FLASH_ClearFlag清除。

10.功能说明
  • 安全解锁/锁定:通过FLASH_Unlock()FLASH_Lock()防止误操作,确保数据安全。
  • 页擦除管理:擦除最小单位为1页,擦除后所有位变为1(0xFFFF)。
  • 数据校验:写入后通过memcmp比对数据完整性,防止写入错误。
  • 错误处理:函数返回错误码,便于调试和异常恢复。

11.使用流程
  1. 配置起始地址:确保FLASH_START_ADDR位于用户FLASH区域(非代码区)。
  2. 数据对齐:写入数据需为半字数组(16位对齐),地址必须为偶数。
  3. 操作顺序:​必须解锁→擦除→写入→锁定的顺序操作,否则会触发硬件错误。
  4. 功耗管理:FLASH操作期间需保持稳定电源,避免电压跌落导致数据损坏。

12.注意事项
  • 中断处理:FLASH操作期间需禁用全局中断(__disable_irq()),防止打断关键操作。
  • 擦写次数:FLASH典型擦写寿命约10,000次,频繁操作需配合磨损均衡算法。
  • 写保护:通过选项字节(Option Bytes)可设置页写保护,防止误擦除关键数据。
  • 代码保护:启用读保护(RDP)后,调试器无法读取FLASH内容,需谨慎操作。
13.选项字节配置示例
void FLASH_ConfigureOptionBytes(void) {
    FLASH_Unlock();                             // 解锁FLASH
    FLASH_OB_Unlock();                          // 解锁选项字节

    FLASH_OB_Erase();                           // 擦除选项字节(触发全片擦除!)

    // 配置读保护级别(RDP Level 1:启用保护)
    FLASH_OB_RDPConfig(OB_RDP_Level_1);

    // 配置硬件看门狗(上电后自动启用)
    FLASH_OB_USERConfig(OB_IWDG_SW, ENABLE);    // 启用硬件看门狗

    FLASH_OB_Launch();                          // 应用选项字节配置
    FLASH_Lock();                               // 锁定FLASH
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值