基于GD32A503x的SPI通信

一、简介:

GD32A503:GD32A503是一个高性能的微控制器,属于GD32系列产品线。它包含多种通信接口,其中包括SPI(Serial Peripheral Interface)。SPI是一种高速的、全双工的、同步的通信协议,常用于微控制器与外围设备间的数据传输。

SPI通信:SPI (Serial Peripheral Interface) 是一个同步串行接口协议,SPI主要被用于微控制器和其外围设备之间的通信,如存储器、传感器、ADCs等。是一主多从的全双工通信,由主设备的SCK提供时钟信号来同步通信,SPI的速度比其他的一般通信更快,其模式有四种模式,协议相对简单,无错误检测。
二、实例验证:

1、连线:本文用的是GD32A503RDT3的单片机作为主机,从机也为GD32A503RDT3进行SPI通信,通过SPI0让两台设备进行通信。首先先看到GD32A503RDT3的用户手册.

图中我们可以看到四线引脚的描述,弄懂四线引脚描述后,我们通过查看GD32A503RDT3的datasheet可以知道其对应的引脚为PE14(spi0 slk),PA2(spi0 mosi),PE13(spi0 miso),PA1(spi0 nss)。我们确认四个引脚连接无误(MOSI接MOSI,MISO接MISO切记不要接反了)。

2、主机配置:主机SPI配置部分SCK MOSI NSS如下代码进行初始化。

    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOE);	


    
    gpio_af_set(GPIOA, GPIO_AF_4, GPIO_PIN_2);//PA2 SPI0_MOSI 
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);



    gpio_af_set(GPIOE, GPIO_AF_4, GPIO_PIN_13  );// PE13MISO
    gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13  );
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13  );
	
    gpio_af_set(GPIOE, GPIO_AF_4, GPIO_PIN_14 );// PE14SCK
    gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14 );
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14 );

    gpio_mode_set	(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_1);//PA1 NSS
    gpio_output_options_set (GPIOA, GPIO_OTYPE_PP   , GPIO_OSPEED_50MHZ , GPIO_PIN_1);

将其引脚配置好后,对主机的SPI进行初始化配置。

#define  SPI0_CS_LOW()        gpio_bit_reset(GPIOA, GPIO_PIN_1)
#define  SPI0_CS_HIGH()       gpio_bit_set(GPIOA, GPIO_PIN_1)

    spi_parameter_struct spi0_init_struct;
    rcu_periph_clock_enable(RCU_SPI0);
    SPI0_CS_HIGH() ;	
	
	spi0_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi0_init_struct.device_mode          = SPI_MASTER;
    spi0_init_struct.frame_size           = SPI_FRAMESIZE_16BIT;
    spi0_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi0_init_struct.nss                  = SPI_NSS_SOFT;
    spi0_init_struct.prescale             = SPI_PSC_128;
    spi0_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi0_init_struct);
		
	spi_enable(SPI0);    

进行初始化前先把片选CS拉高。
为什么要这么做有几个原因:

  1. 防止误操作:在设置或初始化SPI接口时,可能会在SPI总线上产生一些噪音或未定义的状态。如果CS被拉低,从设备可能会误解这些噪音为有效的通信,从而导致不可预知的行为。

  2. 明确的状态:将CS拉高是明确告诉从设备,主设备当前不希望与其通信。这为SPI的初始化或配置提供了一个明确、确定的状态。

  3. 从设备复位:某些从设备可能在CS从低到高的转换时进行内部复位或重新同步。因此,在初始化开始时先将CS拉高可以确保从设备处于一个已知的、良好的初始状态。
     

3、从机配置:从机SPI配置部分SCK MOSI NSS如下代码进行初始化。

    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOE);    
    
    gpio_af_set(GPIOA, GPIO_AF_4, GPIO_PIN_2);//PA2 SPI0_MOSI 
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);

    gpio_af_set(GPIOE, GPIO_AF_4, GPIO_PIN_13  );// PE13MISO
    gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13  );
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13  );
	
    gpio_af_set(GPIOE, GPIO_AF_4, GPIO_PIN_14 );// PE14SCK
    gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14 );


    gpio_mode_set	(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_1);//PA1 NSS

从机仅有MISO需要设置为输出模式,其他三条线都是从主机接收。参考主机一样也初始化从机的SPI0

    spi_parameter_struct spi0_init_struct;
    rcu_periph_clock_enable(RCU_SPI0);
    
    SPI0_CS_HIGH() ;	
	
	spi0_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi0_init_struct.device_mode          = SPI_SLAVE;
    spi0_init_struct.frame_size           = SPI_FRAMESIZE_16BIT;
    spi0_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi0_init_struct.nss                  = SPI_NSS_SOFT;
    spi0_init_struct.prescale             = SPI_PSC_128;
    spi0_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi0_init_struct);
		
	spi_i2s_interrupt_enable(SPI0, SPI_I2S_INT_RBNE);
	nvic_irq_enable(SPI0_IRQn, 1, 0);

	spi_enable(SPI0);

需要注意的是device_mode主机配置为MASTER,从机为SLAVE。其他跟主机保持一致即可。clock_polarity_phase的设置关乎到数据最终的采样,两者必须要保持一致。同样frame_size一致可以确保两者通信时不会发生数据的丢失(同为8BIT或16BIT).endian是选择先发哪个方向的位数据,MSB(Most Significant Bit)传输最重要的位,LSB(Least Significant Bit)传输最不重要位。一般都设置位MSB,确保最重要位能够先发送。因为从机要确定接收信息的时机,所以要采用中断,这里中断nvic代码一并给出。

4、通信代码:配置完后,在主机程序写入通信代码。

uint16_t SPI_send_receive(uint16_t send_data)
{ 
	uint16_t receive_data = 0;
	SPI0_CS_LOW() ;	//拉低CS片选引脚,开始通信。
	while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));//发送缓冲区为RESET,可以发送。
	spi_i2s_data_transmit(SPI0,send_data);//发送数据send_data
	while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));//判断接收缓冲区
	receive_data =spi_i2s_data_receive(SPI0);//接收数据 给到receive_data
	SPI0_CS_HIGH() ;//拉高CS片选引脚,结束通信。
    return receive_data ;
}

在从机程序写入中断服务程序。

void SPI0_IRQHandler(void) 
{   
  
    if (spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)==SET)//从机判断接收缓冲区为set 触发中断 接收数据
    {
    	received_data = spi_i2s_data_receive(SPI0);//接收数据存入received_data。 
		send_data=~received_data;//处理你的send_data,这里将接收数据取反发送。
        
        while (RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));//判断发送缓冲区状态,发送数据。
        spi_i2s_data_transmit(SPI0, send_data);
    }
}

写好后,将两者在各自的主函数里初始化GPIO口和SPI0,就可以进行通信了。这里举例主机发送的数据为0x8F00(1000111100000000),从机接收后返回值为0x70FF,设计完成。

5、验证图形:将程序下载到主机与从机中,这次我们用到示波器来检测四条线的波形,看看四条线的波形是否与我们预期的波形相匹配。从机程序进行debug,看看能否正常进入中断,data数据是否正常。如图示是正常的。

接下来看看四条线的波形。MOSI为CH1(黄),CLK为CH2(蓝),CS为CH3(粉),MISO为CH4(紫)。

MOSI和MISO,可以看到两个数据是取反的,是正常准确的。

片选和时钟,可以看到CS拉低后 时钟一共16个时钟波形,对应配置的16bit。也是正常的。

最终波形,可以证明我们SPI通信成功了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值