2024年最全STM32 SPI详解(1),2024年最新BATJ等企业物联网嵌入式开发面试知识分享

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

上面的过程转为动画

初始状态

主机读取一个bit过程

总结:

没有读和写的说法,因为实质上每次SPI是主从设备在交换数据。也就是说,你发一个数据必然会收到一个数据;你要收一个数据必须也要先发一个数据。

2.4、SPI传输模式

上升沿、下降沿、前沿、后沿触发。当然也有MSB和LSB传输方式.

3、工作机制

3.1、相关缩写

SPI的极性Polarity和相位Phase,最常见的写法是CPOL和CPHA,不过也有一些其他写法,简单总结如下:

(1) CKPOL (Clock Polarity) = CPOL = POL = Polarity = (时钟)极性

(2) CKPHA (Clock Phase) = CPHA = PHA = Phase = (时钟)相位

(3) SCK=SCLK=SPI的时钟

(4) Edge=边沿,即时钟电平变化的时刻,即上升沿(rising edge)或者下降沿(falling edge)

对于一个时钟周期内,有两个edge,分别称为:

Leading edge=前一个边沿=第一个边沿,对于开始电压是1,那么就是1变成0的时候,对于开始电压是0,那么就是0变成1的时候;

Trailing edge=后一个边沿=第二个边沿,对于开始电压是1,那么就是0变成1的时候(即在第一次1变成0之后,才可能有后面的0变成1),对于开始电压是0,那么就是1变成0的时候;

3.2、CPOL极性

先说什么是SCLK时钟的空闲时刻,其就是当SCLK在数发送8个bit比特数据之前和之后的状态,于此对应的,SCLK在发送数据的时候,就是正常的工作的时候,有效active的时刻了。

先说英文,其精简解释为:Clock Polarity = IDLE state of SCK。

再用中文详解:

SPI的CPOL,表示当SCLK空闲idle的时候,其电平的值是低电平0还是高电平1:

CPOL=0,时钟空闲idle时候的电平是低电平,所以当SCLK有效的时候,就是高电平,就是所谓的active-high;

CPOL=1,时钟空闲idle时候的电平是高电平,所以当SCLK有效的时候,就是低电平,就是所谓的active-low;

3.3、CPHA相位

首先说明一点,capture strobe = latch = read = sample,都是表示数据采样,数据有效的时刻。相位,对应着数据采样是在第几个边沿(edge),是第一个边沿还是第二个边沿,0对应着第一个边沿,1对应着第二个边沿。

对于:

CPHA=0,表示第一个边沿:

对于CPOL=0,idle时候的是低电平,第一个边沿就是从低变到高,所以是上升沿;

对于CPOL=1,idle时候的是高电平,第一个边沿就是从高变到低,所以是下降沿;

CPHA=1,表示第二个边沿:

对于CPOL=0,idle时候的是低电平,第二个边沿就是从高变到低,所以是下降沿;

3.4、极性和相位图示

图例1

图例2

3.5 、软件设置极性和相位

SPI分主设备和从设备,两者通过SPI协议通讯。

而设置SPI的模式,是从设备的模式,决定了主设备的模式。

所以要先去搞懂从设备的SPI是何种模式,然后再将主设备的SPI的模式,设置和从设备相同的模式,即可正常通讯。

对于从设备的SPI是什么模式,有两种:

1.固定的,有SPI从设备硬件决定的

SPI从设备,具体是什么模式,相关的datasheet中会有描述,需要自己去datasheet中找到相关的描述,即:

关于SPI从设备,在空闲的时候,是高电平还是低电平,即决定了CPOL是0还是1;

然后再找到关于设备是在上升沿还是下降沿去采样数据,这样就是,在定了CPOL的值的前提下,对应着可以推算出CPHA是0还是1了。

2.可配置的,由软件自己设定

从设备也是一个SPI控制器,4种模式都支持,此时只要自己设置为某种模式即可。

然后知道了从设备的模式后,再去将SPI主设备的模式,设置为和从设备模式一样,即可。

对于如何配置SPI的CPOL和CPHA的话,不多细说,多数都是直接去写对应的SPI控制器中对应寄存器中的CPOL和CPHA那两位,写0或写1即可。

4、STM32的SPI控制模块

SPI是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32也有SPI接口。

SPI接口一般使用4条线通信:

MISO  主设备数据输入,从设备数据输出。

MOSI  主设备数据输出,从设备数据输入。

SCLK  时钟信号,由主设备产生。

CS  从设备片选信号,由主设备控制。

SPI主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。

STM32的SPI功能很强大,SPI时钟最多可以到18Mhz,支持DMA,可以配置为SPI协议或者I2S协议

关于SPI,从数据手册查到

STM32F207VCT6共有3个SPI。

从下表查出每个SPI对应的管脚

STM32标准外设库SPI_InitTypeDef的定义


typedef struct
{
    uint16_t SPI_Direction; // 设置SPI 的通信方式,可以选择为半双工,全双工,以及串行发和串行收方式
   uint16_t SPI_Mode; // 设置SPI 的主从模式
   uint16_t SPI_DataSize; // 为8 位还是16 位帧格式选择项
   uint16_t SPI_CPOL; // 设置时钟极性
   uint16_t SPI_CPHA; // 设置时钟相位
   uint16_t SPI_NSS;   //设置NSS 信号由硬件(NSS管脚)还是软件控制
   uint16_t SPI_BaudRatePrescaler;  //设置SPI 波特率预分频值
   uint16_t SPI_FirstBit;    //设置数据传输顺序是MSB 位在前还是LSB 位在前
   uint16_t SPI_CRCPolynomial; //设置CRC 校验多项式,提高通信可靠性,大于1 即可
}SPI_InitTypeDef;

第一个参数SPI_Direction 是用来设置SPI的通信方式,可以选择为半双工,全双工,以及串行发和串行收方式,这里我们选择全双工模式SPI_Direction_2Lines_FullDuplex。

第二个参数SPI_Mode用来设置SPI的主从模式,这里我们设置为主机模式 SPI_Mode_Master,当然有需要你也可以选择为从机模式 SPI_Mode_Slave。

第三个参数SPI_DataSiz为8位还是16位帧格式选择项,这里我们是8位传输,选择SPI_DataSize_8b。

第四个参数SPI_CPOL用来设置时钟极性,我们设置串行同步时钟的空闲状态为高电平所以我们选择SPI_CPOL_High。

第五个参数SPI_CPHA 用来设置时钟相位,也就是选择在串行同步时钟的第几个跳变沿(上升或下降)数据被采样,可以为第一个或者第二个条边沿采集,这里我们选择第二个跳变沿,所以选择 SPI_CPHA_2Edge

第六个参数SPI_NSS设置NSS信号由硬件(NSS管脚)还是软件控制,这里我们通过软件控制NSS关键,而不是硬件自动控制,所以选择 SPI_NSS_Soft。

第七个参数 SPI_BaudRatePrescaler很关键,就是设置 SPI 波特率预分频值也就是决定 SPI 的时钟的参数,从不分频道256分频8个可选值,初始化的时候我们选择256分频值SPI_BaudRatePrescaler_256,传输速度为36M/256=140.625KHz。

第八个参数 SPI_FirstBit设置数据传输顺序是 MSB 位在前还是LSB位在前,这里我们选择SPI_FirstBit_MSB高位在前。

第九个参数 SPI_CRCPolynomial是用来设置CRC校验多项式,提高通信可靠性,大于1即可。

示例代码:

void  SPIInit( void )
{
    SPI_InitTypeDef SPI_InitStructure;
    FLASH_GPIO_Init();
    /*!< Deselect the FLASH: Chip Select high */
    GPIO_SetBits( GPIOA, GPIO_Pin_4 );
    /*!< SPI configuration */
    SPI_InitStructure.SPI_Direction     = SPI_Direction_2Lines_FullDuplex;      /* 双线双向全双工 */
    SPI_InitStructure.SPI_Mode      = SPI_Mode_Master;                      /* 主 SPI */
    SPI_InitStructure.SPI_DataSize      = SPI_DataSize_8b;                      /* SPI 发送接收 8 位帧结构 */
    SPI_InitStructure.SPI_CPOL      = SPI_CPOL_High;                        /* 串行同步时钟的空闲状态为高电平 */
    SPI_InitStructure.SPI_CPHA      = SPI_CPHA_2Edge;                       /* 第二个跳变沿数据被采样 */
    SPI_InitStructure.SPI_NSS       = SPI_NSS_Soft;                         /* NSS 信号由软件控制 */
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;             /* 预分频 16 */
 
    SPI_InitStructure.SPI_FirstBit      = SPI_FirstBit_MSB;                     /* 数据传输从 MSB 位开始 */
    SPI_InitStructure.SPI_CRCPolynomial = 7;                                    /* CRC 值计算的多项式 */
    SPI_Init( SPI1, &SPI_InitStructure );
    /*!< Enable the sFLASH_SPI  */
    SPI_Cmd( SPI1, ENABLE );
}

看到这里,可能觉的前面讲原理并没有太大的用处,因为STM32集成了SPI控制器,配置一下即可。

一方面我们学习原理是为了更好的理解SPI,用于对接不同的SPI设备,像norflash的spi驱动网上有大量的例子,不容易出错。但并不是特别常见的,spi驱动SD卡,SPI驱动网络PHY,SPI驱动ESP8266,甚至在设计两个IC通信时,由于没有过多GPIO,又觉的IIC通信速度慢的话,可以设计两个IC之间使用SPI通信,显然这些场景就需要了解SPI的原理

另外一方面,实际应用中,有可能因为芯片其他管脚用于特殊功能,留下的管脚没有硬件SPI功能,只能模拟实现,这个时候学习SPI原理就很有必要了。

5、SPI的应用

SPI的常用应用NorFlash

从数据手册上看到,SPI传输:CKPOL=1 , CKPHA=1

所以STM32的SPI读取NorFlash的配置如下

抓取下面代码波形

抓取的波形如下

0100 1011 就是0X4B

其中看到:

起始电平是高电平,也就是CKPOL=1

第二个边沿采样,也就是CKPHA=1

其实说成类似IIC的高电平有效也是没有问题的

下面这句话是写模拟SPI的核心

自己的理解:在下降沿转换数据,在上升沿采样数据

除了抓取波形,在华邦Flash也看到了时序图

6、code

读取norflash

使用STM32F207硬件SPI模块

/**
  * @brief  Initializes the peripherals used by the SPI FLASH driver.
  * @param  None
  * @retval None
  */
void FLASH_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  
  /*!< Enable the SPI clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
  
  /*!< Enable GPIO clocks */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); 
  /*!< SPI pins configuration *************************************************/
  
  /*!< Connect SPI pins to AF5 */  
  GPIO_PinAFConfig(GPIOA, 5, GPIO_AF_SPI1);
  GPIO_PinAFConfig(GPIOA, 6, GPIO_AF_SPI1);
  GPIO_PinAFConfig(GPIOB, 5, GPIO_AF_SPI1);
  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;//GPIO_PuPd_DOWN;
  
  /*!< SPI SCK pin configuration */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  /*!< SPI MISO pin configuration */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  /*!< SPI MOSI pin configuration */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_5;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
  /*!< Configure sFLASH Card CS pin in output pushpull mode */


![img](https://img-blog.csdnimg.cn/img_convert/5b305728cab992a3ea651a4ae4c76a07.png)
![img](https://img-blog.csdnimg.cn/img_convert/44980b1383d235d9146e82be23763de9.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

 =  GPIO_Pin_5;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
  /*!< Configure sFLASH Card CS pin in output pushpull mode */


[外链图片转存中...(img-sLM9pC0n-1715633433247)]
[外链图片转存中...(img-65njKcLG-1715633433248)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

  • 22
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值