stm32驱动W24Q16
0赞W24Q16是FLASH存储芯片,容量为16Mbit。注意是16Mbit,其实就是2M-byte。W24Q16采用的是spi总线。但是这个spi总线有三种方式。
首先列下该芯片的管脚图:
第一种是标准spi(Standard)。即传统的四根线,CS片选信号,clk时钟信号,DI数据输入信号,DO数据输出信号。这个时候,WP和HOLD有自己的功能。
第二种是双SPI模式(Dual SPI)。这个时候还是用到4根线,CS片选信号,clk时钟信号,不过这里的DI和DO变成双向的IO线了,即用到了IO1和IO2。这个时候,WP和HOLD还是有自己的功能。
第三种是正交SPI模式(Quad SPI,这里暂且这么翻译)。这个时候会用到6根线,即所有信号线都使用了。CS片选信号,clk时钟信号,这个还是一样,不过变化的是,数据线用到了4个,IO0-IO3。所以这个时候,WP和HOLD本身的功能就没有了。
看看这三种模式的传输有什么区别。
其实三个都是用的SPI协议,即首先要CS片选有效,然后在clk的时钟下,发送数据和接收数据,不同的只是信号线的使用。
看看时序图,以读数据为例
第一种
第二种
第三种:
从时序图,就可以看出区别了吧。
在读数据的时候,发命令和发地址都是一样的,都是DI这个管脚接收。但是在读数据的时候,就不一样了。
对于第一种,只有DO一个管脚输出,所以需要8个时钟周期输出一个字节的值。
对于第二种,有两个管脚输出,所以只需要4个时钟周期就输出一个字节的值,
对于第三种,就更快了,有4个管脚,所以只需要两个时钟周期就输出一个字节的值。
所以,看出,其实就是读取数据的快慢而已,同样的时间下,第三种读取最快。但是用的管脚多,第一种最慢,但是用的管脚少。至于命令,地址,这些都是一样的。
写数据也是差不多的。
看看芯片的内存地址是怎么排布的。
在芯片中,最大的单位是块,然后是扇区,最后是页。
看图:
这图就说明很清楚了,
一个块64KB,包括16个扇区,因为一个扇区4KB大。一个扇区又包括16页。因为一个页256字节大。
为什么要定义这么复杂的结构,那是为了以后的操作使用。这个说道指令的时候就知道了。
然后就是芯片的内部寄存器。芯片有两个内部寄存器,这两个内部寄存器记录了一些信息。
第一个寄存器,
第0位:记录了芯片是否忙状态。因为在写入数据和擦除数据的时候,是需要时间的。你不能在上一个数据还没有写成功之前,又马上写入下一个数据。所以这个位就指示了,现在是否在写状态,如果为1的话,说明,现在还在写,所以在这个时候就不能写入数据。为0的话,说明现在芯片空闲,可以写入数据了。
第1位:指示是否可写。该芯片是有保护数据功能的,即写数据不能你想写就能写。你必须要这位为1,指示芯片可写,然后才能写入数据。否则芯片是不响应你写数据的命令的。所以在写入数据和擦除数据之前,需要把这位给置1.另外还要注意的是:每当写完数据或者擦除数据后,该位会自动为0.即变成不可写。所以在每次写之前都要将这位置1.而不能就初始化的时候置1就行了。否则会发现,只写了一次数据,后面在写数据就不行了。
第7-2位和寄存器2的第0位:这几位是指示保护的。上面的写保护,是保护数据不能随意更改,必须要写保护取消。而这几位,是指示在写数据的工程,那么位置是数据是要保护的,不允许更改的。因为有时候,需要某一部分的数据需要保持不变,写数据或者擦除的时候忽略这一部分。这个就干这个功能的。具体看看数据手册就知道了,很简单的。
第二个寄存器
第1位:这个事用来指示现在的操作是否是第三种SPI模式。1的话,是第三种SPI模式,否则不是。
这里为什么只有指示第三种模式,而没有指示第二种模式了,因为第二种模式其实是在第一种模式的变形,所以是通过不同的命令来实现的。
下面就是重要的命令了。
我们知道,对于SPI协议来说,第一个数据,肯定是命令,表示你要对芯片进行什么操作。所以一切的操作都是基于命令的。
这个芯片的命令特别多:
首先是读器件的一些信息的命令。
通过上面这些命令,可以读出器件的一些信息,后面也说明了,读出来的信息为什么。
下面才是重点了
看上面的,命令是不是特别多。
第一个命令:写使能,这个就是之前说的,将内部寄存器位1的值给置1,使能写数据或者擦除数据。
第二个命令,写取消。这个看名字就知道了,将内部寄存器位1的值给置0,禁止写数据和擦除数据。
第三个命令:读状态寄存器1的值。刚刚说了,内部有两个状态寄存器,这里是读取第一个。发完命令后读取的第一个字节值就是了。
第四个命令:读状态寄存器1的值。这里是读取第二个。发完命令后读取的第一个字节值就是了。
第五个命令:写状态寄存器。这里就是写那两个状态寄存器的值。配置芯片的工作模式。发完命令后在发送的写入的值就是了。不过注意寄存器的顺序。
第六个命令:页写入。FLASH和一般的存储芯片不一样,是不能随意写的,是要按页写的,即从页的首地址开始写。不能从其他位置写。写入的数据最多是256字节。超过256字节,就把超过的数据从页的首地址从新开始写。而且,在写数据之前,是要将写数据的地方给擦除的。即只有擦除过的地方,写的数据才正确,没有擦除过的地方,写的数据就不正确。因为页地址是256字节。所以这里的命令后面跟着的3个字节的地址,对256取余是要为0的。即页对齐。
第七个命令: 正交SPI方式页写入。和页写入一样的,只是数据由4根线传输。
第8-11命令:是擦除数据命令。这里就可以看出,为什么之前看到的芯片的地址那么复杂,需要块,扇区,页。就是方便擦写的。因为在写数据之前,是要擦写数据的。那么怎么擦写,这就是关键了。这里从命令可以看出,配置了4种擦写。后面跟着的就是擦写的地址。
后面的命令就不介绍了。
然后是读命令了
这里读命令,就分有那种SPI模式读了。这个也很简单,就不介绍了。。
以上的dummy,是说明,这个数据是什么不重要。一般设为0xff。
搞定了这些基础知识后,编程那就很简单了。
首先是封装stm32自带的spi库函数。封装为发一个数据,同时把数据读取回来。但是要注意库函数是只有标准SPI模式的。如果要用两种模式的话,需要自己写了。
uint8_t spi_write_byte(uint8_t data) { while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1,data); while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI1); }
代码如上,就是调用了SPI库函数。发送的是data值,函数返回读取的值。
剩下的就是封装命令,写数据,读数据就可以了。。代码就不说了,因为真是有点简单,因为最低层的SPI发送函数已经写好了,就只要不断的调用就行了。