首先介绍下GD32 105R的SPI脚位分布
脚位 |
类型 |
名称 |
默认功能 |
20 |
I/O |
PA4 |
SPI1_NSS(8)/ USART2_CK(8) DAC_OUT1/ADC12_IN4 |
21 |
I/O |
PA5 |
SPI1_SCK(8) DAC_OUT2 ADC12_IN5 |
22 |
I/O |
PA6 |
SPI1_MISO(8) TIM8_BKIN/ADC12_IN6 TIM3_CH1(8) |
23 |
I/O |
PA7 |
SPI1_MOSI(8)/ TIM8_CH1N/ADC12_IN7 TIM3_CH2(8) |
33 |
I/O |
PB12 |
SPI2_NSS/I2S2_WS/ I2C2_SMBA/ USART3_CK(8)/ TIM1_BKIN(8) |
34 |
I/O |
PB13 |
SPI2_SCK/I2S2_CK USART3_CTS(8)/ TIM1_CH1N |
35 |
I/O |
PB14 |
SPI2_MISO/TIM1_CH2N USART3_RTS(8)/ |
36 |
I/O |
PB15 |
SPI2_MOSI/I2S2_SD TIM1_CH3N(8)/ |
50 |
I/O |
JTDI |
SPI3_NSS/ I2S3_WS |
55 |
I/O |
JTDO |
SPI3_SCK / I2S3_CK/ |
56 |
I/O |
NJTRST |
SPI3_MISO |
57 |
I/O |
PB5 |
I2C1_SMBA/ SPI3_MOSI I2S3_SD |
SPI,是一种高速的,全双工,同步的通信总线,接口简单,利于硬件设计与实现。采用主从模式架构,支持多从设备应用。时钟速度快,目前应用中的数据速率可达几Mbps,且没有系统开销。相对抗干扰能力强,传输稳定,正是出于这种简单易用的特性,GD32 105R_STAR芯片也集成了这种通信协议。
1、SPI在一般应用中有4根信号线:
MOSI:主器件数据输出,从器件数据输入。
MISO:主器件数据输入,从器件数据输出。
SCK: 时钟信号,由主设备控制发出。
/SS: 从设备选择信号,由主设备控制。 根据此信号可以决定能连接到总线上从设备的数量。
2、根据时钟极性(CPOL)及相位(CPHA)不同可以组合成4种工作模式:
SPI0:CPOL=0,CPHA=0
SPI1:CPOL=0,CPHA=1
SPI2:CPOL=1,CPHA=0
SPI3:CPOL=1,CPHA=1
根据不同外设模块的需求,来对GD32 105R_STAR的SPI外设进行不同的匹配设置,楼主根据PT6315的外设需求,进行如下初始化配置:
/* **************************************************************************** *函数名称:void Pt_SPIInit(void) *函数功能:PT6315 SPI 总线初始化 *日期:2015 4 6 *版本:V1.0 *作者:yrj *SPI_FirstBit_MSB;//高位在前 PT6315手册对应改为低位在前。 **************************************************************************** */ // PB12/SPI2NSS PB13/SPI2CLK PB14/SPI2MISO PTOUT PB15/SPI2MOSI PTIN void Pt_SPIInit(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; //PB14 (MISO)浮空输入 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB,&GPIO_InitStructure); //PB15 MOSI PB13 SCK 复用推挽输出(外设总线用) GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); //PB12 NSS,PB11 WP写保护普通推挽输出 本实验用软件控制NSS(主从设备的选择控制端) GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); Pt_Disable(); //PB12/NSS 失能 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
SPI_InitTypeDef SPI_InitStructure; SPI_I2S_DeInit(SPI2); SPI_Cmd(SPI2,DISABLE);//在改变CPOL/CPHA位之前必须清除SPE位将SPI禁止 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主模式 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//时钟悬空低 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//数据捕获与第1个时钟沿 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//软件控制NSS信号 SPI_InitStructure.SPI_BaudRatePrescaler =SPI_BaudRatePrescaler_8;//比特率预分频值为8。最大18MHz SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB; /*SPI_FirstBit_MSB; //高位在前 7 7 与PT6315手册对应改为低位在前。*/ SPI_InitStructure.SPI_CRCPolynomial = 7;//定义用于CRC值计算的多项式 7 SPI_Init(SPI2, &SPI_InitStructure); SPI_Cmd(SPI2,ENABLE); }
此外由于SPI是一种全双工的同步通信总线,所以在进行数据通信中收发是同步进行的,为了在实际的函数调用中简单明了,针对GD32 105R_STAR SPI数据的收发,楼主在此分别设计了两个函数来进行数据的发送和接收。
SPI发送函数:
/* **************************************************************************** *函数名称:uint8 Send_Byte(void) *函数功能:通过硬件SPI发送一个字节 *日期:2015 4 6 *版本:V1.0 *作者:yrj **************************************************************************** */ uint32 CsyCnt; void SendPt_Byte(uint8 data) { SPI_I2S_SendData(SPI2, data);//发送数据 CsyCnt = 0; while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET) //等待数据发送完毕 { CsyCnt++; if(CsyCnt>10000) break ; } SPI_I2S_ClearFlag(SPI2,SPI_I2S_FLAG_TXE); //清除发送完成 //////////// 测试是否正常写入 if( CsyCnt >10000) // 有故障 { /*重新初始化*/ Pt_SPIInit(); /*重新发送数据*/ SPI_I2S_SendData(SPI2, data);/*发送数据*/ while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET); /*等待数据发送完毕*/ } while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)==RESET); /*等待数据发接收完毕*/ SPI_I2S_ReceiveData(SPI2); /*接收返回的数据,在此无实意*/ }SPI接收函数:/* **************************************************************************** *函数名称:uint8 Get_Byte(void) *函数功能:通过硬件SPI接口接收一个字节到处理器 *日期:2015 4 6 *版本:V1.0 *作者:yrj **************************************************************************** */ uint8 GetPt_Byte(void) { while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET); /*等待数据发送完毕*/ SPI_I2S_SendData(SPI2, 0);/*发送该数据易产生时钟,数据本身无意义。*/ while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)==RESET);/*等待接收完成*/ return SPI_I2S_ReceiveData(SPI2);/*返回最近接收到的数据*/ }