你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F103的DMA相关问题

[复制链接]
hitlocking 提问时间:2015-11-30 19:24 /
有幸在工程中用到STM32F103的DMA功能,而且是两个串口(USART2和USART3)都需要用到DMA功能来实现数据传输。以前用STM32F103都是只用过一个DMA通道,这次用到了DMA1的两个通道,结果发现了一个惊天的问题:

两个通道的DMA无法实现共存!!!


先贴代码:
  1. //DMA1的各通道配置
  2. //这里的传输形式是固定的,这点要根据不同的情况来修改
  3. //从存储器->外设模式/8位数据宽度/存储器增量模式
  4. //DMA_CHx:DMA通道CHx
  5. //cpar:外设地址
  6. //cmar:存储器地址   
  7. void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar, u32 Direction)
  8. {
  9.         DMA_InitTypeDef DMA_InitStructure;
  10.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1|RCC_APB2Periph_AFIO, ENABLE);        //使能DMA传输
  11.         DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值
  12.         DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA外设基地址
  13.         DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址
  14.         DMA_InitStructure.DMA_DIR = Direction;//数据传输方向,DMA_DIR_PeripheralDST:从内存读取发送到外设;DMA_DIR_PeripheralSRC:从外设读取发送到内存
  15.         DMA_InitStructure.DMA_BufferSize = 32;  //DMA通道的DMA缓存的大小
  16.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
  17.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
  18.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为8位
  19.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
  20.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal;//;// ;  //工作在循环缓存模式
  21.         DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//DMA_Priority_Medium; //DMA通道 x拥有中优先级
  22.         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
  23.         DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器       
  24. }
复制代码
这是一个总的配置函数,接下来是USART2和USART3的配置:
  1. void My_usart3_init(u32 bound)
  2. {
  3.         //GPIO端口设置
  4.         GPIO_InitTypeDef  GPIO_InitStructure;
  5.         USART_InitTypeDef USART_InitStructure;
  6.         NVIC_InitTypeDef  NVIC_InitStructure;

  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
  8.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  9.          //USART3_TX   PB.10
  10.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  11.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  13.         GPIO_Init(GPIOB, &GPIO_InitStructure);

  14.         //USART3_RX          PB.11
  15.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  16.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  17.         GPIO_Init(GPIOB, &GPIO_InitStructure);  
  18.                
  19.         //USART 初始化设置                 
  20.         USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
  21.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  22.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  23.         USART_InitStructure.USART_Parity = USART_Parity_No;
  24.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  25.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  26.         //配置串口3的DMA中断
  27.         NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
  28.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  29.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  30.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  31.         NVIC_Init(&NVIC_InitStructure);
  32.        
  33.         UART_DMA_Config(DMA1_Channel3,(u32)&USART3->DR,(u32)USART3_RX_BUF,DMA_DIR_PeripheralSRC);//DMA1通道3,外设为串口3,存储器为USART3_RX_BUF,外设到内存
  34.         USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);          //使能串口2的DMA接收               
  35.         USART_Init(USART3, &USART_InitStructure);
  36.         USART_Cmd(USART3, ENABLE);                    //使能串口
  37.         DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);        //使能DMA1_Channel3的数据传输完成中断        DMA1_IT_TC3
  38.         DMA_Cmd(DMA1_Channel3, ENABLE);           //开启DMA传输
  39. }
复制代码
  1. void My_usart2_init(u32 bound)
  2. {
  3.         //GPIO端口设置
  4.         GPIO_InitTypeDef  GPIO_InitStructure;
  5.         USART_InitTypeDef USART_InitStructure;
  6.         NVIC_InitTypeDef  NVIC_InitStructure;

  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
  8.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  9.          //USART2_TX   PA.2
  10.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  11.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  13.         GPIO_Init(GPIOA, &GPIO_InitStructure);

  14.         //USART2_RX          PA.3
  15.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  16.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  17.         GPIO_Init(GPIOA, &GPIO_InitStructure);  

  18.         NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  19.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
  20.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                //

  21.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
  22.         NVIC_Init(&NVIC_InitStructure);        //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器USART1
  23.                
  24.         //USART 初始化设置                 
  25.         USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
  26.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  27.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  28.         USART_InitStructure.USART_Parity = USART_Parity_No;
  29.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  30.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  31.         UART_DMA_Config(DMA1_Channel6,(u32)&USART2->DR,(u32)USART2_RX_BUF,DMA_DIR_PeripheralSRC);//DMA1通道7,外设为串口2,存储器为USART2_RX_BUF,外设到内存
  32.         USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);          //使能串口2的DMA接收               
  33.         USART_Init(USART2, &USART_InitStructure);
  34.         USART_Cmd(USART2, ENABLE);                    //使能串口
  35.         DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);        //使能DMA1_Channel6的数据传输完成中断        DMA1_IT_TC6
  36.         DMA_Cmd(DMA1_Channel6, ENABLE);           //开启DMA传输
  37. }
复制代码
OK了,这样USART2和USART3就和DMA通道连在一起了。USART2是DMA1_Channel6,USART3是DMA1_Channel3。
然后就是两个DMA中断函数,在这里进行数据处理:
  1. void DMA1_Channel3_IRQHandler()
  2. {

  3.         if(DMA_GetITStatus(DMA1_IT_TC3) != RESET)
  4.         {
  5. //                printf("over\r\r\n");
  6.                 DMA_ClearITPendingBit(DMA1_IT_TC3);
  7. ………………………………
  8.                        
  9.                 }       
  10.         //执行完DMA1_Channel3的中断后, 把channel3失能,把channel6使能,这样就可以进入usart2的DMA中断了
  11.         //和usart2中遥相呼应
  12. //        DMA_Cmd(DMA1_Channel6, ENABLE);               
  13. //        DMA_Cmd(DMA1_Channel3, DISABLE);                       
  14.         }               
  15. }
复制代码
  1. void DMA1_Channel6_IRQHandler()
  2. {
  3.         u16 sum=0;       
  4.         if(DMA_GetITStatus(DMA1_IT_TC6) != RESET)
  5.         {
  6. //                printf("over\r\r\n");
  7.                 DMA_ClearITPendingBit(DMA1_IT_TC6);
复制代码


在上面的中断函数中,进行相应的数据处理。

接下来就是重点了!高能!

经过认真测试,USART2的DMA1_Channel6和USART3的DMA1_Channel3无法同时在程序中起作用!!!

不过仔细一想,本来嘛,STM32的DMA1的总线只有一条,如果Channel6占据了,当然Channel3就无法工作了,这也是合理的。怎么办呢?分时复用一下就OK了吧。OK,设置分时复用:
  1. void DMA1_Channel3_IRQHandler()
  2. {

  3. if(DMA_GetITStatus(DMA1_IT_TC3) != RESET)
  4. {
  5. //        printf("over\r\r\n");
  6. DMA_ClearITPendingBit(DMA1_IT_TC3);
  7. ………………………………

  8. }       
  9. //执行完DMA1_Channel3的中断后, 把channel3失能,把channel6使能,这样就可以进入usart2的DMA中断了
  10. //和usart2中遥相呼应
  11.         DMA_Cmd(DMA1_Channel6, ENABLE);       
  12.         DMA_Cmd(DMA1_Channel3, DISABLE);       
  13. }       
  14. }
复制代码
  1. void DMA1_Channel6_IRQHandler()
  2. {
  3. u16 sum=0;       
  4. if(DMA_GetITStatus(DMA1_IT_TC6) != RESET)
  5. {
  6. //        printf("over\r\r\n");
  7. DMA_ClearITPendingBit(DMA1_IT_TC6);
  8.         //执行完DMA1_Channel6的中断后, 把channel6失能,把channel3使能,这样就可以进入usart3的DMA中断了
  9.         //和usart3中遥相呼应
  10.         DMA_Cmd(DMA1_Channel6, DISABLE);               
  11.         DMA_Cmd(DMA1_Channel3, ENABLE);       
  12. }
  13. }
复制代码
这样总可以了吧!虽然不断地开关浪费时间,可是我只要能实现两个通道都可以用就OK!

然而too young too simple!竟然是不可以的,两个通道都不工作!!!

是因为变化的太快了?
反正是都没有受到数据。
这是不是STM32F103的固有缺陷?就像硬件IIC一样?







猜测刚进系统的时候,两个DMA传输是抢占式的,谁在前使能,谁就占用了DMA总线,除非数据传输完成
收藏 1 评论1 发布时间:2015-11-30 19:24

举报

1个回答
电子信息港帐好 回答时间:2015-12-1 11:27:02
虽然不懂,想知道答案

所属标签

相似问题

官方最新资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版