活动发起人@小虚竹 想对你说:

这是一个以写作博客为目的的创作活动,旨在鼓励大学生博主们挖掘自己的创作潜能,展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴,那么,快来参加吧!我们一起发掘写作的魅力,书写出属于我们的故事。我们诚挚邀请你参加为期14天的创作挑战赛!

提醒:在发布作品前,请将不需要的内容删除。

目录

一.SPI通信的特点

SPI是全双工,同步,串行通讯

二.SPI协议

1. SPI物理层(物理层负责数据的物理传输)

2. SPI协议层(协议层负责数据传输的规则和标准)

STM32的采样

GD32采样

三.SPI结构框图

STM32外设结构:

GD32结构:

四.使用注意事项

 五.软件配置

配置时钟

GPIO引脚配置

SPI外设配置

主函数引用


一.SPI通信的特点

SPI是全双工,同步,串行通讯

  • 全双工:同时收发数据(半双工是分时收发数据)
  • 同步:多任务全部执行完成才结束(异步为可以同时执行完成多个任务,不需要等待其他任务结束)
  • 串行:对于一个字节数据,分八次由低位到高位一次一次传输(对于异步,同样一个字节,可以由多条数据线一次传输)

串行和并行通常在选择上,企业应用更偏向串行。并行在传输速度上更快,但是多个数据线在传输上会造成干扰,影响数据准确性,而串行只有一个数据线,可以保证数据传输准确,现在串行在传输速度上已经发展成为高速串行,更为符合实际用途,所以现在串行更为普遍,SPI广泛应用在ADC,LCD等设备与MCU之间。

二.SPI协议

1. SPI物理层(物理层负责数据的物理传输)

SPI接口采用主从模式架构:支持一主一从和一主多从模式,但是不支持多主模式。

STM32和GD32在SPI物理层上一致,图1为STM32的SPI架构,图2为GD32的SPI架构

图1:

图2:

  • SCK/SCLK:时钟信号,由主机产生并控制
  • MOSI:Master output Slave input,主数据输出,从数据输入
  • MISO:主数据输入,从数据输出
  • SS/NSS:从机片选使能信号,主机SPI通讯

2. SPI协议层(协议层负责数据传输的规则和标准)

SPI协议定义通讯的起始和停止信号,数据有效性,时钟同步

  • 起始和停止信号:NSS/SS置低开始,置高结束,除此之外,拉低片选哪个从机通信。
  • 数据有效性:在NSS拉低之后,在SCK的上升沿时MISO和MOSI进行数据准备, SCK的下降沿时读取MISO和MOSI上的数据。在NSS为高时,MISO和MOSI上的数据无效。
  • 时钟同步:需要SCK时钟信号严格同步。
STM32的采样

(奇数/偶数边沿采集配置)(见下图)

CPHA=0,奇数边沿采样

CPHA=1,偶数边沿采样

GD32采样

CKPH=0,奇数边沿采样

CKPH=1,偶数边沿采样

三.SPI结构框图

STM32外设结构:

GD32结构:

四.使用注意事项

(1) 在切换SPI时钟前要关闭SPI,切换完成后再使能SPI。
(2) 在采用SPI发送数据时,发送buf空标志TBE置位,并不代表数教据发送完成,仅代表数据从发
送数据寄存器移到发送移位寄存器中,如果通过查询TBE标志来拉高CS片选,由于GD32系列MCU代码执行效率较高,当发送速率较低时可能会出现当TBE置位时,拉高CS片选,此时数据还未完成发送,造成从机接受数据出错。可以通过查询接收数据寄存器非空RBNE和TRANS标志位来判断数据发送完成,然后再拉高CS片选。
(3) SPI的MISO管脚需配置为浮空输入模式,否则有可能数据按收异常

 

 五.软件配置

配置步骤:

1.配置时钟 

   STM32: RCC_APBxPeriphClockCmd

   GD32:   RCU_periph_clock_enable  

2.GPIO引脚配置

STM32:

#define FLASH_SPIx                      SPI1
#define FLASH_SPI_APBxClock_FUN         RCC_APB2PeriphClockCmd
#define FLASH_SPI_CLK                   RCC_APB2Periph_SPI1

//CS(NSS) 
#define FLASH_SPI_CS_APBxClock_FUN      RCC_APB2PeriphClockCmd
#define FLASH_SPI_CS_CLK                RCC_APB2Periph_GPIOB
#define FLASH_SPI_CS_PORT               GPIOB
#define FLASH_SPI_CS_PIN                GPIO_Pin_6

//SCK 
#define FLASH_SPI_SCK_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define FLASH_SPI_SCK_CLK               RCC_APB2Periph_GPIOA
#define FLASH_SPI_SCK_PORT              GPIOA
#define FLASH_SPI_SCK_PIN               GPIO_Pin_5

//MOSI 
#define FLASH_SPI_MOSI_APBxClock_FUN    RCC_APB2PeriphClockCmd
#define FLASH_SPI_MOSI_CLK              RCC_APB2Periph_GPIOA
#define FLASH_SPI_MOSI_PORT             GPIOA
#define FLASH_SPI_MOSI_PIN              GPIO_Pin_7

#define FLASH_SPI_CS_LOW() GPIO_ResetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
#define FLASH_SPI_CS_HIGH() GPIO_SetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )

#define Dummy_Byte 0xFF

void SPI_FLASH_Init(void)
{
 SPI_InitTypeDef SPI_InitStructure;
 GPIO_InitTypeDef GPIO_InitStructure;
 
 FLASH_SPI_APBxClock_FUN ( FLASH_SPI_CLK, ENABLE );

 FLASH_SPI_CS_APBxClock_FUN ( FLASH_SPI_CS_CLK|FLASH_SPI_SCK_CLK|FLASH_SPI_MOSI_PIN, ENABLE );
 

 GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
 GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);
 
 /*  SCK */
 GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);
 /* MISO */
// GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
// GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);
 
 /* MOSI  */
 GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
 GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);
 
 /*CS */
 FLASH_SPI_CS_HIGH();

GD32:

void gpio_config(void)
{
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
/* SPI0 GPIO config:SCK/PA5, MISO/PA6, MOSI/PA7 */
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
/* PA3 as NSS */
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X
#if defined GD32F1X0 || GD32F3X0 || GD32E23X
/* SPI0 GPIO config: SCK/PA5, MISO/PA6, MOSI/PA7 */
gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
#elif defined GD32F4XX
gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
#endif
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
#endif
SET_SPI0_NSS_HIGH
}

3.SPI外设配置

STM32:

SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
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_2;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(FLASH_SPIx, &SPI_InitStructure);

/* SPI */
SPI_Cmd(FLASH_SPIx, ENABLE);

GD32:

4.主函数引用

 

个人整理如上,如有补充,问题,还请指出

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐