既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
关于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 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void FLASH_SPIInit(void)
{
SPI_InitTypeDef SPI_InitStructure;
FLASH_GPIO_Init();
/*!< Deselect the FLASH: Chip Select high */
GPIO_SetBits(GPIOE,GPIO_Pin_12);
/*!< 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);
}
软件模拟SPI协议
/**
* @brief Sends a byte through the SPI interface and return the byte received
* from the SPI bus.
* @param byte: byte to send.
* @retval The value of the received byte.
*/
uint8_t SPI_ReadWriteByte(uint8_t data)
{
uint8_t i,data_read = 0;
if(data!=0xA5){
for(i=0;i<8;i++){
MSPI_CLK_L();
if(data&0x80){
MSPI_MOSI_H();
}else{
MSPI_MOSI_L();
}
MSPI_DELAY();
data = data<<1;
MSPI_CLK_H();
MSPI_DELAY();
}
return data_read;
}else{
for(i=0;i<8;i++){
MSPI_CLK_L();
MSPI_DELAY();
data_read = data_read<<1;
MSPI_CLK_H();
if(MSPI_READ_IN()){
data_read |= 0x01;
}
MSPI_DELAY();
}
return data_read;
}
}
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void FLASH_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*!< Enable GPIO clocks */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
/*!< Configure sFLASH Card CS pin in output pushpull mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/*!< SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOA, &GPIO_InitStructure);
MSPI_CLK_H();
/*!< SPI MOSI pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOB, &GPIO_InitStructure);
MSPI_MOSI_H();
/*!< SPI MISO pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void FLASH_SPIInit(void)
{
FLASH_GPIO_Init();
/*!< Deselect the FLASH: Chip Select high */
GPIO_SetBits(GPIOE,GPIO_Pin_12);
}
开源地址:
https://github.com/strongercjd/STM32F207VCT6
点击查看本文所在的专辑,STM32F207教程
关注公众号,第一时间收到文章更新。评论区不能及时看到,需要交流可以到公众号沟通
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
/bbs.csdn.net/topics/618679757)**
关注公众号,第一时间收到文章更新。评论区不能及时看到,需要交流可以到公众号沟通
[外链图片转存中…(img-c7KJMxk3-1715907204806)]
[外链图片转存中…(img-T1TdnydG-1715907204806)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)