hitlocking 发表于 2015-11-30 19:24:39

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总线,除非数据传输完成

电子信息港帐好 发表于 2015-12-1 11:27:02

:o:o:o:o:o虽然不懂,想知道答案
页: [1]
查看完整版本: STM32F103的DMA相关问题