目录
一、扇区擦除 Sector Erase 指令 (20h)
1、步骤
a、扇区擦除前,必须解锁FLASH,也就是写使能 (06h)
b、FLASH进行扇区擦除,看第一个图 (20h)
c、检查是否擦除 状态寄存器 (05h or 35h)
d、对FLASH上锁,禁止写入数据 (04h)
2、编写代码
二、页编程 Page Program 指令(02h)
1、步骤
2、编写代码
cs拉低之后,直接发送(06h),再将cs拉高,完成写使能。
cs拉低之后,发送(20h),再发送一个24位地址,cs拉高,完成扇区擦除。
05h表示状态寄存器1,35h表示状态寄存器2
这里我们主要用状态寄存器1,因为状态寄存器1包含一个BUSY位,在S0最低位上,如果BUSY位为1,表示还在繁忙中,如果BUSY位为0,表示已经操作完毕(很重要 !!!)下图就是状态寄存器1
cs拉低之后,直接发送(04h),再将cs拉高,完成上锁。
//写使能
void w25qxx_write_enable(void)
{
//片选引脚拉低
W25QXX_SS=0;
//发送0x06
SPI1_SendByte(0x06);
//片选引脚拉高
W25QXX_SS=1;
}
//读状态寄存器1
uint8_t w25qxx_read_status1(void)
{
uint8_t status=0;
//片选引脚拉低
W25QXX_SS=0;
//发送0x05
SPI1_SendByte(0x05);
//发送任意参数,读取状态寄存器的值
status=SPI1_SendByte(0xFF);
//片选引脚拉高
W25QXX_SS=1;
return status;
}
//写失能
void w25qxx_write_disable(void)
{
//片选引脚拉低
W25QXX_SS=0;
//发送0x04
SPI1_SendByte(0x04);
//片选引脚拉高
W25QXX_SS=1;
}
//擦除
void w25qxx_erase_sector(uint32_t addr)
{
uint8_t status=0;
//执行写使能指令
w25qxx_write_enable();
//延时一会儿,让片选引脚能够给保持高电平一段时间,让w25qxx识别
delay_us(1);
//片选引脚拉低
W25QXX_SS=0;
//发送0x20
SPI1_SendByte(0x20);
//发送24bit的地址
SPI1_SendByte((addr>>16)&0xFF);
SPI1_SendByte((addr>>8)&0xFF);
SPI1_SendByte( addr&0xFF);
//片选引脚拉高
W25QXX_SS=1;
//延时一会儿,让片选引脚能够给保持高电平一段时间,让w25qxx识别
delay_us(10);
//检查当前是否已经擦除成功
while(1)
{
status=w25qxx_read_status1();
if((status & 0x01) ==0) //判断最低为是否为0,为0表示操作完毕,退出。
break;
//每隔1毫秒进行查询
delay_ms(1);
}
//开启写保护
w25qxx_write_disable();
}
一次最高只能写入256字节,原因是缓冲区最大接受256个字节
a:写使能 (06h)
b:页写入指令 (02h)
这里的24位地址是任意地址,不是扇区地址,和(20h)不一样。发送完后cs拉高。
c:检测是否编程完毕,使用状态寄存器1,和上面红字区域一样。
d:写失能。
uint8_t SPI1_SendByte(uint8_t byte)
{
/*!< Loop while DR register in not emplty ,等待发送缓冲区为空*/
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
/*!< Send byte through the SPI1 peripheral ,通过SPI1发送字节*/
SPI_I2S_SendData(SPI1, byte);
/*!< Wait to receive a byte ,由于是同步通信,等待接收字节*/
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
/*!< Return the byte read from the SPI bus ,成功接收从机的字节并返回*/
return SPI_I2S_ReceiveData(SPI1);
}
//写使能
void w25qxx_write_enable(void)
{
//片选引脚拉低
W25QXX_SS=0;
//发送0x06
SPI1_SendByte(0x06);
//片选引脚拉高
W25QXX_SS=1;
}
//读状态寄存器1
uint8_t w25qxx_read_status1(void)
{
uint8_t status=0;
//片选引脚拉低
W25QXX_SS=0;
//发送0x05
SPI1_SendByte(0x05);
//发送任意参数,读取状态寄存器的值
status=SPI1_SendByte(0xFF);
//片选引脚拉高
W25QXX_SS=1;
return status;
}
//写失能
void w25qxx_write_disable(void)
{
//片选引脚拉低
W25QXX_SS=0;
//发送0x04
SPI1_SendByte(0x04);
//片选引脚拉高
W25QXX_SS=1;
}
//写数据,一次最高256字节
void w25qxx_write_page(uint32_t addr,uint8_t *pbuf,uint32_t len)
{
uint8_t status=0;
//执行写使能指令
w25qxx_write_enable();
//延时一会儿,让片选引脚能够给保持高电平一段时间,让w25qxx识别
delay_us(10);
//片选引脚拉低
W25QXX_SS=0;
//发送0x02
SPI1_SendByte(0x02);
//发送24bit的地址
SPI1_SendByte((addr>>16)&0xFF);
SPI1_SendByte((addr>>8)&0xFF);
SPI1_SendByte( addr&0xFF);
//发送数据
while(len--)
SPI1_SendByte(*pbuf++);
//片选引脚拉高
W25QXX_SS=1;
//延时一会儿,让片选引脚能够给保持高电平一段时间,让w25qxx识别
delay_us(10);
//检查当前是否已经写入成功
while(1)
{
status=w25qxx_read_status1();
if((status & 0x01) ==0)
break;
//每隔1毫秒进行查询
delay_ms(1);
}
//开启写保护
w25qxx_write_disable();
}
验证代码片段
int main(void)
{
//spi flash初始化
w25qxx_init();
//打印id信息
printf("w25qxx spi flash id=%04X\r\n",w25qxx_read_id());
//从地址0进行扇区擦除,每次擦除4KB字节
printf("w25qxx spi flash erase sector at addr 0\r\n");
w25qxx_erase_sector(0);
//从地址0写入64字节数据,写入数据位1~64
for(i=0; i<64; i++)
buf[i]=i+1;
printf("w25qxx spi flash write data at addr 0,data is 1~64\r\n");
w25qxx_write_page(0,buf,64);
//从地址0读取64字节数据
memset(buf,0,64);
printf("w25qxx spi flash read data at addr 0:\r\n");
w25qxx_read_data(0,buf,64);
for(i=0; i<64; i++)
{
printf("%02X ",buf[i]);
}
printf("\r\n");
while(1)
{
}
}