GD32F350.SPI软件片选模式

在开始使用GD32F350G8的硬件SPI时对于NSS功能下的主从模式有点迷惑,
需求为主机模式下对从机发送数据,片选线低有效
手册上说If the application wants to use NSS line to control the SPI slave, NSS should be configured to hardware output mode (SWNSSEN=0, NSSDRV=1). NSS goes low after SPI is enabled.
这里的问题是在开启NSS硬件输出模式后,使能SPI,NSS引脚是一直低的状态,不能满足需求,但也说到可以选择通用IO来作为片选线:
The application may also use a general purpose IO as NSS pin to realize more flexible NSS.
疑惑点在于我的SPI控制线是采用对应硬件SPI的IO口,
后面发现可以不配置NSS片选线,直接控制NSS电平状态

void SPI1_PortInit(void)
{
	spi_parameter_struct spi_init_struct;
	
	rcu_periph_clock_enable(RCU_SPI0);
	rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_GPIOB);
	
	gpio_af_set(GPIOB,GPIO_AF_0,GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);							//sck, MISO, MOSI													
	
	gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_15);						//nss						
	gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);	//sck, MISO, MOSI					   

	gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_15);				//nss					
	gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5); 		//sck, MISO, MOSI
	
	GPIO_BOP(GPIOA) = (uint32_t)GPIO_PIN_15;							 //set High
	spi_i2s_deinit(SPI0);
	/* configure SPI0 parameter */
	spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;	 //全双工							
	spi_init_struct.device_mode          = SPI_MASTER;					 //主机模式							
	spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;		  	 //8bit									
	spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;								
	spi_init_struct.nss                  = SPI_NSS_SOFT;				//软件触发									
	spi_init_struct.prescale             = SPI_PSC_8;
	spi_init_struct.endian               = SPI_ENDIAN_MSB;
	
	
	spi_init(SPI0, &spi_init_struct);
	spi_enable(SPI0);
}

最开始我是直接这样操作:

void SPI1_Hardw_SendData(uint8_t  Addr,uint8_t  Regdata,uint32_t TimeOut)
{
	GPIO_BC(GPIOA) = (uint32_t)GPIO_PIN_15;
		while( RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE) )
	{
		if(TimeOut > 0) TimeOut--; 
		else 				break;			
	}
	
	Addr = Addr | 0x80;                         	//地址高位置1,表示写寄存器
	
	spi_i2s_data_transmit(SPI0,Addr);
	while( RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE) )
	{
		if(TimeOut > 0) TimeOut--; 
		else 				break;			
	}
	spi_i2s_data_transmit(SPI0,Regdata);
	GPIO_BOP(GPIOA) = (uint32_t)GPIO_PIN_15;
}

出来的波形错误,片选线被提前拉高,个人见解是数据在放入SPI_DATA寄存器后,SPI硬件自行去执行发数与时钟跳变这一些动作,而在程序上,数据存入SPI_DATA寄存器,就去执行片选线拉高动作,导致时序不正确,当时忘了记录现象;增加延时改进后就ok了

void SPI1_Hardw_SendData(uint8_t  Addr,uint8_t  Regdata,uint32_t TimeOut)
{
	GPIO_BC(GPIOA) = (uint32_t)GPIO_PIN_15;
	while( RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE) )
	{
		if(TimeOut > 0) TimeOut--; 
		else 				break;			
	}
	
	Addr = Addr | 0x80;                         	//地址高位置1,表示写寄存器
	spi_i2s_data_transmit(SPI0,Addr);
	while( RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE) )
	{
		if(TimeOut > 0) TimeOut--; 
		else 				break;			
	}
	spi_i2s_data_transmit(SPI0,Regdata);
	delay_1us(2);									//延时等待SPI发送完成
	GPIO_BOP(GPIOA) = (uint32_t)GPIO_PIN_15;

}

这里延时可以改进为判断SPI发送缓冲区空标志位(TBE)的状态来等待发送完成,发送缓冲区为空时, TBE置位。 通过写SPI_DATA寄存器将下一个待发送数据写入发送缓冲区来清除TBE置位。
当发送数据较多时,就可以引入SPI+DMA的方式来发送数据,为CPU减轻工作负担,去做其他事情。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mapoplus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值