STM32基础之SPI

发布者:RainbowDreamer最新更新时间:2022-04-20 来源: eefocus关键字:STM32  基础  SPI 手机看文章 扫描二维码
随时随地手机看文章

SPI简介

SPI协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线。


SPI接口主要应用在EEPROM、FLASH、实时时钟、AD转换器,还有数字信号处理器和数字信号解码器之间。SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,比如AT91RM9200。


SPI分为主、从两种模式,一个SPI通讯系统需要包含一个(且只能是一个)主设备,一个或多个从设备。SPI接口的读写操作,都是由主设备发起。当存在多个从设备时,通过各自的片选信号进行管理。


优点:支持全双工通信、通信简单、数据传输速率快;

缺点:没有指定的流控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据的可靠性上有一定的缺陷。


SPI引脚说明

在这里插入图片描述

SS:从设备选择信号线,常称为片选信号线,也称为NSS、CS。

每个从设备都有独立的这一条SS信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。当主机要选择从设备时,把该从设备的SS信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行SPI通讯。所以SPI通讯以SS线置低电平为开始信号,以SS线被拉高作为结束信号。


SCK (Serial Clock):时钟信号线,用于通讯数据同步

每它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如STM32的SPI时钟频率最大为fpclk/2,两个设备之间通讯时,通讯速率受限于低速设备。


MOSI (Master Output, Slave Input):主设备输出/从设备输入引脚。

MISO(Master Input,,Slave Output):主设备输入/从设备输出引脚。

SPI协议层

SPI基本通讯过程

在这里插入图片描述

标号①处,NSS信号线由高变低,是SPI通讯的起始信号。NSS是每个从机各自独占的信号线,当从机检在自己的NSS线检测到起始信号后,就知道自己被主机选中了,开始准备与主机通讯。


在图中的标号⑥处,NSS信号由低变高,是SPI通讯的停止信号,表示本次通讯结束,从机的选中状态被取消。


SPI使用MOSI及MISO信号线来传输数据,使用SCK信号线进行数据同步。MOSI及MISO数据线在SCK的每个时钟周期传输一位数据,且数据输入输出是同时进行的。


SPI通讯模式

在这里插入图片描述

时钟极性CPOL是指SPI通讯设备处于空闲状态时,SCK信号线的电平信号(即SPI通讯开始前、 NSS线为高电平时SCK的状态)。CPOL=0时, SCK在空闲状态时为低电平,CPOL=1时,则相反。


时钟相位CPHA是指数据的采样的时刻,当CPHA=0时,MOSI或MISO数据线上的信号将会在SCK时钟线的“奇数边沿”被采样。当CPHA=1时,数据线在SCK的“偶数边沿”采样。


SPI通信有4种不同的模式,不同的从设备可能在出厂是就是配置为某种模式,这是不能改变的;但我们的通信双方必须是工作在同一模式下,所以我们可以对我们的主设备的SPI模式进行配置,通过CPOL(时钟极性)和CPHA(时钟相位)来控制我们主设备的通信模式,具体如下:

在这里插入图片描述

STM32的SPI架构剖析

在这里插入图片描述

通讯引脚

STM32芯片有多个SPI外设,它们的SPI通讯信号引出到不同的GPIO引脚上,使用时必须配置到这些指定的引脚,以《STM32F10x规格书》为准。

其中SPI1是APB2上的设备,最高通信速率达36Mbtis/s,SPI2、SPI3是APB1上的设备,最高通信速率为18Mbits/s。除了通讯速率,在其它功能上没有差异。


时钟控制逻辑

SCK线的时钟信号,由波特率发生器根据“控制寄存器CR1”中的BR[0:2]位控制,该位是对fpclk时钟的分频因子,对fpclk的分频结果就是SCK引脚的输出时钟频率

数据控制逻辑

SPI的MOSI及MISO都连接到数据移位寄存器上,数据移位寄存器的数据来源来源于接收缓冲区及发送缓冲区。


通过写SPI的“数据寄存器DR”把数据填充到发送缓冲区中。


通过读“数据寄存器DR”,可以获取接收缓冲区中的内容。


其中数据帧长度可以通过“控制寄存器CR1”的“DFF位”配置成8位及16位模式;配置“LSBFIRST位”可选择MSB先行还是LSB先行。


整体控制逻辑

整体控制逻辑负责协调整个SPI外设,控制逻辑的工作模式根据“控制寄存器(CR1/CR2)”的参数而改变,基本的控制参数包括前面提到的SPI模式、波特率、LSB先行、主从模式、单双向模式等等。


在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器(SR)”,只要读取状态寄存器相关的寄存器位,就可以了解SPI的工作状态了。除此之外,控制逻辑还根据要求,负责控制产生SPI中断信号、DMA请求及控制NSS信号线。


实际应用中,一般不使用STM32 SPI外设的标准NSS信号线,而是更简单地使用普通的GPIO,软件控制它的电平输出,从而产生通讯起始和停止信号。


通讯过程

控制NSS信号线,产生起始信号;

把要发送的数据写入到“数据寄存器DR”中,该数据会被存储到发送缓冲区;

通讯开始,SCK时钟开始运行。MOSI把发送缓冲区中的 数据一位一位地传输出去;MISO则把数据一位一位地存储进接收缓冲区中;

当发送完一帧数据的时候,“状态寄存器SR”中的“TXE标志位”会被置1,表示传输完一帧,发送缓冲区已空;类似地,当接收完一帧数据的时候,“RXNE标志位”会被置1,表示传输完一帧,接收缓冲区非空;

等待到“TXE标志位”为1时,若还要继续发送数据,则再次往“数据寄存器DR”写入数据即可;等待到“RXNE标志位”为1时,通过读取“数据寄存器DR”可以获取接收缓冲区中的内容。


假如使能了TXE或RXNE中断,TXE或RXNE置1时会产生SPI中断信号,进入同一个中断服务函数,到SPI中断服务程序后,可通过检查寄存器位来了解是哪一个事件,再分别进行处理。也可以使用DMA方式来收发“数据寄存器DR”中的数据。


SPI编程

SPI相关配置库函数

初始化函数

void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);


作用:初始化SPI的相关参数,比如方向(全双工)、主从模式、数据大小、CPOL、CPHA、片选软件模式、预分频系数等。


3个使能函数

void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);

void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState);

void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);


作用:使能SPI接口;使能SPI中断;使能SPI的DMA功能。


2个数据传输函数

void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);

uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);


4个状态位函数

FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);

void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);

ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);

void SPI_I2S_ClearITPendingBit(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);


作用:前两者用于获得和清除SPI的各种状态位;后两者则针对SPI的中断标志位。


SPI一般步骤

实验目标:利用SPI2进行初始化等操作。


配置相关引脚的复用功能,使能SPIx时钟。调用函数:void GPIO_Init();

初始化SPIx,设置SPIx工作模式。调用函数:void SPI_Init();

使能SPIx。调用函数:void SPI_Cmd();

SPI传输数据。调用函数:void SPI_I2S_SendData()uint16_t SPI_I2S_ReceiveData();

查看SPI传输状态。调用函数:SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)。

void SPI2_Init(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  SPI_InitTypeDef  SPI_InitStructure;

 

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能 

RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2,  ENABLE );//SPI2时钟使能

 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB

 

  GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);  //PB13/14/15上拉

 

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工

SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构

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(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

 

SPI_Cmd(SPI2, ENABLE); //使能SPI外设

SPI2_ReadWriteByte(0xff);//启动传输  

 

 

}   

//SPI 速度设置函数

//SpeedSet:

//SPI_BaudRatePrescaler_2   2分频   

//SPI_BaudRatePrescaler_8   8分频   

//SPI_BaudRatePrescaler_16  16分频  

//SPI_BaudRatePrescaler_256 256分频 

  

void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)

{

  assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));

SPI2->CR1&=0XFFC7;

SPI2->CR1|=SPI_BaudRatePrescaler; //设置SPI2速度 

SPI_Cmd(SPI2,ENABLE); 

 

 

//SPIx 读写一个字节

//TxData:要写入的字节

//返回值:读取到的字节

u8 SPI2_ReadWriteByte(u8 TxData)

{

u8 retry=0;

while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位

{

retry++;

if(retry>200)return 0;

}   

SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据

retry=0;

 

while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位

{

retry++;

if(retry>200)return 0;

}       

return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据     

}

关键字:STM32  基础  SPI 引用地址:STM32基础之SPI

上一篇:STM32基础之中断--外部中断
下一篇:STM32基础之IIC

推荐阅读最新更新时间:2024-11-10 10:14

STM32开发笔记19: STM32CubeMX中定时器的配置方法
单片机型号:STM32L053R8T6 本文介绍在STM32CubeMX进行定时器的配置,产生固定时间中断的方法,以TIM2为例,步骤如下: 1、使能TIM2,指定时钟源。 2、查看数据手册,确定该定时器的内部数据总线,本文所引用的定时器内部数据总线为APB1。 3、在时钟配置中确认所选定时器的内部数据总线的时钟频率,我这里是32MHz。 4、在配置页中,选中相应的时钟,在Prescaler中输入预分频系数,在Counter Period中输入溢出系数。例如,本例中时钟为32MHz/32=1MHz,也就是一个周期为1us,我选择溢出系数为1000,则产生中断的时间为1ms。
[单片机]
<font color='red'>STM32</font>开发笔记19: STM32CubeMX中定时器的配置方法
STM32十年超24亿颗+完整生态圈,ST已成为物联网真正受益者
  “物联网”这个概念在中国流行起来已经至少有十几年了,整个产业界也讨论、追逐了很多年。至今,这个概念仍没有出现爆发性的机会和巨头厂商,因此很多人开始怀疑这就是一个“伪”概念。
下面就随嵌入式小编一起来了解一下相关内容吧。   不过,回顾过去几百年的工业历史告诉我们,要真正验证一个历史趋势是否真正存在,可能需要几十上百年的时间。而往往大多数人当真正看到机会那一刻,其实已经为时已晚。最后真正的赢家一般都是,在机会来临之前就已经开始了深度布局。   就在4月25日,知名的国际半导体厂商 意法半导体 (下称ST)在深圳举办的“ STM32 中国峰会”上,笔者第一真正感受到了真正的“物联网”其实已经来临,而且ST 率先布局并成为真正的受
[嵌入式]
STM32程序软件复位
在需要软件复位的地方添加如下两句代码: __set_FAULTMASK(1); //STM32程序软件复位 NVIC_SystemReset();
[单片机]
基于stm32的滤波器的总结
数字滤波器的类型有FIR(有限长冲击与IIR(无限长。 离散数字系统中,滤波器的表述为差分方程。 FIR FIR基本特性: FIR 滤波器永远是稳定的(系统只有零点); FIR 滤波器的冲激响应是有限长序列; FIR 滤波器的系统函数为多项式; FIR 滤波器具有线性相位。 实现同样参数的滤波器,FIR比IIR需要的阶数高,因此计算量大。 目前,FIR 数字滤波器的设计方法主要是建立在对理想滤波器频率特性做某种近似的基础上。设计方法有窗函数法,等波纹设计法(Equiripple)和最小二乘法 (Least-Squares)等。其中窗函数设计法在学校课堂中是重点讲解的,提到FIR滤波器肯定会想到hamming、kaiser窗
[单片机]
STM32:编写XPT2046电阻触摸屏驱动(模拟SPI)
一、环境介绍 单片机采用: STM32F103ZET6 编程软件: keil5 编程语言: C语言 编程风格: 寄存器开发. 目标芯片: XPT2046---标准SPI接口时序 二、XPT2046芯片介绍 2.1 功能 XPT2046是一颗12位的ADC芯片,可以当做普通的ADC芯片使用,但是一般都是用在电阻触摸屏上,方便定位触摸屏坐标。 图1: XPT2046内部原理图 图2:电阻触摸屏---引出的4条线就接在XPT2046的YNXNYPXP上 (XPT2046支持笔中断输出--低电平有效,这个引脚可以配置到单片机的中断脚上,或者轮询判断这个引脚状态,判断触摸屏是否已经按下) 可以单独买一个触摸屏+一个XPT2
[单片机]
<font color='red'>STM32</font>:编写XPT2046电阻触摸屏驱动(模拟<font color='red'>SPI</font>)
纠结的STM32 RTC时钟源LSE
一开始,所有实验都是在神舟板上去完成,根本就没有发现RTC的问题。直到我们自己画板来后调试时,才发现STM32 RTC的外部时钟源存在问题。 这也算是STM32的一个鸡肋,对于LSE外部晶振太过于苛刻,手册上要求使用6pf,这个规格的晶振市场上太少,鱼龙混杂,中招的高手菜鸟不在少数。我们自己的板也是如此,几经波折,反反复复尝试使用不同的规格的晶振,替换外部的电容,电阻都没有能让这个32.768K的LSE起振。但是又需要有RTC来提供时间,考虑的方法主要有2种,第一采用外部RTC时钟芯片,如DS1302。第二是使用内部其它的时钟源来提供RTC时钟。毫无疑问,目前板已经制好,添加时钟芯片肯定造成板上布局更改,还得重新打板,这里采用
[单片机]
STM32:定时器中断与优先级
前言 利用HAL库开发实现功能:使用TIM2实现定时,每隔1秒实现双闪功能 一、基础知识 1、常见的定时器资源 1.系统滴答定时器 SysTick 集成在Cortex M3内核的定时器,主要目的是给RTOS提供时钟节拍做时间基准。比如HAL库函数中的HAL_Delay()就是基于这个定时器开发的。如果要做嵌入式Linux的相关项目,要和上位机进行通讯的话,这个函数就不能用了。 2.看门狗定时器 WatchDog 3.实时时钟 RTC 4.基本定时器 TIM6、TIM7 5.通用定时器 TIM2、TIM3、TIM4、TIM5 在基本定时器的基础上,实现输出比较、输入捕获、PWM生成、单脉冲模式输出等功能。这类定时
[单片机]
<font color='red'>STM32</font>:定时器中断与优先级
IMEC和TEL对7nm工艺半导体布线技术进行基础评价
比利时IMEC分别与东电电子、美国科林研发公司(Lam Research)合作,对7nm工艺以后的逻辑LSI及存储器用布线技术展开研究,并在 IEEE 2015 International Interconnect Technology Conference(IITC) (2015年5月18~21日,法国格勒诺布尔)公布了结果。   图1:使用直接蚀刻制作布线图案的Cu布线的TEM像。Cu布线使用Si氮化膜密封   图2:在钯/钨(Pd/W)底面的28nm直径孔穴(宽高比4.5)中,利用化学镀沉积的Co。左起依次是沉积途中、理想沉积、过度沉积状态   IMEC与东电电子合作开发的,是能够替代广泛普及的铜(Cu)布线的
[半导体设计/制造]
IMEC和TEL对7nm工艺半导体布线技术进行<font color='red'>基础</font>评价
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved