GD32F103配置SPI+DMA收发数据

  GD32是国产的32位单片机,它和STM32非常非常像,就连以前的库函数都差不多(现在从GD官网下载的库函数换了一种风格)。配置SPI和DMA的方法和STM32差不多。

DMA0各通道请求表  上图是DMA0各通道请求表,SPI0的收发分别用了通道1和通道2,我们就配置SPI0。

配置SPI0(或者说SPI1,GD的命名顺序让人闹心)

#define SPI1_CS_HIGH() (GPIOA->BOR = GPIO_PIN_4)
#define SPI1_CS_LOW()  (GPIOA->BCR = GPIO_PIN_4)
void SPI1Init(void)
{
	GPIO_InitPara GPIO_InitStructure;
	SPI_InitPara SPI_InitStructure;
	
	rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_SPI0);
	//GD32的外设命名顺序很烦人,它的手册上都是从0开始数的,到了代码里,使能时钟这里是从0数,到后面又是从1数了
	/* SPI1_SCK(PA5), SPI1_MISO(PA6) and SPI1_MOSI(PA7) GPIO pin configuration */
	GPIO_InitStructure.GPIO_Pin = GPIO_PIN_5 | GPIO_PIN_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	GPIO_InitStructure.GPIO_Pin = GPIO_PIN_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_MODE_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	/* SPI1_CS(PA4) GPIO pin configuration */
	GPIO_InitStructure.GPIO_Pin = GPIO_PIN_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	/* chip select invalid*/
	SPI1_CS_HIGH();
	/* SPI1 parameter config */
	SPI_InitStructure.SPI_TransType = SPI_TRANSTYPE_FULLDUPLEX;
	SPI_InitStructure.SPI_Mode = SPI_MODE_MASTER;
	SPI_InitStructure.SPI_FrameFormat = SPI_FRAMEFORMAT_8BIT;
	SPI_InitStructure.SPI_SCKPL = SPI_SCKPL_LOW;
	SPI_InitStructure.SPI_SCKPH = SPI_SCKPH_1EDGE;
	SPI_InitStructure.SPI_SWNSSEN = SPI_SWNSS_SOFT;
	SPI_InitStructure.SPI_PSC = SPI_PSC_4;
	SPI_InitStructure.SPI_FirstBit = SPI_FIRSTBIT_MSB;
	SPI_InitStructure.SPI_CRCPOL = 7;
	SPI_Init(SPI1, &SPI_InitStructure);//这里变成的SPI1了,没有SPI0
	/* enable SPI1 */
	SPI_Enable(SPI1, ENABLE);
}

unsigned char SPI1ReadWriteByte(unsigned char byte)
{
	/* loop while data register in not emplty */
	while (RESET == SPI_I2S_GetBitState(SPI1,SPI_FLAG_TBE));
	/* send byte through the SPI0 peripheral */
	SPI1->DTR = byte;
	/* wait to receive a byte */
	while(RESET == SPI_I2S_GetBitState(SPI1,SPI_FLAG_RBNE));
	/* return the byte read from the SPI bus */
	return (SPI1->DTR);
}

配置DMA0

void SPI1DMAInit(void)	//DMA0 (count from 0) Channel3 (count from 1)
{
	DMA_InitPara DMA_InitStructure;
//	NVIC_InitPara NVIC_InitParaStruct;	//没用上中断
	
	rcu_periph_clock_enable(RCU_DMA0);
	//Tx_DMA
	DMA_DeInit(DMA1_CHANNEL3);	
	DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&(SPI1->DTR);
	DMA_InitStructure.DMA_MemoryBaseAddr = 0;	//内存地址待定,启动传输时配置
	DMA_InitStructure.DMA_DIR = DMA_DIR_PERIPHERALDST;
	DMA_InitStructure.DMA_BufferSize = 0;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;
	DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;	//收发通道都配成内存地址递增就行
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PERIPHERALDATASIZE_BYTE;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MEMORYDATASIZE_BYTE;
	DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL;
	DMA_InitStructure.DMA_Priority = DMA_PRIORITY_MEDIUM;
	DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;
	
//	NVIC_InitParaStruct.NVIC_IRQ = DMA1_Channel3_IRQn;
//	NVIC_InitParaStruct.NVIC_IRQPreemptPriority = 0;
//	NVIC_InitParaStruct.NVIC_IRQSubPriority = 2;
//	NVIC_InitParaStruct.NVIC_IRQEnable = ENABLE;
//	NVIC_Init(&NVIC_InitParaStruct);
//	NVIC_EnableIRQ(DMA1_Channel3_IRQn);
	
	DMA_Init(DMA1_CHANNEL3, &DMA_InitStructure);
	DMA_ClearIntBitState(DMA1_INT_TC3);
	//DMA_INTConfig(DMA1_CHANNEL3, DMA_INT_TC, ENABLE);
	
	//Rx_DMA
	DMA_DeInit(DMA1_CHANNEL2);
	DMA_InitStructure.DMA_DIR = DMA_DIR_PERIPHERALSRC;
	DMA_InitStructure.DMA_BufferSize = 0;
	DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;
	
//	NVIC_InitParaStruct.NVIC_IRQ = DMA1_Channel2_IRQn;
//	NVIC_InitParaStruct.NVIC_IRQPreemptPriority = 0;
//	NVIC_InitParaStruct.NVIC_IRQSubPriority = 2;
//	NVIC_InitParaStruct.NVIC_IRQEnable = ENABLE;
//	NVIC_Init(&NVIC_InitParaStruct);
//	NVIC_EnableIRQ(DMA1_Channel2_IRQn);
	
	DMA_Init(DMA1_CHANNEL2, &DMA_InitStructure);
	DMA_ClearIntBitState(DMA1_INT_TC2);
	//DMA_INTConfig(DMA1_CHANNEL2, DMA_INT_TC, ENABLE);
}

void SPI1TxDMAEnable(unsigned int mem_addr, unsigned int buf_size)
{
	//tx
	DMA_Enable(DMA1_CHANNEL3, DISABLE);
	while(DMA_GetCmdStatus(DMA1_CHANNEL3));
	DMA_SetCurrDataCounter(DMA1_CHANNEL3, buf_size);	//设置传输数据字节数
	DMA_MemoryTargetConfig(DMA1_CHANNEL3, mem_addr);	//设置内存地址
	SPI_I2S_DMA_Enable(SPI1, SPI_I2S_DMA_TX, ENABLE);
	//rx
	DMA_Enable(DMA1_CHANNEL2, DISABLE);
	while(DMA_GetCmdStatus(DMA1_CHANNEL2));
	DMA_SetCurrDataCounter(DMA1_CHANNEL2, buf_size);
	DMA_MemoryTargetConfig(DMA1_CHANNEL3, mem_addr);	//接收通道的内存地址和发送通道设置成一样的,之前的数据被覆盖前已经通过发送通道发出去了
	SPI_I2S_DMA_Enable(SPI1, SPI_I2S_DMA_RX, ENABLE);
	//enable
	DMA1_CHANNEL2->CTLR |= DMA_CTLR_CHEN;	//DMA Enable
	DMA1_CHANNEL3->CTLR |= DMA_CTLR_CHEN;	//DMA Enable
	while(!DMA_GetIntBitState(DMA1_INT_TC2));
	DMA_ClearIntBitState(DMA1_INT_TC2);
	while(!DMA_GetIntBitState(DMA1_INT_TC3));
	DMA_ClearIntBitState(DMA1_INT_TC3);
}

  上面代码中函数SPI1TxDMAEnable(unsigned int mem_addr, unsigned int buf_size)用来启动一次DMA传输,RX通道和TX通道的内存地址配成同一个就行,因为SPI的数据收发是在一个时钟控制下同时进行,内存的变量被读入的数据覆盖之前已经被发送出去了,不用担心内存数据被覆盖而发生错误。

  • 4
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值