STM32F103的DMA相关问题
有幸在工程中用到STM32F103的DMA功能,而且是两个串口(USART2和USART3)都需要用到DMA功能来实现数据传输。以前用STM32F103都是只用过一个DMA通道,这次用到了DMA1的两个通道,结果发现了一个惊天的问题:两个通道的DMA无法实现共存!!!
先贴代码:
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar, u32 Direction)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1|RCC_APB2Periph_AFIO, ENABLE); //使能DMA传输
DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;//DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar;//DMA内存基地址
DMA_InitStructure.DMA_DIR = Direction;//数据传输方向,DMA_DIR_PeripheralDST:从内存读取发送到外设;DMA_DIR_PeripheralSRC:从外设读取发送到内存
DMA_InitStructure.DMA_BufferSize = 32;//DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal;//;// ;//工作在循环缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//DMA_Priority_Medium; //DMA通道 x拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx, &DMA_InitStructure);//根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
} 这是一个总的配置函数,接下来是USART2和USART3的配置:
void My_usart3_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDefGPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDefNVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
//USART3_TX PB.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//USART3_RX PB.11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
//配置串口3的DMA中断
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
UART_DMA_Config(DMA1_Channel3,(u32)&USART3->DR,(u32)USART3_RX_BUF,DMA_DIR_PeripheralSRC);//DMA1通道3,外设为串口3,存储器为USART3_RX_BUF,外设到内存
USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE); //使能串口2的DMA接收
USART_Init(USART3, &USART_InitStructure);
USART_Cmd(USART3, ENABLE); //使能串口
DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE); //使能DMA1_Channel3的数据传输完成中断 DMA1_IT_TC3
DMA_Cmd(DMA1_Channel3, ENABLE); //开启DMA传输
}void My_usart2_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDefGPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDefNVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//USART2_TX PA.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART2_RX PA.3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器USART1
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
UART_DMA_Config(DMA1_Channel6,(u32)&USART2->DR,(u32)USART2_RX_BUF,DMA_DIR_PeripheralSRC);//DMA1通道7,外设为串口2,存储器为USART2_RX_BUF,外设到内存
USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE); //使能串口2的DMA接收
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE); //使能串口
DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE); //使能DMA1_Channel6的数据传输完成中断 DMA1_IT_TC6
DMA_Cmd(DMA1_Channel6, ENABLE); //开启DMA传输
}OK了,这样USART2和USART3就和DMA通道连在一起了。USART2是DMA1_Channel6,USART3是DMA1_Channel3。
然后就是两个DMA中断函数,在这里进行数据处理:
void DMA1_Channel3_IRQHandler()
{
if(DMA_GetITStatus(DMA1_IT_TC3) != RESET)
{
// printf("over\r\r\n");
DMA_ClearITPendingBit(DMA1_IT_TC3);
………………………………
}
//执行完DMA1_Channel3的中断后, 把channel3失能,把channel6使能,这样就可以进入usart2的DMA中断了
//和usart2中遥相呼应
// DMA_Cmd(DMA1_Channel6, ENABLE);
// DMA_Cmd(DMA1_Channel3, DISABLE);
}
}
void DMA1_Channel6_IRQHandler()
{
u16 sum=0;
if(DMA_GetITStatus(DMA1_IT_TC6) != RESET)
{
// printf("over\r\r\n");
DMA_ClearITPendingBit(DMA1_IT_TC6);
在上面的中断函数中,进行相应的数据处理。
接下来就是重点了!高能!
经过认真测试,USART2的DMA1_Channel6和USART3的DMA1_Channel3无法同时在程序中起作用!!!
不过仔细一想,本来嘛,STM32的DMA1的总线只有一条,如果Channel6占据了,当然Channel3就无法工作了,这也是合理的。怎么办呢?分时复用一下就OK了吧。OK,设置分时复用:
void DMA1_Channel3_IRQHandler()
{
if(DMA_GetITStatus(DMA1_IT_TC3) != RESET)
{
// printf("over\r\r\n");
DMA_ClearITPendingBit(DMA1_IT_TC3);
………………………………
}
//执行完DMA1_Channel3的中断后, 把channel3失能,把channel6使能,这样就可以进入usart2的DMA中断了
//和usart2中遥相呼应
DMA_Cmd(DMA1_Channel6, ENABLE);
DMA_Cmd(DMA1_Channel3, DISABLE);
}
}void DMA1_Channel6_IRQHandler()
{
u16 sum=0;
if(DMA_GetITStatus(DMA1_IT_TC6) != RESET)
{
// printf("over\r\r\n");
DMA_ClearITPendingBit(DMA1_IT_TC6);
//执行完DMA1_Channel6的中断后, 把channel6失能,把channel3使能,这样就可以进入usart3的DMA中断了
//和usart3中遥相呼应
DMA_Cmd(DMA1_Channel6, DISABLE);
DMA_Cmd(DMA1_Channel3, ENABLE);
}
}这样总可以了吧!虽然不断地开关浪费时间,可是我只要能实现两个通道都可以用就OK!
然而too young too simple!竟然是不可以的,两个通道都不工作!!!
是因为变化的太快了?
反正是都没有受到数据。
这是不是STM32F103的固有缺陷?就像硬件IIC一样?
猜测刚进系统的时候,两个DMA传输是抢占式的,谁在前使能,谁就占用了DMA总线,除非数据传输完成
:o:o:o:o:o虽然不懂,想知道答案
页:
[1]