提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
这里主要记录一下stm32f407zg的dma-uart的接收
一、dma相关
1.简介
DMA:一种搬运数据的东西(在搬运过程中不占用cpu,但是会抢占总线,可能会导致cpu错过中断),一般用在adc的采集中,在我的开发板(stm32f407zg)中,两个dma,每个dma8个数据流,每个数据流有8个通道(即:对应8个外设请求),注意:每一个数据流虽然有8个通道,但是同一时刻只能相应一个通道。
2.模式
外设到存储器传输、存储器到外设传输和存储器到存储器传输三种传输模式
外设:外设的数据寄存器。
存储器:一般是指片内SRAM、外部存储器、片内Flash等等。
3.优先级
两种设置模式
1.软件设置(非常高、高、中和低)
2.硬件控制(数据流编号越小优先级别越高)
4.FIFO
每个数据流都独立拥有四级32位的FIFO,也就是16个字节,可以设置阈值(1/4、1/2、3/4和满),到达阈值才传—FIFO模式,有数就传—直接模式(默认直接模式)
5.配置参数说明
DMA2支持全部三种传输模式(dma1不支持内存到内存,因为没有挂载在ahb总线上),
位宽:可以设置外设和存储器数据宽度大小:字节(8位)、半字(16位)和字(32位),当时用直接模式的时候,只需要指定外设数据宽度既可。
源地址和目标地址:32位,两种寄存器(DMA_SxM0AR(x为0~7) ,DMA_SxM1AR(x为0~7) ,其中DMA_SxM1AR只用来双缓冲模式所以会看到在直接模式中的memory0)
流控制:即传输数据的个数,这里的个数单位是前面设置的位宽
循环模式/单次模式:字面意思。
传输类型:单次与突发(突发一般与FIFO一起使用,达到阈值即传输)
二、代码
//nvic配置中断源优先级,没什么好说的
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//DMA配置
void USART_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
//复位初始化dma数据流
DMA_DeInit(DMA2_Stream2);
//确保复位完成
while(DMA_GetCmdStatus(DMA2_Stream2) != DISABLE)
{
}
DMA_InitStructure.DMA_Channel = DMA_Channel_4;//通道4
DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)(USART1_BASE+0x04);//外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (u32)u1rxbuf;//存储器地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//方向
DMA_InitStructure.DMA_BufferSize = USART2_MAX_RX_LEN;//要传输数据大小
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;//优先级中
//不用FIFO
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
//注意:这两句要有的,我之前一直以为我使用直接模式,就不需要这两句了,后来一直调不通
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//单次模式
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream2, &DMA_InitStructure);
NVIC_Configuration();
DMA_ITConfig(DMA2_Stream2,DMA_IT_TC,ENABLE);//开启传输完成中断
DMA_Cmd(DMA2_Stream2, ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
while (DMA_GetCmdStatus(DMA2_Stream2) != ENABLE)
{
}
}
//中断
void DMA2_Stream2_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_Stream2,DMA_IT_TCIF2)!=RESET)
{
DMA_ClearITPendingBit(DMA2_Stream2,DMA_IT_TCIF2);
DMA_Cmd(DMA2_Stream2,DISABLE);
//乒乓操作
if(witchbuf)
{
memcpy(p,u2rxbuf,USART2_MAX_RX_LEN);
DMA2_Stream2->M0AR = (u32)u1rxbuf;
witchbuf=0;
}
else
{
memcpy(p,u1rxbuf,USART2_MAX_RX_LEN);
DMA2_Stream2->M0AR = (u32)u2rxbuf;
witchbuf=1;
}
DMA2_Stream2->NDTR = USART2_MAX_RX_LEN;
/*因为是DMA正常模式,并非循环,所以传输完一次就停止了
,要想开启需要这样做
1:DMA_ClearITPendingBit(DMA2_Stream2,DMA_IT_TCIF2);
2:DMA_Cmd(DMA2_Stream2,ENABLE);
*/
DMA_Cmd(DMA2_Stream2,ENABLE);
}
}
总结
下把争取做到少些文字,更生动形象,不然文字太多自己都不想看;