You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

STM32L4xx系列:如何通过嵌入式代码禁用写保护及检查状态?

嘿,我来帮你搞定STM32L4xx系列的写保护问题,完全用嵌入式代码实现,不用依赖ST-Link Utility工具。下面分两部分给你讲清楚:检查写保护状态,以及禁用写保护的具体代码实现。

一、检查用户地址是否处于写保护状态

STM32L4的FLASH写保护(WRP)是通过选项字节来配置的,每个WRP区域对应一段FLASH地址范围。要检查某个地址是否被保护,我们需要读取选项字节里的WRP配置,然后判断目标地址是否在保护范围内。

这里给你一个裸机寄存器操作的示例函数,直接读取硬件寄存器,不需要依赖HAL库:

#include "stm32l4xx.h"

/**
 * @brief 检查指定地址是否处于FLASH写保护状态
 * @param address 要检查的用户地址(必须在FLASH用户区:0x08000000 ~ 0x081FFFFF,具体范围看你的芯片型号)
 * @return 1:地址处于写保护;0:地址未被写保护/非法地址
 */
uint8_t CheckFlashWriteProtection(uint32_t address) {
    // 先校验地址合法性
    if(address < FLASH_BASE || address > (FLASH_BASE + FLASH_SIZE - 1)) {
        return 0; // 非法地址,这里默认返回未保护,你也可以改成报错
    }

    // 读取选项字节的WRP配置寄存器
    uint32_t optcr = FLASH->OPTCR;
    
    // 解析WRP1A区域的起始和结束偏移(STM32L4默认第一个WRP区域)
    uint32_t wrp1a_start = (optcr & FLASH_OPTCR_WRP1A_STRT) >> FLASH_OPTCR_WRP1A_STRT_Pos;
    uint32_t wrp1a_end = (optcr & FLASH_OPTCR_WRP1A_END) >> FLASH_OPTCR_WRP1A_END_Pos;
    
    // 转换为实际的FLASH地址范围:每个WRP单元对应1KB(0x400)的FLASH
    uint32_t wrp_start_addr = FLASH_BASE + wrp1a_start * 0x400;
    uint32_t wrp_end_addr = FLASH_BASE + (wrp1a_end + 1) * 0x400 - 1;

    // 检查地址是否在WRP1A区域内,且WRP使能位已置位
    if((address >= wrp_start_addr && address <= wrp_end_addr) && (optcr & FLASH_OPTCR_WRPEN)) {
        return 1;
    }

    // 如果你需要检查其他WRP区域(比如WRP1B、WRP2A),可以参考上面的逻辑重复判断
    // 具体区域数量和范围请参考你的STM32L4型号参考手册(RM0351)

    return 0;
}
二、禁用FLASH写保护的代码实现

要禁用写保护,必须先解锁FLASH控制器和选项字节,然后修改WRP配置,最后保存配置并重新锁定(可选)。下面是完整的示例函数:

/**
 * @brief 禁用FLASH的写保护(以WRP1A区域为例,可扩展到其他区域)
 * @return 0:操作成功;1:操作失败
 */
uint8_t DisableFlashWriteProtection(void) {
    // 临时关闭全局中断,避免干扰FLASH操作
    __disable_irq();

    // 1. 解锁FLASH_CR寄存器(默认是锁定状态)
    if(FLASH->CR & FLASH_CR_LOCK) {
        FLASH->KEYR = FLASH_KEY1;  // 写入解锁密钥1
        FLASH->KEYR = FLASH_KEY2;  // 写入解锁密钥2
        if(FLASH->CR & FLASH_CR_LOCK) {
            __enable_irq();
            return 1; // FLASH解锁失败
        }
    }

    // 2. 解锁选项字节寄存器OPTCR
    if(FLASH->CR & FLASH_CR_OPTLOCK) {
        FLASH->OPTKEYR = FLASH_OPT_KEY1;  // 选项字节解锁密钥1
        FLASH->OPTKEYR = FLASH_OPT_KEY2;  // 选项字节解锁密钥2
        if(FLASH->CR & FLASH_CR_OPTLOCK) {
            __enable_irq();
            return 1; // 选项字节解锁失败
        }
    }

    // 3. 修改WRP配置:清除WRP使能位,设置WRP1A区域为无保护
    // 无保护配置:WRP1A_STRT设为0x1F,WRP1A_END设为0x00(参考STM32L4手册)
    FLASH->OPTCR &= ~(FLASH_OPTCR_WRPEN | FLASH_OPTCR_WRP1A_STRT | FLASH_OPTCR_WRP1A_END);
    FLASH->OPTCR |= (0x1F << FLASH_OPTCR_WRP1A_STRT_Pos) | (0x00 << FLASH_OPTCR_WRP1A_END_Pos);

    // 如果要禁用其他WRP区域,这里继续修改对应的WRPx_STRT和WRPx_END即可

    // 4. 触发选项字节编程,保存配置
    FLASH->CR |= FLASH_CR_OPTSTRT;
    // 等待操作完成(BUSY位清零)
    while(FLASH->SR & FLASH_SR_BSY);

    // 5. 检查是否有错误发生
    if(FLASH->SR & (FLASH_SR_WRPERR | FLASH_SR_OPTVERR)) {
        // 清除错误标志
        FLASH->SR |= FLASH_SR_WRPERR | FLASH_SR_OPTVERR;
        __enable_irq();
        return 1;
    }

    // 6. 重新锁定FLASH和选项字节(可选,根据你的需求决定是否保持解锁状态)
    FLASH->CR |= FLASH_CR_LOCK | FLASH_CR_OPTLOCK;

    // 恢复全局中断
    __enable_irq();

    return 0;
}
几个关键注意事项
  • 供电要求:操作选项字节时,芯片供电必须稳定,电压要在2.0V~3.6V范围内(STM32L4的规范),否则可能导致配置失败甚至硬件损坏。
  • 中断处理:操作过程中关闭全局中断是个好习惯,避免中断触发影响FLASH的编程流程。
  • 芯片差异:不同STM32L4型号的FLASH大小、WRP区域数量可能不同,比如L476有4个WRP区域,L432可能只有2个。具体请参考对应型号的参考手册(RM0351)。
  • 密钥值:上面代码里的FLASH_KEY1FLASH_KEY2FLASH_OPT_KEY1FLASH_OPT_KEY2都是STM32标准定义的宏,如果你用的是标准库或HAL库,已经包含在头文件里了;如果是纯裸机,你可以直接写数值:
    • FLASH_KEY1 = 0x45670123;
    • FLASH_KEY2 = 0xCDEF89AB;
    • FLASH_OPT_KEY1 = 0x08192A3B;
    • FLASH_OPT_KEY2 = 0x4C5D6E7F;

内容的提问来源于stack exchange,提问作者Hoa.N

火山引擎 最新活动