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

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管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版