w25qxx spi flash WP写保护引脚的正确使用方式

WP引脚使用方式

spi flash有一个外部写保护引脚WP, 此引脚并不是直接保护flash上的数据内容,而是保护状态寄存器不被异常改写.flash上的内容写保护是通过状态寄存器的BPxbit的不同组合来实现的. 对于环境相对恶劣的使用场景(供电不稳等.)需要对flash上的内容加以保护.整体的设计思路就是 使用状态寄存器的BPx位组合实现flash上数据内容的局部或整体写保护. 外部WP引脚的电平状态结合状态寄存器的SRP位实现状态寄存器的保护进而间接保护flash上受保护的数据内容.

通过BPx位组合实现的flash写保护,其实是把flash受保护区域置为了只读状态. 这种情况下除非改变flash状态寄存器的BPx位,解除写保护,否则无法擦写受保护区域.

针对相对重要或者是基本不会变动的数据,比如字库等,就可以放置在flash的受保护区域,作为只读数据存在.确保恶劣条件下数据的稳定性.

关键寄存器描述

这里仅贴出一些关键的寄存器,更详细的描述还需要参考数据手册.

状态寄存器写保护测试

通过状态寄存器的写保护位配合外部WP引脚状态,达到状态寄存器的写保护效果.

#define WP_HIGH() GPIO_Set_Output_Data_Bits(GPIOC_SFR,GPIO_PIN_MASK_0,Bit_SET)
#define WP_LOW()  GPIO_Set_Output_Data_Bits(GPIOC_SFR,GPIO_PIN_MASK_0,Bit_RESET)

#define   SPI_FLASH_RDSR         0x05   /* read status register         */
#define   SPI_FLASH_WRSR         0x01   /* write status register        */

static uint8_t flash_readstatus(uint8_t addr)
{
    uint8_t datain, i;

    SPI_FLASH_ENABLE();
    SpiWrite(&addr, 1);
    datain = SpiReadByte();
    SPI_FLASH_DISABLE();
    return datain;
}

static void flash_writestatus(uint8_t addr, uint8_t status)
{
    uint8_t dataout[2] = {0};

    SpiSimpleCmd(SPI_FLASH_WREN); 
    dataout[0] = addr;
    dataout[1] = status;
    SPI_FLASH_ENABLE();
    SpiWrite(dataout, 2);
    SPI_FLASH_DISABLE();

    while(1){
        if ((flash_readstatus(SPI_FLASH_RDSR) & 0x01) == 0)     // 等待flash操作完成.
            break;
        delay_ms(5);
    }
}

uint8_t flash_statustest(void)
{
    uint8_t get_data = 0;
    /*
        写入0x80, 此时拉低WP引脚,即状态寄存器处于hardware protedted模式.状态寄存器不可写入.
        拉高WP引脚, 状态寄存器处于hardware unprotected,状态寄存器可写.
    */
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    uart_printf("status = 0x%x\r\n", get_data);
    flash_writestatus(SPI_FLASH_WRSR, 0x80);
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    uart_printf("status = 0x%x\r\n", get_data);
    WP_LOW();       // 拉低时, 写入无效.
    flash_writestatus(SPI_FLASH_WRSR, 0x8C);
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    uart_printf("status = 0x%x\r\n", get_data);
    WP_HIGH();      // 拉高时, 写入有效.
    flash_writestatus(SPI_FLASH_WRSR, 0x8C);
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    uart_printf("status = 0x%x\r\n\r\n", get_data);
}
//打印结果
status = 0x8c
status = 0x80
status = 0x80           // 拉低后写入0x8C无效     状态寄存器仍为0x80.
status = 0x8c           // 拉高后写入0x8C生效

flash数据内容写保护测试

通过BPx位组合实现的flash写保护,其实是把flash受保护区域置为了只读状态. 这种情况下除非改变flash状态寄存器的BPx位,解除写保护,否则无法擦写受保护区域.

uint8_t flash_datatest(void)
{
    uint8_t get_data = 0;
    uint8_t write_data[3] = {0x01,0x02,0x03};
    uint8_t read_data[3] = {0};

    /*
        1.所有数据区域都不设置保护, 读写flash测试. 正常擦写.
        2.所有数据区域都设置保护(flash数据区处于只读状态), 读写flash测试. 擦写无效.
    */
    WP_HIGH();      // 拉高时, 写入有效.
    flash_writestatus(SPI_FLASH_WRSR, 0x80);
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    uart_printf("status = 0x%x\r\n", get_data);        // 输出0x80

    /*
        状态寄存器的BPx位组合不保护任何flash数据区域时, 无论外部WP引脚拉高还是拉低,
        都数据都能正常写入.
    */
    WP_LOW();   
    flash_sector_erase(0);
    flash_write(0, write_data, sizeof (write_data));
    flash_read(0, read_data, sizeof (read_data));
    uart_printf("get_data = 0x%x  0x%x  0x%x\r\n", read_data[0],read_data[1],read_data[2]);

    WP_HIGH();
    write_data[0] = 0x04;
    write_data[1] = 0x05;
    write_data[2] = 0x06;
    flash_sector_erase(0);
    flash_write(0, write_data, sizeof (write_data));
    flash_read(0, read_data, sizeof (read_data));
    uart_printf("get_data = 0x%x  0x%x  0x%x\r\n", read_data[0],read_data[1],read_data[2]);       

    WP_HIGH();   
    flash_writestatus(SPI_FLASH_WRSR, 0x9C);           // 设置写保护所有扇区
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    uart_printf("status = 0x%x\r\n", get_data);        // 输出0x9C

    /*
        flash状态寄存器对所有的flash数据内容设置了写保护.此时无论外部引脚拉高还是拉低.
        都无法对flash数据内容进行擦写. 必须解除写保护,才能正常擦写.
    */
    WP_HIGH();  
    write_data[0] = 0x07;
    write_data[1] = 0x07;
    write_data[2] = 0x07;
    flash_sector_erase(0);
    flash_write(0, write_data, sizeof (write_data));
    flash_read(0, read_data, sizeof (read_data));
    uart_printf("get_data = 0x%x  0x%x  0x%x\r\n", read_data[0],read_data[1],read_data[2]);

    WP_LOW();  
    write_data[0] = 0x07;
    write_data[1] = 0x07;
    write_data[2] = 0x07;
    flash_sector_erase(0);
    flash_write(0, write_data, sizeof (write_data));
    flash_read(0, read_data, sizeof (read_data));
    uart_printf("get_data = 0x%x  0x%x  0x%x\r\n", read_data[0],read_data[1],read_data[2]);

    /*
        设置状态寄存器保护低8K数据.        
    */
    WP_HIGH();   
    flash_writestatus(SPI_FLASH_WRSR, 0xE8);           // 设置写保护低8K数据
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    get_data = flash_readstatus(SPI_FLASH_RDSR);
    uart_printf("status = 0x%x\r\n", get_data);        // 输出0xE8

    /*
       设置了保护低8K数据, 即低8K为只读.无法擦写.
    */
    write_data[0] = 0x07;
    write_data[1] = 0x07;
    write_data[2] = 0x07;
    flash_sector_erase(0);
    flash_write(0, write_data, sizeof (write_data));
    flash_read(0, read_data, sizeof (read_data));
    uart_printf("get_data = 0x%x  0x%x  0x%x\r\n", read_data[0],read_data[1],read_data[2]);

    /*
        高于8K地址的数据不受保护,可正常擦写.
    */
    flash_sector_erase(0x1000*2);
    flash_write(0x1000*2, write_data, sizeof (write_data));
    flash_read(0x1000*2, read_data, sizeof (read_data));
    uart_printf("get_data = 0x%x  0x%x  0x%x\r\n", read_data[0],read_data[1],read_data[2]);

    // 打印结果.
    status = 0x80               // 未保护数据区域 flash正常擦写
    get_data = 0x1  0x2  0x3
    get_data = 0x4  0x5  0x6
    status = 0x9c               // 保护全部区域 flash无法擦写  保持之前的值
    get_data = 0x4  0x5  0x6
    get_data = 0x4  0x5  0x6
    status = 0xe8               // 保护低8K 0地址保持之前的值   8K之后正常擦写.
    get_data = 0x4  0x5  0x6
    get_data = 0x7  0x7  0x7
}

总结

本文对spi flash 的WP引脚做了相对深入的分析.结合数据手册给了其基本用法,读者如需更深入的用法, 还需结合数据手册进行深入分析.

版权声明:本文为CSDN博主「云卷花开」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/w___dream/article/details/122470810

生成海报
点赞 0

云卷花开

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

STM32CubeMx hal 驱动sg90舵机

一、舵机的控制原理 舵机通过接收PWM信号,使其进入内部电路产生一个偏置电压,触发电机通过减速齿轮带动电位器移动,使电压差为零时,电机停转,从而达到伺服的效果。即给舵机一个

STM32F1xx HAL库 中文详解 之 ADC篇

本文主要从ADC中用到的结构体、函数以及用法讲解。 目录 一、结构体 1.ADC_InitTypeDef 2.ADC_ChannelConfTypeDef 3.ADC_AnalogWDGConfTypeDef 4.ADC_Handl

stm32开发遇到的问题及后续

STM32开发问题记录 HAL库开发,问题罗列以及后续排查简单记录(仅适用于个人) 一、uart 1.1 问题: 打印正常,但是加入接收中断后,开始出bu