你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32接口篇之SPI接口和W25Q16初始化详解  

[复制链接]
bb123 发布时间:2016-8-25 15:48


STM32接口篇之SPI接口
                                                        ---SPI接口操作FLASH存储芯片W25Q16初始化代码详细分析
学习STM32F4SPI接口和FLASH存储芯片W25Q16,通过对初始化代码分析,更好的了解STM32SPI接口编程中的一些关键知识点。

学习素材:
l  W25Q16数据手册
l  电路原理图
l  STM32F4应用手册
针对W25Q16SPI接口初始化代码


1 硬件电路说明
(1)=关键原理图

FLASH芯片接口图

1.jpg

GPIO接口图
2.jpg

3.jpg
(2)   原理图说明
首先我们看到上面第一个图,第一个图展示了W25Q16的原理图信息,我们配合W25Q16的数据手册(第六页 见下图),我们分析具体IO的连接和功能,分析结果见下表
4.jpg
5.jpg

  
管脚号
  
名称
连接的io或者信号
功能
  
1
  
CS
PB0(不复用)
片选信号 该信号低有效  即当该信号为低电平的时候对W25Q16的操作是有效的
  
2
  
DO
PB4(复用SPI1_MOSI或者SPI3_MOSI
数据输出信号
  
3
  
WP
3.3V
写保护输入 当该信号为低电平是开启写保护  无法写入数据 从图中我们可以看出 这个管脚直接接在高电平3.3V上面 始终不开启写保护(不过做一个上拉应该会更好)
  
5
  
DI
PB5(复用SPI1_MISO或者SPI3_MISO
数据输入信号
  
6
  
CLK
PB3(复用SPI1_CLK或者SPI3_CLK)
时钟信号
注意:配合(1)中的GPIO接口图,我们可以得到具体IO的复用方法,在上表中已经给出。

(3)   编程需求
通过上表的分析,我们可以得出如下编程需求:
l  PB3(CLK),PB4(MOSI),PB5(MISO)初始化为复用功能(可以使用复用SPI接口或者SPI3接口,因为SPI1和SPI3控制器的相关引脚都在这三个IO上,见GPIO接口图)
l  PB0初始化为普通IO,该IO的功能是在操作SPI接口的时候,拉低该IO,操作结束以后,拉高该IO。
l  初始化配置SPI控制器,该控制器的初始化要配合W25Q16芯片手册进行。


2 初始化程序分析(1)   代码展示
void SPI1_Init(void)
{                 
GPIO_InitTypeDef  GPIO_InitStructure;         
SPI_InitTypeDef  SPI_InitStructure;         
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//使能GPIOB时钟        
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);//使能SPI1时钟         
//GPIOFB3,4,5初始化设置         
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;        
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF;//复用功能        
GPIO_InitStructure.GPIO_OType= GPIO_OType_PP;//推挽输出         
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_100MHz;//100MHz        
GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_UP;//上拉         
GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化        
GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1);//PB3复用为 SPI1         
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1);//PB4复用为 SPI1        
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1);//PB5复用为 SPI1              
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//复位SPI1        
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1         
SPI_InitStructure.SPI_Direction= SPI_Direction_2Lines_FullDuplex;           
SPI_InitStructure.SPI_Mode= SPI_Mode_Master;                   //设置SPI工作模式:设置为主SPI         
SPI_InitStructure.SPI_DataSize= SPI_DataSize_8b;                          
SPI_InitStructure.SPI_CPOL= SPI_CPOL_High;                          
SPI_InitStructure.SPI_CPHA= SPI_CPHA_2Edge;   //串行同步时钟的第二个跳变沿(上升或下降)数据被采样         
SPI_InitStructure.SPI_NSS= SPI_NSS_Soft;               //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制         SPI_InitStructure.SPI_BaudRatePrescaler= SPI_BaudRatePrescaler_256;            //定义波特率预分频的值:波特率预分频值为256         SPI_InitStructure.SPI_FirstBit= SPI_FirstBit_MSB;         //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始         SPI_InitStructure.SPI_CRCPolynomial= 7;      //CRC值计算的多项式         
SPI_Init(SPI1,&SPI_InitStructure);        
SPI_Cmd(SPI1, ENABLE); //使能SPI外设         
SPI1_ReadWriteByte(0xff);//启动传输            
}     

void W25QXX_Init(void){     
GPIO_InitTypeDef  GPIO_InitStructure;   
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//使能GPIOB时钟
//GPIOB0    GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0;//PB0   
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_OUT;//输出   
GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;//推挽输出   
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_100MHz;//100MHz   
GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_UP;//上拉   
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化         
W25QXX_CS=1;                           //SPI FLASH不选中        
SPI1_Init();                                         //初始化SPI         
SPI1_SetSpeed(SPI_BaudRatePrescaler_2);             //设置为42M时钟,高速模式         
W25QXX_TYPE=W25QXX_ReadID();        //读取FLASH ID.
}  
(2)   代码分析1.  初始化代码总体分析由展示的代码,我们可以看出,对W25Q16的初始化主要使用了两个函数,主要调用函数void W25QXX_Init(void)对W25Q16进行初始化,而该函数又调用了SPI1_Init()函数对SPI1接口进行初始化。代码主要流程图如下: 6.jpg

通过以上流程图,我们可以看出对W25Q16的初始化,主要是初始化SPI接口。下面对代码具体说明。
2.  代码详细分析(我们主要分析SPI1接口的初始化函数)我们先分析函数voidSPI1_Init(void),对该函数里面的没一行代码进行详细说明l  GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef  SPI_InitStructure;
代码分析:首先定义了两个结构体变量,这两个结构体的类型定义在GPIO和SPI的库函数中,主要作为GPIO和SPI初始化调用的参数,我们一会详细分析。
l  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);//使能SPI1时钟
代码分析:STM32有着强大且细分的时钟系统,我们可以单独的对每一个控制器的时钟进行使能,这样可以更好的降低功耗。因此,这两句分别使能GPIOB和SPI1的时钟。关于时钟库函数的说明,请看我的《STM32库函数说明及示例-RCC篇》
l  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF;//复用功能         
GPIO_InitStructure.GPIO_OType= GPIO_OType_PP;//推挽输出         
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_100MHz;//100MHz         
GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_UP;//上拉GPIO_Init(GPIOB,&GPIO_InitStructure);

//初始化代码分析:这几行代码主要是初始化结构体参数GPIO_InitStructure,该参数指定了GPIO的一些具体的配置,注意第二行代码,我们把PB3,PB4和PB5设置成复用功能。第三行我们采用推挽输出,可以得到更大的驱动能力。第四行我们把IO的最大翻转速度配置成100MHZ,因为考虑PB3作为SPI的时钟口,最高的频率可达42MHZ。其它关于GPIO库函数GPIO_Init(GPIOB, &GPIO_InitStructure)的详细解释,请见我的《STM32库函数说明及示例-GPIO篇》。

l  GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3复用为 SPI1         GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1);//PB4复用为
SPI1GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1);//PB5复用为 SPI1

代码分析:以上三行实现管脚复用功能的具体配置,我们分别把PB3,PB4和PB5配置成SPI1接口的复用功能。关于该函数的详细说明,请见我的《STM32库函数说明及示例-GPIO篇》。

l  RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);        
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);         对SPI1接口的时钟进行复位,以便进行SPI接口的初始化操作l  SPI_InitStructure.SPI_Direction =SPI_Direction_2Lines_FullDuplex;           
SPI_InitStructure.SPI_Mode= SPI_Mode_Master;                   //设置SPI工作模式:设置为主SPI        
SPI_InitStructure.SPI_DataSize= SPI_DataSize_8b;                          
SPI_InitStructure.SPI_CPOL= SPI_CPOL_High;                          
SPI_InitStructure.SPI_CPHA= SPI_CPHA_2Edge;            
SPI_InitStructure.SPI_NSS= SPI_NSS_Soft;                       
SPI_InitStructure.SPI_BaudRatePrescaler= SPI_BaudRatePrescaler_256;                           
SPI_InitStructure.SPI_FirstBit= SPI_FirstBit_MSB;                  
SPI_InitStructure.SPI_CRCPolynomial= 7;      //CRC值计算的多项式         
SPI_Init(SPI1,&SPI_InitStructure);   
   
代码分析:这一段代码是SPI接口初始化的关键代码,在该代码中,对结构体变量SPI_InitStructure里面的成员变量进行了初始化。以下分别进行说明:
Ø  第一行使用宏SPI_Direction_2Lines_FullDuplex将SPI接口配置成双线全双工模式,因为硬件接口使用了输入和输出两个IO,所以应该是双线模式,而且W25Q16的数据是在收发两个方向同时传输,所以是全双工模式。
Ø  第二行设置STM32的SPI接口工作在主模式(SPI_Mode_Master)。因为读写数据的请求都是由STM32主动发出,所以是主设备。这里,大家要搞清楚主从设备的区别,通信的发起方就是主设备。
Ø  第三行设置数据长度为8位(SPI_DataSize_8b),因为W25Q16的最小传输数据单位(或者说每个地址对应的数据是1个字节)是1个字节。1个字节是8位,所以选择8位。
Ø  第四行和第五行分别设置极性和相位为SPI_CPOL_High和SPI_CPHA_2Edge。SPI_CPOL_High表示时钟的初始电平位高电平,SPI_CPHA_2Edge表示在第二个边沿进行数据采样(见下图1)。这样的组合是SPI数据传输模式中的模式3。根据W25Q16的数据手册,W25Q16支持MODE0(MODE0是SPI的初识电平为低电平,在第一个边沿进行数据采样配置组合是SPI_CPOL_Low,SPI_CPHA_1Edge)和MODE3。请见图2黄色部分。因此这里我们选择MODE3,当然选择MODE0也是可以的。
8.jpg
图1:SPI MODE3时序图

7.jpg
图2

Ø  第六行设置SPI_NSS信号,由软件产生。因为我们没有使用硬件NSS信号,所以选择由软件产生NSS信号。大家注意我们的CS管脚是连接到普通IO上面的,因此没有使用硬件NSS。
Ø  第七行配置SPI时钟的分频值为256(SPI_BaudRatePrescaler_256),因此实际的时钟值是APB2的时钟/256 Ø  第八行配置SPI的第一位是最高有效位(SPI_FirstBit_MSB)。这个也是和W25Q16相关的。请见下图红色箭头部分。
9.jpg
      
Ø  第九行配置SPI的CRC校验多项式为7
Ø  第十行调用SPI_Init(SPI1, &SPI_InitStructure);对SPI1接口进行初始化。
l  SPI_Cmd(SPI1, ENABLE); //使能SPI外设SPI1_ReadWriteByte(0xff);//启动传输  
以上第一行使能SPI接口,第二行使用SPI接口写入一个0XFF,以启动数据的传输。相当于启动数据发送器。



基于STM32的SPI接口操作W25Q16初始化代码详细分析.pdf

下载

760.51 KB, 下载次数: 973

STM32-SPI-W25Q16

评分

参与人数 1 ST金币 +10 收起 理由
zero99 + 10

查看全部评分

1 收藏 7 评论25 发布时间:2016-8-25 15:48

举报

25个回答
bb123 回答时间:2016-8-25 15:52:13
本帖最后由 bb123 于 2016-8-25 15:53 编辑

发新贴了 SPI接口和W25Q16 请大家一起学习分享 有什么问题请及时提出
我的其它两篇帖子请参考
STM32库函数注释翻译,每个函数使用说明及使用示例
https://www.stmcu.org.cn/module/forum/thread-607584-1-1.html
STM32库函数翻译,每个函数说明及示例-RCC(时钟)篇(上)
https://www.stmcu.org.cn/module/forum/thread-607608-1-2.html

beebird 回答时间:2016-8-26 23:03:58
好文章,正准备学STM32的SPI的使用
disheng4688 回答时间:2016-8-27 08:58:56
谢谢分享。
kunchen 回答时间:2017-2-6 09:25:16
谢谢分享
yimao111 回答时间:2017-5-16 10:55:21
楼主,你的2.5 引脚的MOSI和MISO 弄反了吧
yimao111 回答时间:2017-5-16 10:56:26
楼主,你的2.5 引脚的MOSI和MISO 弄反了吧
lanmanck 回答时间:2017-5-22 11:39:18
yimao111 发表于 2017-5-16 10:55
楼主,你的2.5 引脚的MOSI和MISO 弄反了吧

他用io模拟,你管得着!
langtaosha 回答时间:2017-6-10 10:45:30
多谢楼主,辛苦了
艾汇思 回答时间:2017-6-14 10:22:59
楼主,您把整个源代码发出来给我们学习好不好?谢谢了!
123下一页

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版