STM32与GD32的SPI通信对比与解析

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

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

     

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

    作者:_蒙娜丽嘎_

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32与GD32的SPI通信对比与解析

    发表回复