华邦W25Q16存储器颗粒SPI编程.docx
- 文档编号:6483600
- 上传时间:2023-01-06
- 格式:DOCX
- 页数:21
- 大小:2.60MB
华邦W25Q16存储器颗粒SPI编程.docx
《华邦W25Q16存储器颗粒SPI编程.docx》由会员分享,可在线阅读,更多相关《华邦W25Q16存储器颗粒SPI编程.docx(21页珍藏版)》请在冰豆网上搜索。
华邦W25Q16存储器颗粒SPI编程
华邦W25Q16存储器颗粒SPI编程
W25X16、W25X32和W25X64系列FLASH存储器可以为用户提供存储解决方案,具有“PCB板占用空间少”、“引脚数量少”、“功耗低”等特点。
与普通串行FLASH相比,使用更灵活,性能更出色。
它非常适合做代码下载应用,例如存储声音,文本和数据。
工作电压在2.7V-3.6V之间,正常工作状态下电流消耗0.5毫安,掉电状态下电流消耗1微安。
所有的封装都是"节省空间"型的。
W25X16、W25X32和W25X64分别有8192、16384和32768可编程页,每页256字节。
用"页编程指令"每次就可以编程256个字节。
用"扇区(sector)擦除指令"每次可以擦除16页,用“块(block)擦除指令”每次可以擦除256页,用“整片擦除指令”即可以擦除整个芯片。
W25X16、W25X32和W25X64分别有512、1024和2048个可擦除"扇区"或32、64和128个可擦除“块”。
W25X16、W25X32和W25X64支持标准的SPI接口,传输速率最大75MHz。
四线制:
①:
串行时钟引脚CLK;
②:
芯片选择引脚CS;
③:
串行数据输出引脚DO;
④:
串行数据输入输出引脚DIO。
(注意:
第④引脚“串行数据输入输出引脚DIO”的解释:
在普通情况下,这根引脚是“串行输入引脚(DI),当使用了快读双输出指令(FastReadDualOutputinstruction)时,这根引脚就变成了DO引脚,这种情况下,芯片就有了两个DO引脚了,所以叫做双输出,这时,如果与芯片通信的速率相当于翻了一倍,所以传输速度更快。
)
另外,芯片还具有保持引脚(HOLD)、写保护引脚(WP)、可编程写保护位(位于状态寄存器bit1)、顶部和底部块的控制等特征,使得控制芯片更具灵活性。
芯片支持JEDEC工业标准。
引脚排布:
原理图:
控制和状态寄存器说明
S7
S6
S5
S4
S3
S2
S1
S0
SRP
(Reservd)
TB
BP2
BP1
BP0
WEL
BUSY
通过"读状态寄存器指令"读出的状态数据可以知道芯片存储器阵列是否可写或不可写,或是否处于写保护状态。
通过"写状态寄存器指令"可以配置芯片写保护特征。
状态寄存器:
忙位(BUSY)
BUSY位是个只读位,位于状态寄存器中的S0。
当器件在执行"页编程"、"扇区擦除"、"块区擦除"、"芯片擦除"、"写状态寄存器"指令时,该位自动置1。
这时,除了"读状态寄存器"指令,其它指令部忽略。
当编程、擦除和写状态寄存器指令执行完毕之后,该位自动变为0,表示芯片可以接收其它指令了。
写保护位(WEL)
WEL位是个只读位,位于状态寄存器中的S1。
执行完"写使能"指令后,该位置1。
当芯片处于"写保护状态"下,该位为0。
在下面两种情况下,会进入"写保护状态"
•掉电后
•执行以下指令后写禁能、页编程、扇区擦除、块区擦除、芯片擦除和写状态寄存器
块区保护位(BP2,BP1,BP0)
BP2\BP1\BP0位是可读可写位,分别位于状态寄存器的S4\S3\S2。
可以用"写状态寄存器"命令置位这些块区保护位。
在默认状态下,这些位都为0,即块区处于未保护状态下。
可以设置块区没有保护、部分保护或者是全部处于保护状态下。
当SPR位为1或/WP引脚为低的时候,这些位不可以被更改。
底部和顶部块区保护位(TB)
TB位是可读可写位,位于状态寄存器的S5。
该位默认为0,表明顶部和底部块区处于未被保护状态下。
可以用"写状态寄存器"命令置位该位。
当SPR位为1或/WP引脚为低的时候,这些位不可以被更改。
保留位
状态寄存器的S6为保留位,读出状态寄存器值时,该位为0。
建议读状态寄存器值用于测试时将该位屏蔽。
状态寄存器果护位(SRP)
SRP位是可读可写位,位于状态寄存器的S7。
该位结合/WP引脚可以实现禁能写状态寄存器功能。
该位默认值为0。
当SRP位=0时,/WP引脚不能控制状态寄存器的"写禁能"。
当SRP位=1,/WP引脚=0时,"写状态寄存器"命令失效。
当SRP位=1,/WP引脚=1时,可以执行"写状态寄存器"命令。
状态寄存器存储保护模块:
1、写使能时序图(指令:
0x06):
“写使能”指令将会使“状态寄存器”WEL位置位。
在执行每个“页编程”、“扇区擦除”、“块区擦除”、“芯片擦除”、和“写状态寄存器”命令之前,都要先置位WEL。
/CS引脚先拉低之后,“写使能”指令代码06h从DI引脚输入,在CLK上升沿采集,然后再拉高/CS引脚。
程序设计流程:
1、使能片选位,拉低CS引脚;
2、CLK起始状态或高电平或低平,配置数据采集从CLK第一个上升沿开始;
3、等待发送缓冲区是否为空,SPI_SR的TXE位;
4、将数据赋值给SPI_DR寄存器;
5、等待接收缓冲区是否为空,SPI_SR的RXNE位;
6、返回接收到的数据;
7、禁能片选位,拉高CS引脚。
例程:
unsignedcharSPI_SendByte(unsignedcharbyte)
{
while(!
(SPI_SR&0x02));//等待发送缓冲区为空
SPI_DR=byte;//送值到数据寄存器
whlie(!
(SPI_SR&0x01));//等待接收缓冲区为空
returnSPI_DR;//返回接收的内容
}
unsignedcharSPI_WriteEnable()
{
Flash_CS=0;//使能CS引脚
SPI_SendByte(0x06)//写使能指令
Flash_CS=1;//禁能片选引脚
}
2、写禁能时序图(指令:
0x04):
“写禁能”指令将会使WEL位变为0。
/CS引脚拉低之后,把04h从DIO引脚送到芯片之后,拉高/CS,就完成了这个指令。
在执行完“写状态寄存器”、“页编程”、“扇区擦除”、“块区擦除”、“芯片擦除”指令之后,WEL位就会自动变为0。
程序设计流程:
1、使能片选位,拉低CS引脚;
2、CLK起始状态或高电平或低平,配置数据采集从CLK第一个上升沿开始;
3、等待发送缓冲区是否为空,SPI_SR的TXE位;
4、将数据赋值给SPI_DR寄存器;
5、等待接收缓冲区是否为空,SPI_SR的RXNE位;
6、返回接收到的数据;
7、禁能片选位,拉高CS引脚。
例程:
unsignedcharSPI_SendByte(unsignedcharbyte)
{
Flash_CS=0;//使能CS引脚
while(!
(SPI_SR&0x02));//等待发送缓冲区为空
SPI_DR=byte;//送值到数据寄存器
whlie(!
(SPI_SR&0x01));//等待接收缓冲区为空
returnSPI_DR;//返回接收的内容
Flash_CS=1;//禁能片选引脚
}
unsignedcharSPI_WriteEnable()
{
Flash_CS=0;//使能CS引脚
SPI_SendByte(0x04)//写禁能指令
Flash_CS=1;//禁能片选引脚
}
3、读状态时序(指令:
0x05):
当/CS拉低之后,开始把05h从DIO引脚送到芯片,在CLK的上升沿数据被芯片采集,当芯片认出采集到的数据时05h时,芯片就会把“状态寄存器”的值从DO引脚输出,数据在CLK的下降沿输出,高位在前。
“读状态寄存器”指令在任何时候都可以用,甚至在编程、擦除和写状态寄存器的过程中也可以用,这样,就可以从状态寄存器的BUSY位判断编程、擦除和写状态寄存器周期有没有结束,从而让我们知道芯片是否可以接收下一条指令了。
如果/CS不被拉高,状态寄存器的值将一直从DO引脚输出。
/CS拉高之后,读指令结束。
程序设计流程:
1、使能片选,拉低CS引脚;
2、发送读取指令0x04;
3、循环发送读伪指令0xFF,等待非忙时跳出循环;
4、禁能片选,拉高CS引脚。
例程:
voidSPI_ReadStatus()
{
unsignedcharFlash_Status;
FLASH_CS=0;//使能片选引脚
SPI_SendByte(0x05);//发送读状态指令
do
{
Flash_Status=SPI_SendByte(0xFF);//发送伪指令维持时钟等待非空跳出循环,伪指令任意写。
}while(!
(Flash_Status&0x01));
FLASH_CS=1;//禁能片选引脚
}
4、写状态时序(指令:
0x01)
在执行“写状态寄存器”指令之前,需要先执行“写使能”指令。
先拉低/CS引脚,然后把01h从DIO引脚送到芯片,然后再把你想要设置的状态寄存器值通过DIO引脚送到芯片,拉高/CS引脚,指令结束,如果此时没有把/CS引脚拉高,或者是拉的晚了,值将不会被写入,指令无效。
只有“状态寄存器”当中的“SRP、TB、BP2、BP1、BP0位”可以被写入,其它“只读位”值不会变。
在该指令执行的过程中,状态寄存器中的BUSY位为1,这时候可以用“读状态寄存器”指令读出状态寄存器的值判断,当指令执行完毕,BUSY位将自动变为0,WEL位也自动变为0。
通过对“TB”、“BP2”、“BP1”、“BP0”位写1,就可以实现将芯片的部分或全部存储区域设置为只读。
通过对“SRP位”写1,再把/WP引脚拉低,就可以实现禁止写入状态寄存器的功能。
程序设计流程:
1、使能片选,CS引脚拉低;
2、发送写状态指令0x01;
3、发送读取指令0x04
4、禁能片选,CS引脚拉高。
例程:
voidSPI_FLASH_WriteStatus()
{
FLASH_CS=0;//使能片选引脚
SPI_SendByte(0x06);//写使能指令
SPI_SendByte(0x01);//写状态指令
SPI_SendByte(0x00);//写入状态的数据
FLASH_CS=1;//禁能片选引脚
}
5、读数据时序图(指令:
0x03):
“读数据”指令允许读出一个字节或一个以上的字节被读出。
先把/CS引脚拉低,然后把03h通过DIO引脚送到芯片,之后再送入24位的地址,这些数据在CLK的上升沿被芯片采集。
芯片接收完24位地址之后,就会把相应地址的数据在CLK引脚的下降沿从DO引脚送出去,高位在前。
当读完这个地址的数据之后,地址自动增加,然后通过DO引脚把下一个地址的数据送出去,形成一个数据流。
也就是说,只要时钟在工作,通过一条读指令,就可以把整个芯片存储区的数据读出来。
把/CS引脚拉高,“读数据”指令结束。
当芯片在执行编程、擦除和读状态寄存器指令的周期内,“读数据”指令不起作用。
程序设计流程(指令:
0x03):
1、使能片选,拉低CS引脚;
2、发送读数据指令0x03,紧接着发送24位地址;
3、读以SPI_DR寄存器数据
4、禁能片选,拉高CS引脚
例程:
voidSPI_FLASH_BufferRead(unsignedchar*pBuffer,unsignedintReadAddr,unsignedlongintNumByteToRead)
{
FLASH_CS=0;//拉低片选线选中芯片
SPI_SendByte(READ);//发送读数据命令
SPI_SendByte((ReadAddr&0xFF0000)>>16);//发送24位FLASH地址,先发高8位
SPI_SendByte((ReadAddr&0x00FF00)>>8);//再发中间8位
SPI_SendByte(ReadAddr&0x0000FF);//最后发低8位
while(NumByteToRead--)//计数
{
*pBuffer=SPI_SendByte(Dummy_Byte);//读一个字节的数据
pBuffer++;//指向下一个要读取的数据
}
FLASH_CS=1;//拉高片选线不选中芯片
}
6、快读时序图(指令:
0x0B):
“快读”指令和“读数据”指令很相似,不过,“快读”指令可以运行在更高的传输速率下。
先把/CS引脚拉低,然后把0Bh通过引脚DIO送到芯片,然后把24位地址通过DIO引脚送到芯片,接着等待8个时钟,之后数据将会从DO引脚送出去。
程序设计流程(指令:
0x0B):
1、使能片选,拉低CS引脚;
2、发送快读数据指令0x0B,紧接着发送24位地址;
3、发送8个字节伪指令等待8个时钟
4、读以SPI_DR寄存器数据
5、禁能片选,拉高CS引脚
例程:
voidSPI_FLASH_BufferRead(unsignedchar*pBuffer,unsignedintReadAddr,unsignedlongintNumByteToRead)
{
FLASH_CS=0;//拉低片选线选中芯片
SPI_SendByte(READ);//发送读数据命令
SPI_SendByte((ReadAddr&0xFF0000)>>16);//发送24位FLASH地址,先发高8位
SPI_SendByte((ReadAddr&0x00FF00)>>8);//再发中间8位
SPI_SendByte(ReadAddr&0x0000FF);//最后发低8位
SPI_SendByte(0xFF);//发送8个字节伪指令,等待8个时钟。
while(NumByteToRead--)//计数
{
*pBuffer=SPI_SendByte(Dummy_Byte);//发送伪指令读出一个字节的数据
pBuffer++;//指向下一个要读取的数据
}
FLASH_CS=1;//拉高片选线不选中芯片
}
7、快速读双输出(指令:
0x3B):
“快读双输出”指令和“快读”指令很相似,不过,“快读双输出”指令是从两个引脚上输出数据:
DI和DIO。
这样,传输速率就相当于两倍于标准的SP看传输速率了。
这个指令特别适合于需要在一上电就把代码从芯片下载到内存中的情况或者缓存代码段到内存中运行的情况。
“快读双输出”指令和“快读”指令的时序差不多。
先把/CS引脚拉低,然后把3Bh通过引脚DIO送到芯片,然后把24位地址通过DIO引脚送到芯片,接着等待8个时钟,之后数据将会分别从DO引脚和DIO引脚送出去,DIO送偶数位,DO送寄数位。
程序设计流程:
1、使能片选,拉低CS引脚;
2、写快读双输出指令0x3B,紧接着写24位地址;
3、写1个字节的伪指令,等待8个时钟;
4、读取SPI_DR寄存器
5、禁能片选,拉高CS引脚
例程(参考完整例程):
暂无。
8、页编程时序图(指令:
0x02):
执行“页编程”指令之前,需要先执行“写使能”指令,而且要求待写入的区域位都为1,也就是需要先把待写入的区域擦除。
先把/CS引脚拉低,然后把代码02h通过DIO引脚送到芯片,然后再把24位地址送到芯片,然后接着送要写的字节到芯片。
在写完数据之后,把/CS引脚拉高。
写完一页(256个字节)之后,必须把地址改为0,不然的话,如果时钟还在继续,地址将自动变为页的开始地址。
在某些时候,需要写入的字节不足256个字节的话,其它写入的字节都是无意义的。
如果写入的字节大于了256个字节,多余的字节将会加上无用的字节覆盖刚刚写入的的256个字节。
所以需要保证写入的字节小于等于256个字节。
在指令执行过程中,用“读状态寄存器”可以发现BUSY位为1,当指令执行完毕,BUSY位自动变为0。
如果需要写入的地址处于“写保护”状态,“页编程”指令无效。
程序设计流程:
1、写使能指令0x06,将芯片WEL位置0;
2、擦除芯片需要写入的区域,可以用扇区、块、芯片擦除指令;
3、使能片选,拉低CS引脚;
4、发送“页编程”指令0x02,接着发送24位地址、发送要写入的数据;
5、发读状态指令0x05检查芯片BUSY位操作是否结束
6、禁能片选,拉高CS引脚。
例程:
voidSPI_FLASH_PageWrite(unsignedchar*pBuffer,unsignedlongintWriteAddr,unsignedintNumByteToWrite)
{
SPI_FLASH_WriteEnable();//先使能对FLASH芯片的操作
FLASH_CS=0;//拉低片选线选中芯片
SPI_SendByte(WRITE);//发送页写命令
SPI_SendByte((WriteAddr&0xFF0000)>>16);//发送24位FLASH地址,先发高8位
SPI_SendByte((WriteAddr&0xFF00)>>8);//再发中间8位
SPI_SendByte(WriteAddr&0xFF);//最后发低8位
while(NumByteToWrite--)//发送地址后紧跟欲写入数据
{
SPI_SendByte(*pBuffer);//发送欲写入FLASH的数据
pBuffer++;//指向下一个要写入的数据
}
FLASH_CS=1;//拉高片选线不选中芯片
SPI_FLASH_WaitForWriteEnd();//等待写操作结束
}
程序说明:
*pBuffer是一个指针,是读取数据后的存储区,通常指向一个数组;
WriteAddr是24位芯片地址,需要把数据写到芯片什么位置就靠它了。
NumByteToWrite是写入字节的数量,例如需要写入50个字节,这里就给50。
写入的数据不可以大于256Byte,否则页地址会溢出,地址会从0开始,最前面写入的数据会被破坏,写入的数据大于256Byte时,重新用下一页的起始地址来写剩余的数据(处理翻页问题请在本章末尾查看完整例程)。
页编程完整流程图:
W25Q16总共有16Mbit空间,合计2MByte,共8192个页,每页256Byte。
因为每页是一个独立的单元,所以在写入数据时不支持自动翻页,如果写入的数据超出256Byte,那么页地址就溢出归零,数据又从零开始写,也就是说最先写入的数据会被破坏。
数据写入时可能碰到有几种情况,一种情况是:
页地址对齐的情况,就是页地址可以被256整除,且写入的数据不够256Byte,这种情况直接写入即可,不需要考虑翻页问题;第二种情况是:
写入的数据刚好是256Byte或者多一点点,这种情况写完一整页的数据后,就要把页地址加256跳到下一页的开始位置写剩余的数据;第三种情况是:
页地址不对齐情况,也就是页地址不能被256整除,这种情况说明,某页被用掉一部分,现在从剩余的空间继续向下写,如果空间够写就直接写入,不需要考虑翻页问题,如果空间不够写就要将页地址加上剩余空间的数跳转到下一页写剩余的数据,如果剩余的数据等于或大于256Byte,页地址还需要加256再向下进行翻页。
9、扇区擦除时序图(指令:
0x20):
“扇区擦除”指令将一个扇区C4K字节)擦除,擦除后扇区位都为1,扇区字节都为FFh。
在执行“扇区擦除”指令之前,需要先执行“写使能”指令,保证WEL位为1。
先拉低属CS引脚,然后把指令代码20h通过DIO引脚送到芯片,然后接着把24位扇区地址送到芯片,然后拉高属CS引脚。
如果没有及时把属CS引脚拉高,指令将不会起作用。
在指令执行期间,BUSY位为1,可以通过“读状态寄存器”指令观察。
当指令执行完毕,BUSY位变为0,WEL位也会变为0。
如果需要擦除的地址处于只读状态,指令将不会起作用。
程序设计流程:
1、先执行写使能指令;
2、使能片选,拉低CS引脚;
3、发送扇区擦除指令0x20,紧接着发送擦除的24位地址;
4、等待擦除指令结束,发送读状态指令查看BUSY位状态是否为0;
5、禁能片选,拉高CS引脚。
例程:
voidSPI_FLASH_BlockErase(unsignedlongintBlockAddr)
{
SPI_FLASH_WriteEnable();//FLASH写使能(该函数请查阅完整例程)
FLASH_CS=0;//拉低片选线选中芯片
SPI_SendByte(0xD8);//发送块或扇区(0x20)擦除命令SPI_SendByte((BlockAddr&0xFF0000)>>16);//发送24位FLASH擦除地址,先发高8位
SPI_SendByte((BlockAddr&0x00FF00)>>8);//再发中间8位
SPI_SendByte(BlockAddr&0x0000FF);//最后发低8位
FLASH_CS=1;//拉高片选线不选中芯片
SPI_FLASH_WaitForWriteEnd();//等待块清除操作完成(该函数请查阅完整例程)
}
10、芯片擦除时序图(指令:
0xC7):
“芯片擦除”指令将会使整个芯片的存储区位都变为1,即字节都变位FFh。
在执行“芯
片擦除”指令之前需要先执行"写使能"指令。
先把/CS引脚拉低,然后再把指令代码C7h通过DIO引脚送到芯片,然后拉高/CS引脚。
如果没有及时拉高/CS引脚,指令无效。
在“芯片擦除”指令执行周期内,可以执行“读状态寄存器”指令访问BUSY位,这时BUSY位为1,当“芯片擦除”指令执行完毕,BUSY变为0,WEL位也变为0。
任何一个块区处于保护状态(BP2\BP1\BP0),指令都会失效。
程序设计流程:
1、发送0x06写使能;
2、使能片选,拉低CS引脚;
3、发送擦除指令0xC7,紧接着发送24位擦除地址;
4、禁能片选,拉高CS引脚
5、等待操作完成。
例程:
voidSPI_FLASH_ChipErase(void)
{
SPI_FLASH_WriteEnable();//FLASH写使能
FLASH_CS=0;//拉低片选线选中芯片
SPI_SendByte(Chip_E);//发送芯片擦除命令
FLASH_CS=1;//拉高片选线不选中芯片
SPI_FLASH_WaitForWriteEnd();//等待写操作完成
}
11、“释放掉电/器件ID”指令(命令:
0xAB):
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 华邦 W25Q16 存储器 颗粒 SPI 编程