文章目录[隐藏]
GD32是国产的32位单片机,它和STM32非常非常像,就连以前的库函数都差不多(现在从GD官网下载的库函数换了一种风格)。配置SPI和DMA的方法和STM32差不多。
上图是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的数据收发是在一个时钟控制下同时进行,内存的变量被读入的数据覆盖之前已经被发送出去了,不用担心内存数据被覆盖而发生错误。
版权声明:本文为CSDN博主「Chenxr32」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/QDchenxr/article/details/119813261
暂无评论