STM32F0单片机快速入门十:用 SPI HAL 库读写W25Q128
1. W25Q128 介绍
当我们有比较多的数据需要掉电存储时,上一篇文章所介绍的 24C02 (256个字节EEPROM)就不够了。此时我们会用到另外一种类型的存储器,即 Flash。比如具有 SPI 接口的 W25Q128。这颗小芯片虽然也只有简单的 8 个引脚,但存储容量却达到了128M-bit,也就是 16M 字节,同时它的读写速度可以达到 66MB/S。但是由于 STM32F030 不支持 Quad/Dual SPI,只能以标准 SPI 方式读写,所以速度会低一些。以下是 W25Q128 的主要特点:
a. 133MHz SPI Clock。
b. 10万次擦写寿命,20年数据保持时间。
c. 每颗具有64-Bit唯一序列号 Unique ID。
d. 每次可以写入 1 到 256 字节数据。
e. 写之前需要对目的地址所在扇区进行擦除操作。
( Winbond W25Q128 datasheet )
我们通过以下连线使 W25Q128 连至 STM32F030 的 SPI1:
W25Q128 STM32F030
Pin 1 /CS PA4 也可以用其它 GPIO 引脚
Pin 2 DO PA6 SPI1_MISO
Pin 3 /WP ( VCC )
Pin 4 GND ( GND )
Pin 5 DI PA7 SPI1_MOSI
Pin 6 CLK PA5 SPI1_SCK
Pin 7 /HOLD or /RESET ( VCC )
Pin 8 VCC ( VCC )
2. 代码
代码的开发如果想提高效率,一个方法就是充分利用前人的成果,而不是自己一再的去造轮子。
对于W25Q128 我们可以从Github上找到驱动代码:
https://github.com/nimaltd/w25qxx
GNU General Public License v3.0
我们把它集成进SPI例程里,完成 W25Q128 的读写功能。
Step 1,下载后把解压的文件夹 w25qxx-master 放在 STM32Cube_FW_F0_V1.11.0\Drivers\BSP\Components
Step 2, 我们用 Keil 打开下面这个工程:
STM32Cube_FW_F0_V1.11.0\Projects\STM32F030R8-Nucleo\Examples\SPI\SPI_FullDuplex_ComPolling\MDK-ARM\Project.uvprojx
在项目(STM32F030R8-Nucleo)上点鼠标右键,选择Add Group...
新建 Group 并改名称为 Drivers\BSP\Components\w25qxx-master
Step 3, 在 Drivers\BSP\Components\w25qxx-master上点右键,选择Add Existing Files to Group "Drivers\BSP\Components\w25qxx-master"...,
找到 Drivers/BSP/components/w25qxx-master/w25qxx.c 点击Add,然后可以看到w25qxx.c已经添加进项目中:
Step 4, 在 Options for Target 里添加路径,这里使用的是工程所在路径的相对路径,也可以使用绝对路径,但如果工程拷贝到别的地方的时候,此包含路径就需要跟随更改。
Add include path ../../../../../../Drivers/BSP/components/w25qxx-master
Step 5, 驱动头文件 w25qxx.h 中原来包含的的 spi.h, 因为我们使用的 Cube 库,头文件需要做如下替换:
//#include "spi.h"
#include "stm32f0xx_hal.h"
Step 6, main.h 里根据实际情况配置引脚,把驱动头文件 #include "w25qxx.h" 包含进来。片选信号 CS 可以由任意一个 GPIO 控制,在函数
HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
里把CS引脚配置为GPIO输出就行了,实际的拉低拉高是驱动代码实现的。
Step 7, 在 main.c 里定义了 SpiHandle 并指向 SPI1, 我们在 w25qxx.c里也要用到这个 Handle,所以通过 extern 来引用一下。
Step 8, 初始化 SPI1,然后调用 w25qxx 驱动的初始化代码 W25qxx_Init( ); 然后就可以用擦除,读写等函数了。
在代码的修改过程中,我们可以再次体会 Cube 库的这种分层结构带来的好处,特别是如何与第三方驱动代码融合。各个模块就像积木一样,我们只需要把它们搭建起来就可以快速的实现我们想要的功能。
下面是读出数据时实际抓取的波形:
参考资料:
PM0215 STM32F0xxx Cortex-M0 programming manual
UM1785 Description of STM32F0 HAL and low-layer drivers
Winbond W25Q128 Datasheet
STM32F030 Datasheet
STM32F030 Reference Manual
STM32的SPI通信(1)——硬件SPI
学过单片机的朋友,对于SPI通信应该比较熟悉吧。小秋也差不多,自学过野火的视频教程,也看过正点原子的视频教程,但是,小秋总感觉自己没有掌握,比如新上手一个SPI通信的芯片,关于SPI的程序还是那么陌生,不知道各位有没有这种类似的情况。现在,小秋由表及里,认真剖析一下SPI,看看SPI通信到底哪点不好掌握。
拿到一块SPI通信的芯片,首先是要解决单片机跟这块芯片的通信问题,能读能写;其次是对这块芯片进行寄存器设置。明确知道了这两个步骤之后,小秋就明白了,为什么小秋之前不能够熟练的掌握SPI。以前把这两个步骤混合起来了,寄存器设置比较麻烦,需要看其datasheet,而且还是英文的,所以如果以上两个步骤一起做,就总觉得很困难,而且需要在英文datasheet中搜寻,总感觉无所下手。所以,分步进行是非常有必要的。今天来实现的功能就是,对这块芯片进行SPI通讯,能读能写。读的话,我们一般都会去读芯片id,看读出的结果是否与datasheet中介绍的一致,同时也就验证了读函数的正确性。至于写函数呢,好像一般也就没有进行验证。我们可以这样,先去读芯片id,保证读函数的正确;再往一个能读写的寄存器中进行写操作,然后再读回来,看写进去的值是否与读出来的值一致,这样也就验证了写函数是否正确。
1)下面简要介绍一下SPI时序。
SSEL:片选信号;
SCK:时钟信号;
MOSI:主机输出,从机输入;
MISO:主机输入,从机输出。
SPI通信时序图1
SPI通信时序图2
SPI通信时序图3
SPI通信时序图4
CPOL:时钟的极性。如果SCK在数据发送之前和发送之后是都高电平,那么CPOL=1;
CPHA:时钟的相位。如果数据的输出在SCK的第一个沿上,那么CPHA=0。
以SPI通信时序图1来进行分析,空闲时刻SCK为高电平,所以CPOL=1;在SCK的第二个沿上(即上升沿),数据是稳定的,可以进行数据采样,所以CPHA=1。
以上4种时序图,做到心里有数就行。
2)以STM32F407为开发平台,通过硬件SPI对W25Q128进行读写操作:
首先我们来看一下W25Q128的引脚定义:
我们采用标准的SPI通信,绘制出如下原理图:
通过W25Q128的datasheet,我们可以知道,W25Q128支持SPI标准通信:模式0(CPOL=0,CPHA=0)与模式3(CPOL=1,CPHA=1)。以下程序我们都采用模式3进行读写操作。
以下为在STM32F407下,SPI1的设置:
读取W25Q128芯片的ID,看其datasheet:
时钟SCK置低电平,发送90h(8个SCK)、00h(8个SCK)、00h(8个SCK)、00h(8个SCK),返回高8位(8个SCK)、低8位(8个SCK)。看图中的DI、DO,就可知道是高位在前,低位在后。所以可以写出读取芯片ID的函数:
因为SPI是全双工通信,在读的时候同时写,所以函数用ReadWrite表示。
那么W25Q128的ID为多少呢,看其datasheet:
所以如果能够正确读取W25Q128的话,W25Q128_ID=0xEF17。
运行以下程序,下载进去之后发现,蜂鸣器响,证明写的程序都是正确的。
如果没有蜂鸣器的话,可以用指示灯,或者通信验证,或者直接进行调试,验证W25Q128_ID是否等于0xEF17。
不知道细心的朋友有没有发现,小秋在读取芯片ID的时候,同时使用了写函数和读函数。使用硬件SPI,读写函数是同一个。SPI1_ReadWriteByte()既是写入函数,又是读取函数,所以现在我们已经验证了读函数和写函数的正确。这样说起来感觉有点拗口,明天小秋写一篇文章,《STM32的SPI通信(2)——模拟SPI》,在读取芯片ID的时候,既有写入函数,又有读取函数,而且这两个函数是不一样的,这样子我们就可以看得比较明显了。此外,今天的单片机平台是基于STM32F407的,明天实现完模拟SPI之后,在STM32F103上实现一下硬件SPI和模拟SPI,看这两个平台有什么不一样的地方。
相关问答
在电路中com(ma|n)是什么意思?com一般表示公共端;很多时候都是直接接地;但是要根据你的电路来不清楚的可以根据实际的芯片去找对应的datasheet,看一下com一般表示公共端;很多时候都是直接...
【电子元器件数据手册 datasheet 中封装尺寸的引脚宽度如何计...[最佳回答]好的厂家给出的datasheet中,封装器件的尺寸都很详细.一般是元器件尺寸图在上面,下面会有个表格标明各个字母代表的数值.一一对应即可知道元器件尺寸...
datasheet 是可数还是不可数名词?datasheet数据表示不可数名词Fieldselector:Asmallboxorbarthatyouclicktoselectanentirecolumnina...
如何从元器件 datasheet 中提取需要的信息?先通过其他软件将datasheet(一般是pdf格式)中的pinname,pinnumber转成word/excel。有excel整理好这些pinname,pinnumber.在orcad...
摩尔资料卡哪里看?用户可以通过访问各大电子元器件供应商的网站或在线元器件库查询相关元器件的摩尔资料卡。常见的元器件供应商包括Digi-Key、Mouser、Avnet等,这些网站提供了...
STM32外设名字括号中的数字是什么意思?如SPI1_NSS(7)/USART2...[回答]你是说引脚定义那张表格吧?表格的下面有几条注释,括号里面的数字对应该条注释.比如我这个STM32F103的第7是(不同版本的datasheet不一样):7.Unlikei...
ka3824参数?输入电压范围5~30V,最大功耗=1W,振荡器频率≥500kHz,基准电压=5V,电压调整率=6mV,电流调整率=6mA,输出端最大电流=1000mA,最大占空度=95%。K...输...
在 Datasheet 上如何查芯片的引脚功能?要查芯片的引脚功能,首先需要找到芯片的Datasheet。在Datasheet中,通常会有引脚定义表,其中列出了每个引脚的名称、编号和功能。可以根据引脚编号或名称,找到...
wps怎么打印一个文件夹内的多个表格-ZOL问答并确保选择了包含所有工作表的相应工作簿(即sheet1-sheet7)。2.在页面左上角...SubCombineSheetsCells()DimwsNewWorksheetAsWor...
二极管上的加号代表什么?这个是厂家自己决定的。两组代码一般是一个生产批号,一个型号代码。型号代码有世界通用的如1P4008,也有厂家自己定义的,需要去查厂家的datasheet。至于哪个在...