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

STM32F401使用DMA2+GPIO并行输出问题:输出数据量错误、DMA...

[复制链接]
小温点秋香 提问时间:2018-1-16 10:29 /
问题:
1、DMA  buffsize与实际采集波形对应数据量不一致。输出数据少了,且在BuffSize低于64,GPIO没有输出;问题出在哪里呢?
2、DMA 在输出结束中断后关闭DMA_Cmd(DMA2_Stream5,DISABLE);然后再main函数中修改memory中数据,最后开启DMA;
     发现 输出数据达不到预期效果;问:该怎样实现DMA开关?

代码:
  1. //宏定义 DMA 传送数据量
  2. #define BUFF_LEN   64

  3. //初始化GPIO+DMA2
  4. void Test_RAM2GPIO_DMA(void)
  5. {
  6.         GPIO_InitTypeDef  GPIO_InitStruct;
  7.         TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
  8.         DMA_InitTypeDef           DMA_InitStructure;

  9.         int len = sizeof(g_buff_disp)/8;
  10.         int i;
  11.         for(i=0; i<len; i+=8)
  12.                 {
  13.                         g_buff_disp =   0xffff & (~(1 << 13));
  14.                         g_buff_disp[i+1] = 0xffff | (1 << 13);
  15.                         g_buff_disp[i+2] = 0x0000 ;
  16.                         g_buff_disp[i+3] = 0x0000 | (1 << 13);
  17.                         g_buff_disp[i+4] = 0xffff & (~(1 << 13));
  18.                         g_buff_disp[i+5] = 0xffff;
  19.                         g_buff_disp[i+6] = 0xffff & (~(1 << 13));
  20.                         g_buff_disp[i+7] = 0xffff;
  21.                 }

  22.         my_memcpy32(g_buff_DMA0, g_buff_disp, BUFF_LEN/2);
  23.         //my_memcpy32(g_buff_DMA1, g_buff_disp, BUFF_LEN/2);

  24.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
  25.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  26.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

  27.         //GPIO
  28.         GPIO_InitStruct.GPIO_Pin = GPIO_Pin_All;
  29.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
  30.         GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  31.         GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
  32.         GPIO_Init(GPIOB, &GPIO_InitStruct);
  33.         
  34.         //DMA2 Stream6 channel2
  35.         DMA_InitStructure.DMA_Channel = DMA_Channel_6;
  36.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(GPIOB->ODR); //aSRC_Const_Buffer
  37.         DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&g_buff_DMA0;
  38.         DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  39.         DMA_InitStructure.DMA_BufferSize = BUFF_LEN;//以ODR为单位数据量
  40.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  41.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  42.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  43.         DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;
  44.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  45.         DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  46.         DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                  
  47.         DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  48.         DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//单次
  49.         DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  50.         DMA_Init(DMA2_Stream5, &DMA_InitStructure);
  51.         //双缓存模式  ,默认循环。传送完全部  buff0之后再传送buff1
  52.         //双模式下才能在传输完成时修改源/目标地址
  53.         //DMA_DoubleBufferModeConfig(DMA2_Stream5,(uint32_t)&g_buff_DMA1,DMA_Memory_0);
  54.         //DMA_DoubleBufferModeCmd(DMA2_Stream5,ENABLE);
  55.     DMA_ClearITPendingBit(DMA2_Stream5, DMA_IT_TCIF5);
  56.         DMA_ITConfig(DMA2_Stream5, DMA_IT_TC, ENABLE);
  57.         DMA_Cmd(DMA2_Stream5,ENABLE);

  58.         //TIM1
  59.         TIM_BaseInitStructure.TIM_Period =        1260-1;
  60.         TIM_BaseInitStructure.TIM_Prescaler = 1;
  61.         TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  62.         TIM_BaseInitStructure.TIM_ClockDivision = 0;
  63.         TIM_BaseInitStructure.TIM_RepetitionCounter = 0;
  64.         TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);
  65.         
  66.         TIM_ARRPreloadConfig(TIM1, ENABLE);
  67.         TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_Update);
  68.         TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
  69.         //TIM1开启
  70.         TIM_Cmd(TIM1, ENABLE);
  71. }        

  72. // main 函数中移动buff
  73. void moveLeft(u32 *pData, UI16 n)
  74. {
  75.         u32 head = *pData;
  76.         n=n/2;
  77.         for(u16 i=0; i<n-1;i++)
  78.         {
  79.                 *(pData+i) = *(pData+i+1);
  80.         }
  81.         *(pData+n-1) = head;
  82. }

  83. volatile u8 g_updata_flag = 0;
  84. void my_Animat_Left(void)
  85. {
  86.         if(g_updata_flag)
  87.         {               
  88.                 moveLeft((u32 *)g_buff_disp, (BUFF_LEN-DUMMY_N)/2);
  89.                 my_memcpy32(g_buff_DMA0, g_buff_disp, (BUFF_LEN)/2);
  90.                
  91. DMA_Cmd(DMA2_Stream5,ENABLE);
  92.                 //TIM_Cmd(TIM1, ENABLE);

  93.                 g_updata_flag = 0;               
  94.         }
  95. }

  96. //中断
  97. #ifndef RESERVED_MASK
  98. #define RESERVED_MASK           (uint32_t)0x0F7D0F7D  
  99. #endif
  100. void DMA2_Stream5_IRQHandler(void)
  101. {
  102.         static int cnt = 0;

  103.         if( DMA2->HISR & DMA_IT_TCIF5)        
  104.         {
  105.                 DMA2->HIFCR = (uint32_t)(DMA_IT_TCIF5 & RESERVED_MASK);
  106.                
  107.                 ResetLed();               
  108.                 SetLed();
  109.                 ResetLed();
  110.                cnt=cnt &0x0F;
  111.                 if(!cnt)
  112.                 {
  113.                         g_updata_flag = 1;                                       
  114.                         DMA_Cmd(DMA2_Stream5,DISABLE);               
  115.                 }
  116.                 row ++;
  117.     }
  118. }
复制代码


逻辑分析仪 采集波形:
如下图可见  16个数据 小于64,而且  第12个数据之后出现一段较大空闲。不知原因。





BuffSize=80

BuffSize=80

BuffSize=100

BuffSize=100

BuffSize 100另一时刻结果

BuffSize 100另一时刻结果

评分

参与人数 1 ST金币 -1 收起 理由
zero99 -1 求助帖还付费主题?帮你改过了.

查看全部评分

收藏 2 评论13 发布时间:2018-1-16 10:29

举报

13个回答
wenyangzeng 回答时间:2018-1-24 10:40:13
本帖最后由 wenyangzeng 于 2018-1-24 13:48 编辑

楼主既然设置了DMA传输数据长度:
DMA_InitStructure.DMA_BufferSize = BUFF_LEN;
按理就不应该在中断中再计数cnt了,
因为设置的传输模式中:
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA计数达到100时必定产生中断,当中断发生时,DMA的下一次传输仍然在进行,这时的cnt不会与DMA同步了,以cnt作为关闭DMA的时间,应该会漏掉不少DMA传输数据了。
建议:
如果要关闭DMA,应该在中断到来时就关闭,与cnt无关。
同时,要再次进入DMA传输时,恐怕要再初始化一次DMA了,
其实可以设一个缓冲数组,每次DMA中断将数据复制到缓冲区,DMA不停止工作,需要数据时从缓冲区读。




评分

参与人数 1蝴蝶豆 +5 收起 理由
zero99 + 5

查看全部评分

小温点秋香 回答时间:2018-1-16 10:48:48
@ST  @ST官网
zero99 回答时间:2018-1-16 16:35:38
楼主可以看看这个插入代码的方法
https://www.stmcu.org.cn/module/forum/thread-612887-1-1.html
小温点秋香 回答时间:2018-1-16 16:51:42
zero99 发表于 2018-1-16 16:35
楼主可以看看这个插入代码的方法
https://www.stmcu.org.cn/module/forum/thread-612887-1-1.html ...

Done !
你好, 怎么在论坛里邀请,ST技术答疑呢?
feixiang20 回答时间:2018-1-16 17:42:44
本帖最后由 feixiang20 于 2018-1-18 10:43 编辑

7楼,请问怎样尽可能以最直接的速度关闭DMA ?

评分

参与人数 2ST金币 -4 收起 理由
zero99 -2 二次警告
Inc_brza -2 请勿灌水,警告一次

查看全部评分

小温点秋香 回答时间:2018-1-16 18:25:29
使用一半传输中断:
  1.     DMA_ClearITPendingBit(DMA2_Stream5, DMA_IT_HTIF5); //DMA_IT_TCIF5
  2.         DMA_ITConfig(DMA2_Stream5, DMA_IT_HT, ENABLE);
  3.         u32 n= DMA2_Stream5->NDTR;
  4.         d_p(1,"Start sed n=%d \r\n",n);
复制代码

/*-------中断函数部分代码--------*/
  1.         else if(DMA2->HISR & DMA_IT_HTIF5)//半传输
  2.         {
  3.                 u32 n= DMA2_Stream5->NDTR;       
  4.                 d_p(1,"HT IRQ n=%d\r\n",n); // 过半传送,n <BUFF_SIZE/2 ??
  5.                 DMA2->HIFCR = (uint32_t)(DMA_IT_HTIF5 & RESERVED_MASK);
  6.         }
复制代码

/*---------打印信息------------*/
00:00:00: HT IRQ n=15
00:00:00: Start sed n=32
00:00:00: GPIO_DMA_cfg init ok
发现:半中断后,数据量寄存器并没有等于 32/2=16.注: 配置没用 FIFO。
这个应该是在读取 NDTR寄存器时,继续传送了。导致读取那一刻的值小于 16.

Inc_brza 回答时间:2018-1-16 19:00:01
再DMA传输要结束的时候,接入1个BUF再传输一遍,但是BUF里的数据是0,然后尽可能以最直接的速度关闭DMA

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

zero99 回答时间:2018-1-17 08:56:16
小温点秋香 发表于 2018-1-16 16:51
Done !
你好, 怎么在论坛里邀请,ST技术答疑呢?

大家会帮忙回答的,如果没有我会在签到帖里悬赏
小温点秋香 回答时间:2018-1-17 17:49:49
Inc_brza 发表于 2018-1-16 19:00
再DMA传输要结束的时候,接入1个BUF再传输一遍,但是BUF里的数据是0,然后尽可能以最直接的速度关闭DMA ...

试过了。 问题是发送100个数据,实际只有50个。
DMA控制的GPIO输出频率怎么调节。 我尝试调节TIM1,更新频率。逻辑分析仪得到 IO翻转变快了。道理上说不通。按理说,TIM更新变快只改变 DMA传送次数变快,难道还会改变每次发送的bit更快?horrible!
无薪税绵 回答时间:2018-1-24 10:39:49
问题1,看看DMA2中断内cnt的作用,我看不出它有什么作用。
问题2,建议在DMA2的中断内,开启一个计时器中断,用计时器调用移位函数,这样速度会比在主程序调用要快。

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

12下一页

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版