赞
踩
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生效

通过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引脚做了相对深入的分析.结合数据手册给了其基本用法,读者如需更深入的用法, 还需结合数据手册进行深入分析.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。