要想使用DMA功能,首先使能DMA模块的时钟。
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
将SPI的接收和发送方式设置为DMA方式
void SPI_Config(void) { SPI_I2S_DeInit(SPI1);//重置SPI1 SPI_InitStruct.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//spi设置成双向双线全双工 SPI_InitStruct.SPI_Mode=SPI_Mode_Master;//SPI工作在主模式 SPI_InitStruct.SPI_DataSize=SPI_DataSize_8b;//SPI接收发送8位数据 SPI_InitStruct.SPI_CPOL=SPI_CPOL_Low;//始终悬空低,SCK在空闲时保持低电平 SPI_InitStruct.SPI_CPHA=SPI_CPHA_1Edge;//数据捕获于第一个时钟沿 SPI_InitStruct.SPI_NSS=SPI_NSS_Soft;//软件控制NSS SPI_InitStruct.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_4;比特率预分频值为4分频 SPI_InitStruct.SPI_FirstBit=SPI_FirstBit_MSB;//数据传输从MSB开始 SPI_InitStruct.SPI_CRCPolynomial=7;//用于CRC值校验的多项式 SPI_Init(SPI1,&SPI_InitStruct); SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx,ENABLE);//将SPI1模块接收设置成DMA方式工作 SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx,ENABLE);//将SPI1模块发送设置成DMA方式工作 SPI_Cmd(SPI1,ENABLE) }
SPI的DMA接收配置:
void SPI1_DMA_Recv_Config(void) { DMA1_Channel2->CPAR=(uint32_t)(&(SPI1->DR));//设置DMA通道2的外设地址 DMA1_Channel2->CCR |= 0x2080; //PL=10 优先级高 //MSIZ=00 存储8位 //PSIZE=00 外设8位 //MINC=1 存储地址自增 //PINC=0 外设地址不变 //CIRC=0 非循环模式 //DIR=0 方向由外设到存储器 }
SPI的DMA发送配置:
void SPI1_DMA_Send_Config(void) { DMA1_Channel3->CPAR=(uint32_t)(&(SPI1->DR));//设置DMA通道2的外设地址 DMA1_Channel3->CCR |= 0x0090; //PL=10 优先级高 //MSIZ=00 存储8位 //PSIZE=00 外设8位 //MINC=1 存储地址自增 //PINC=0 外设地址不变 //CIRC=0 非循环模式 //DIR=1 方向由存储器到外设 }
当通道配置为非循环模式时,传输结束后(即传输计数变为0)将不再产生DMA操作。要开始新的DMA传输,需要在关闭DMA通道的情况下,在DMAx_CNDTR寄存器中重新写入传输数目。
在循环模式下,最后一次传输结束时,DMA_CNDTRx寄存器的内容会自动地被重新加载为其初始数值,内部的当前外设/存储器地址寄存器也被重新加载为DMAx_CPAR/DMAx_CMAR寄存器设定的初始基地址。
SPI利用DMA发送接收数据:
void SPI1_ReceiveSendByte(uint16_t num,unsigned char *rx,unsigned char *tx) { DMA_Channel2->CNDTR=num;//设置发送数据字节数 DMA_Channel2->CMAR=(uint32_t)rx;//DMA内存地址寄存器 DMA_Channel3->CNDTR=num;//设置发送数据字节数 DMA_Channel3->CMAR=(uint32_t)tx;//DMA内存地址寄存器 DMA_Channel3->CCR |= 0x0001;//启动DMA DMA_Channel2->CCR |= 0x0001; while((DMA1->ISR & (1<<9)) == 0);//等待DMA传送完成 while((DMA1->ISR & (1<<5)) == 0); DMA1->IRCR |= (1<<5)|(1<<9);//清标志位 DMA_Channel3->CCR &= ~(1<<0);//关闭DMA DMA_Channel2->CCR &= ~(1<<0); }