打印
[RISC-V MCU 应用开发]

二十四、CH32V103应用教程——设置FLASH读写保护及解除

[复制链接]
4115|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 RISCVLAR 于 2020-12-10 18:34 编辑

CH32V103应用教程——设置FLASH读写保护及解除

本章教程将使用CH32V103内部FLASH进行FLASH读写保护及解除设置。

1、用户选择字简介及相关函数介绍
用户选择字固化在FLASH中,在系统复位后会被重新装载到相应寄存器,用户可以任意的进行擦除和编程。用户选择字信息块总共有8个字节(4个字节为写保护,1个字节为读保护,1个字节为配置选项,2 个字节存储用户数据),每个位都有其反码位用于装载过程中的校验。

① 用户选择字解锁
通过写入序列到FLASH_OBKEYR寄存器可解锁用户选择字操作。解锁后,FLASH_CTLR寄存器的OBWRE位将置1,表示可以进行用户选择字的擦除和编程。通过将FLASH_CTLR寄存器的“OBWRE”位,软件清0来再次锁定。     
解锁序列:1)向 FLASH_OBKEYR 寄存器写入 KEY1 = 0x45670123;
                2)向 FLASH_OBKEYR 寄存器写入 KEY2 = 0xCDEF89AB。
注:用户选择字操作需要解除“LOCK”和“OBWRE”两层锁定

② 用户选择字编程
只支持标准编程方式,一次写入半字(2 字节)。实际过程中,对用户选择字进行编程时,FPEC只使用半字中的低字节,并自动计算出高字节(高字节为低字节的反码),然后开始编程操作,这将保证用户选择字中的字节和它的反码始终是正确的。
1)检查 FLASH_CTLR 寄存器 LOCK 位,如果为 1,需要执行“解除闪存锁”操作。
2)检查 FLASH_STATR 寄存器的 BSY 位,以确认没有其他正在进行的编程操作。
3)检查 FLASH_CTLR 寄存器 OBWRE 位,如果为 0,需要执行“用户选择字解锁”操作。
4)设置 FLASH_CTLR 寄存器的 OBPG 位为‘1’,开启用户选择字编程。
5)写入要编程的半字(2 字节)到指定地址。
6)等待 BYS 位变为‘0’或 FLASH_STATR 寄存器的 EOP 位为‘1’表示编程结束,将 EOP 位清 0。
7)读编程地址数据校验。
8)继续编程可以重复 5-7 步骤,结束编程将 OBPG 位清 0。
注:当修改选择字中的“读保护”变成“非保护”状态时,会自动执行一次整片擦除主存储区操作。如果修改“读保护”之外的选型,则不会出现整片擦除的操作。

③ 用户选择字擦除
直接擦除整个 128 字节用户选择字区域。
1)检查FLASH_CTLR寄存器LOCK位,如果为1,需要执行“解除闪存锁”操作。
2)检查FLASH_STATR寄存器的BSY位,以确认没有正在进行的编程操作。
3)检查FLASH_CTLR寄存器OBWRE位,如果为0,需要执行“用户选择字解锁”操作。
4)设置FLASH_CTLR寄存器的OBER 位为‘1’,开启用户选择字擦除。
5)等待BYS位变为‘0’或FLASH_STATR寄存器的EOP位为‘1’表示擦除结束,将 EOP 位清 0。
6)读擦除地址数据校验。
7)结束将 OBER 位清 0。

④ 解除读保护
闪存是否读保护,由用户选择字决定。读取FLASH_OBR寄存器,当RDPRT 位为‘1’表示当前闪存处于读保护状态,闪存操作上受到读保护状态的一系列安全防护。解除读保护过程如下:
1)擦除整个用户选择字区域,此时读保护字段RDPR将变成0xFF,此时读保护仍然有效。
2)用户选择字编程,写入正确的RDPR代码0xA5以解除闪存的读保护。(此步骤首先将导致系统自动对闪存执行整片擦除操作)
3)进行上电复位以重新加载选择字节(包括新的RDPR码),此时读保护被解除。

⑤ 解除写保护
闪存是否写保护,由用户选择字决定。读取FLASH_WPR寄存器,每个比特位代表4K字节闪存空间,当比特位为‘1’表示非写保护状态,为‘0’表示写保护。解除写保护过程如下:
1)擦除整个用户选择字区域。
2)写入正确的RDPR码 0xA5,允许读访问;
3)进行系统复位,重新加载选择字节(包括新的WRPR[3:0]字节),写保护被解除。

关于CH32V103用户选择字具体信息,可参考CH32V103应用手册。关于CH32V103内部FLASH标准库函数,前面已经介绍,在此不再赘述。

2、硬件设计
本章教程为设置内部FLASH读写保护及解除,使用CH32V103内部资源,无需进行硬件连接。

3、软件设计
本章教程主要进行FLASH读写保护以及解除设置,主要通过触摸按键控制。
当按下触摸按键1,则执行写保护状态反转:若目前芯片处于写保护状态,按下触摸按键1则解除写保护;若目前不在写保护状态,按下触摸按键1则设置写保护。
当按下触摸按键2,则执行读保护状态反转:若目前芯片处于读保护状态,按下触摸按键2则解除读保护;若目前不在读保护状态,按下触摸按键2则设置读保护。
关于触摸按键程序在前面章节已经介绍,本章主要进行读写保护及解除程序介绍,具体程序如下:
flash.h文件
#ifndef __FLASH_H
#define __FLASH_H

#include "ch32v10x_conf.h"

void WriteProtect_Toggle(void);
void ReadProtect_Toggle(void);

#endif
flash.h文件主要进行函数的声明;
flash.c文件
#include "flash.h"

//反转写保护的配置,用于演示。若芯片处于写保护状态,则解除;若不是写保护状态,则设置成写保护
void WriteProtect_Toggle(void)
{
    //根据写保护寄存器(FLASH_WPR)值进行判断,闪存写保护状态:1,写保护失效;0,写保护有效。
    if (FLASH_GetWriteProtectionOptionByte() != 0xFFFFFFFF )
    {
        printf("芯片处于写保护状态,即将执行解保护过程...\r\n");

        //解除闪存锁
        FLASH_Unlock();

        //擦除闪存选项字节内容
        FLASH_EraseOptionBytes();

        //对所有页解除写保护
        FLASH_EnableWriteProtection(0x00000000);

        printf("配置完成,芯片将自动复位加载新配置,复位后芯片会解除写保护状态\r\n");

        //启动系统复位,复位芯片,以使选项字节生效
        NVIC_SystemReset();
    }
    else
    {
        printf("芯片处于无写保护状态,即将执行写保护过程...\r\n");

        //解锁
        FLASH_Unlock();

        //擦除闪存选项字节内容,防止因为原有的写保护导致无法写入新的保护配置
        FLASH_EraseOptionBytes();

        //对所有页进行写保护
        FLASH_EnableWriteProtection(0xFFFFFFFF);

        printf("配置完成,芯片将自动复位加载新配置,复位后芯片会处于写保护状态\r\n");

        //启动系统复位,复位芯片,以使选项字节生效
        NVIC_SystemReset();
    }
}

//反转读保护的配置,用于演示。若芯片处于读保护状态,则解除,若不是读保护状态,则设置成读保护
void ReadProtect_Toggle(void)
{
    //判断是否处于读保护状态
    if (FLASH_GetReadOutProtectionStatus () == SET )
    {
        printf("芯片处于读保护状态\r\n");

        //解锁
        FLASH_Unlock();

        printf("即将解除读保护,解除读保护会把 FLASH的所有内容清空\r\n");
        printf("由于解除后程序被清空,所以后面不会有任何提示输出\r\n");
        printf("等待 20秒后即可给芯片下载新的程序...\r\n");

        //解除读保护
        FLASH_ReadOutProtection (DISABLE);

        printf("由于 FLASH 程序被清空,所以本代码不会被执行,串口不会有本语句输出(SRAM 调试模式下例外) \r\n");
    }
    else
    {
        printf("芯片处于无读保护状态,即将执行读保护过程...\r\n");

        //解锁
        FLASH_Unlock();

        //启用读保护
        FLASH_ReadOutProtection (ENABLE);

        printf("芯片已被设置为读保护,上电复位后生效(必须重新给开发板上电,只按复位键无效) \r\n");
        printf("处于保护状态下无法正常下载新程序,必须要先解除保护状态再下载\r\n");
    }
}

flash.c文件主要进行写保护和读保护以及相应解除配置。
main.c文件
int main(void)
{
    u16 ADC_val1,ADC_val2;

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
        USART_Printf_Init(115200);
        Touch_Key_Init();
        printf("SystemClk:%d\r\n",SystemCoreClock);

        /* 获取写保护寄存器的值进行判断,寄存器位为 0 表示有保护,为 1 表示无保护 */
        /* 若不等于 0xFFFFFFFF,则说明有部分页被写保护了 */
        if (FLASH_GetWriteProtectionOptionByte() !=0xFFFFFFFF )
        {

            printf("\r\n目前芯片处于写保护状态,TKEY1解除保护\r\n");

            printf("写保护寄存器的值:WRPR=0x%x\r\n",FLASH_GetWriteProtectionOptionByte());
        }
        else
        {
            //无写保护
            printf("\r\n目前芯片无写保护,TKEY1设置写保护\r\n");

            printf("写保护寄存器的值:WRPR=0x%x\r\n",FLASH_GetWriteProtectionOptionByte());
        }

        /* 若等于 SET,说明处于读保护状态 */
        if (FLASH_GetReadOutProtectionStatus () == SET )
        {
            printf("\r\n目前芯片处于读保护状态,TKEY2解除保护\r\n");

        }
        else
        {
            printf("\r\n目前芯片无读保护,TKEY2设置读保护\r\n");
        }

        while(1)
    {
            ADC_val1 = Get_Adc_Average(ADC_Channel_1,10);
            ADC_val2 = Get_Adc_Average(ADC_Channel_2,10);

            while(ADC_val1<2000)
            {
                printf("ADC1=%d\n",ADC_val1);
                WriteProtect_Toggle();
                Delay_Ms(1000);
            }
            while(ADC_val2<2000)
            {
                printf("ADC2=%d\n",ADC_val2);
                ReadProtect_Toggle();
                Delay_Ms(1000);
            }
        }
}
main.c文件主要进行函数初始化以及触摸按键控制,通过触摸按键1和触摸按键2进行写保护和读保护控制。

4、下载验证
将编译好的程序下载到开发板并复位,串口打印情况具体如下:

由上图可知,目前芯片不在写保护状态,触摸触摸按键1,设置写保护,串口打印输出如下:

由上图可知,目前芯片处于写保护和读保护状态,触摸触摸按键2,解除读保护状态,串口打印如下:

解除读保护之后,FLASH内容被清空,需重新下载程序。


23、设置FLASH读写保护及解除.rar

492.75 KB

使用特权

评论回复

相关帖子

沙发
skyred| | 2021-6-21 11:50 | 只看该作者
对于固化到FLASH中的数据,确实要考虑写保护

使用特权

评论回复
板凳
两只袜子| | 2021-6-21 15:03 | 只看该作者
非常值得借鉴的教程哦

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

132

主题

293

帖子

41

粉丝