??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);
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);
GPIO_InitStructure.GPIO_Pin = GPIO_PIN_4;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI1_CS_HIGH();
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);
SPI_Enable(SPI1, ENABLE);
}
unsigned char SPI1ReadWriteByte(unsigned char byte)
{
while (RESET == SPI_I2S_GetBitState(SPI1,SPI_FLAG_TBE));
SPI1->DTR = byte;
while(RESET == SPI_I2S_GetBitState(SPI1,SPI_FLAG_RBNE));
return (SPI1->DTR);
}
配置DMA0
void SPI1DMAInit(void)
{
DMA_InitPara DMA_InitStructure;
rcu_periph_clock_enable(RCU_DMA0);
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;
DMA_Init(DMA1_CHANNEL3, &DMA_InitStructure);
DMA_ClearIntBitState(DMA1_INT_TC3);
DMA_DeInit(DMA1_CHANNEL2);
DMA_InitStructure.DMA_DIR = DMA_DIR_PERIPHERALSRC;
DMA_InitStructure.DMA_BufferSize = 0;
DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;
DMA_Init(DMA1_CHANNEL2, &DMA_InitStructure);
DMA_ClearIntBitState(DMA1_INT_TC2);
}
void SPI1TxDMAEnable(unsigned int mem_addr, unsigned int buf_size)
{
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);
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);
DMA1_CHANNEL2->CTLR |= DMA_CTLR_CHEN;
DMA1_CHANNEL3->CTLR |= DMA_CTLR_CHEN;
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的数据收发是在一个时钟控制下同时进行,内存的变量被读入的数据覆盖之前已经被发送出去了,不用担心内存数据被覆盖而发生错误。
|