打印
[应用相关]

香版能否说下ADC是用什么条件触发DMA的?

[复制链接]
950|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
GZZXB|  楼主 | 2020-1-13 17:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    ADC是怎么通知DMA可以搬运了,或者说DMA怎么知道有数据可以搬运了。
我详细描述下我的测试,  用一个TIM产生一个50us的时标去定时触发ADC转换(用的是更新事件触发),ADC和DMA连接。 DMA正常传输模式(非循环模式),传输完512个数据后产生传输完成中断并将一个标志置位。   应用层监视这个标志,当检查到标志被置位时,说明采集到了512个数据。将数据处理后,置位TIM的UG事件(此时应该会立即产生一个更新事件,ADC有可能被触发开始转换) --》 清除TIM触发源--》判断ADC是否在空闲,如果不在空闲就等到空闲--》 清除ADC转换完成标志位 --》 失能DMA 重设DMA 源地址、目标地址、数量--》 使能DMA.
   仿真现象是 一使能DMA 就立即搬运了一次数据。按理说应该延时50us才会搬运首次数据才对,因为置位UG后触发ADC的TIM是从0开始计数的,需要计数到溢出才会触发ADC转换。我想不明白的是  TIM已经复位从0开始计数了,TIM触发源也被清除掉了,ADC转换完成标志也被清除掉了。还有什么原因导致DMA立即搬运了一个数据,而不是等待TIM触发才搬运。

使用特权

评论回复
沙发
mmuuss586| | 2020-1-16 09:46 | 只看该作者

使用特权

评论回复
板凳
renzheshengui| | 2020-2-5 08:19 | 只看该作者
帮楼主顶一下吧

使用特权

评论回复
地板
香水城| | 2020-2-5 23:58 | 只看该作者
本帖最后由 香水城 于 2020-2-6 10:03 编辑

应该说你到底是用什么事件触发DMA的。

因为看不到你的代码,感觉是通过定时器的更新事件触发的DMA。

建议你在使能定时器的初始化完成后 紧跟着加一句 更新事件标志位的清零操作。

比方像这样:
        __HAL_TIM_CLEAR_IT(&htimx, TIM_IT_UPDATE);
   

这样做的目的 以保证使能DMA的时候不会立即被更新事件触发传输。

所以建议TIMER的初始化动作 放在使能DMA的前面。

使用特权

评论回复
5
GZZXB|  楼主 | 2020-2-10 16:07 | 只看该作者
香水城 发表于 2020-2-5 23:58
应该说你到底是用什么事件触发DMA的。

因为看不到你的代码,感觉是通过定时器的更新事件触发的DMA。

     是用TIMER触发ADC,然后ADC再产生DMA请求。 因为DMA是工作在正常模式,在传输完后必须要重新设置计数器后才会继续传输。  那么继续下一轮传输前就要把原来潜伏的DMA请求清除掉。我问的问题是在后续正常运行中,而不是刚跑起来的时候,那么和初始化无关了。
     1.TIMER是触发ADC  ADSTART位的吧? 只要TIMER一产生触发事件就会自动将 ADSTART=1开启ADC转换吧?这个应该是无法控制,因为是硬件实现。并不是说将溢出标志清除就不会设置 ADSTART。
     2.ADC转换完成后就会产生DMA请求,这个请求是否一直潜伏着? 如果一直潜伏着那么我一重设DMA时,就会立即响应这个请求。 如何才能在重设DMA计数器前把这个潜伏的DMA请求“清除掉”?
     3. 想实现的目标:  DMA一轮传输完进入DMA中断 --》把定时器计数失能并清0(在这个操作中有可能已经触发了一次ADC转换)--》 等待ADC转换完毕,清除ADC的DMA请求--》重新设置DMA的下一轮传输。
     4.读ADC_DR寄存器是否可以清除掉ADC的DMA请求? 没有在官方文档中找到答案。

使用特权

评论回复
6
香水城| | 2020-2-11 19:16 | 只看该作者
本帖最后由 香水城 于 2020-2-11 19:35 编辑
GZZXB 发表于 2020-2-10 16:07
是用TIMER触发ADC,然后ADC再产生DMA请求。 因为DMA是工作在正常模式,在传输完后必须要重新设置计 ...

我一开始怀疑初始化方面的问题 是因为你说“ 一使能DMA 就立即搬运了一次数据”。
即TIMER的更新事件==》启动ADC,产生EOC==》使能DMA,做一次数据转换。

另外就你的几个问题继续交流下:
1、你如果配置TIMER触发ADC,就是通过定时器事件启动ADC转换,即置位ADSTART位。整个过程
的确是硬件在控制。  但是,如果定时器初始化过程中的产生的更新标志没有先行清除的话,当后续的ADC/DMA配置好后,完全可能会你一使能DMA就触发一次DMA传输,过程就是上面所说的。

2、如果发生ADC转换,产生ADC转换事件了,肯定会触发DMA传输。不会有潜伏的说法。因为你现在是ADC事件触发DMA传输。

3、基于你要实现的目标,目前的DMA是Normal模式,进入DMA传输完成中断后,为了后续的
新一轮转换需再做些准备。关于定时器,如果不修改时间参数的话,你只需在关闭计数器并对计数器清零即可。在这个过程中,还有可能额外触发了ADC,此时由于DMA已经停掉,所以是不会发生DMA传输,但可能EOC事件发生了,这时我们有必要对EOC做个清零动作。否则这个EOC将来就是个隐患。至于这个清零,我们可以通过读AD_DR或直接对该位清零。

4、读ADC_DR寄存器是可以达到清除此应用时的DMA请求的,原因是:这里的DMA请求来自EOC事件,而读ADC_DR可以对EOC清零,从而达到清除DMA请求的作用。官方手册肯定没法写到这个点了,你把握相关原理了就能自行判断了。

再回过头来看上面的第2点,按照你目前的应用,发生了ADC转换,若此时DMA因Normal模式传输结束而停掉了。这时的EOC就得额外处理了,难怪你提到潜伏二字。怎么处理在第3点已经说明了。



使用特权

评论回复
7
wangjiahao88| | 2020-2-11 19:52 | 只看该作者
这个问题,真没有仔细的考虑过。。。就是从淘宝的开发板的例程,胡乱的复制一通……

使用特权

评论回复
8
wangjiahao88| | 2020-2-11 19:53 | 只看该作者
我以为只有深入到一些苛刻的操作的时候,才会考虑这种问题。。。

使用特权

评论回复
9
GZZXB|  楼主 | 2020-2-12 15:56 | 只看该作者
香水城 发表于 2020-2-11 19:16
我一开始怀疑初始化方面的问题 是因为你说“ 一使能DMA 就立即搬运了一次数据”。
即TIMER的更新事件==》 ...

   非常感谢香版的回复!
我说“ 一使能DMA 就立即搬运了一次数据”。  这个指的是下一轮传输的使能,开启下一轮数据传输时必须先关闭DMA重设源地址目的地址及计数器--》 再使能DMA(我说的是这个时候的 “一使能”)。我做了测试在DMA中断中延时一阵子再关闭TIMER 故意制造一个ADC转换,同时将DmaBuf清空,然后用读AD_DR和不读只清除EOC来测试。 体现出来的结果是读AD_DR后再使能DMA,DmaBuf依然为空可以认为是将这个DMA请求给清除掉了。而单用软件对EOC该位写1 后再使能DmaBuf还是被填充了个数据,是否可以认为这个请求还是在?  从而猜测这个DMA请求是否靠有效数据是否被读取来决定呢?   另外我之所以说潜伏这个词,是因为在ADC的触发源描述中有提到上升沿和下降源之类的触发选择,而想当然的认为DMA也是被脉冲触发不存在一直有效。 我说潜伏的意思是想说这个请求只要没有被DMA处理那么就一直存在。

使用特权

评论回复
10
香水城| | 2020-2-13 15:49 | 只看该作者
本帖最后由 香水城 于 2020-2-14 22:04 编辑

不必客气!

你说的下一轮DMA传输过程中,一使能DMA就传输一个数据可以肯定是那个EOC事件触发的。该EOC事件就是你进DMA完成中断
去关定时器 但未关闭之前 由定时器额外触发的ADC转换。建议你关闭定时器后,稍作延时后对ADC的EOC和OVR位都做下清零。
再做后续DMA的相关配置。【我看你在启动第2次DMA之前并没有对定时器的关闭操作,你只是做了个复位,建议你先关闭。一切整理、
配置妥当后,在使能DMA前再启动计数器】

对于你这里的应用,DMA请求终究是来自EOC事件,或者说EOC的置1状态。 因为ADC数据的被读取会影响EOC状态,从而影响
DMA请求的存在与否。所以,你说“DMA请求是否靠有效数据是否被读取来决定”也没啥大问题。 因为EOC的清零要么ADC数据
被读取,要么手动去清零【这个操作你这里可以排除】。


另外,你说的软件对EOC写1,不知你是怎么操作的。该位根本不能被用户写1的啊?

使用特权

评论回复
11
GZZXB|  楼主 | 2020-2-17 14:27 | 只看该作者
香水城 发表于 2020-2-13 15:49
不必客气!

你说的下一轮DMA传输过程中,一使能DMA就传输一个数据可以肯定是那个EOC事件触发的。该EOC事件 ...

  Bit 2 EOC: End of conversion flag
This bit is set by hardware at the end of each conversion of a channel when a new data result is
available in the ADC_DR register. It is cleared by software writing 1 to it or by reading the ADC_DR
register.
0: Channel conversion not complete (or the flag event was already acknowledged and cleared by
software)
1: Channel conversion complete

不是说写1清0吗?

使用特权

评论回复
12
香水城| | 2020-2-17 15:13 | 只看该作者
呵呵!
你是写1清零啊! 那好理解。 我理解成你对EOC置位了。

不知你问题怎么样了。 我模拟你的应用做了测试,可能遇到你发生的问题,应该是代码方面需完善。

使用特权

评论回复
13
香水城| | 2020-2-17 15:19 | 只看该作者
/* Enable ADC DMA mode */
    hadc1.Instance->CR2 |= ADC_CR2_DMA; //Enable ADC DMA function
   
    HAL_DMA_Start_IT(&hdma_adc1, (uint32_t)&hadc1.Instance->DR, (uint32_t)Adc_data1, 3);

    __HAL_TIM_ENABLE(&htim2); //start counter
     
    while(!Flag_DMA_over) //waite for 3 ADC data tranfer to be completed
     {
     }   
     
      Flag_DMA_over =00;
      __HAL_TIM_DISABLE(&htim2); //turn off counter
   
       TIM2->EGR = TIM_EGR_UG;  // reset timer manually
           
     hadc1.Instance->CR2 &= ~ADC_CR2_DMA;  //Disable ADC DMA  
     
     __HAL_DMA_DISABLE(&hdma_adc1);   //Disable DMA2 stream 0   
      
       while(!(__HAL_ADC_GET_FLAG(&hadc1, ADC_FLAG_EOC)));
   
     __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_EOC | ADC_FLAG_OVR); //Clear EOC/OVR
         
    HAL_DMA_Start_IT(&hdma_adc1, (uint32_t)&hadc1.Instance->DR, (uint32_t)Adc_data2, 5);
         
    hadc1.Instance->CR2 |= ADC_CR2_DMA;   ////Enable ADC DMA
   
    __HAL_TIM_ENABLE(&htim2);
  /* USER CODE END 2 */
  /* USER CODE BEGIN WHILE */
  while (1)
  {}

。。。}

使用特权

评论回复
14
GZZXB|  楼主 | 2020-2-17 20:59 | 只看该作者
香水城 发表于 2020-2-17 15:19
/* Enable ADC DMA mode */
    hadc1.Instance->CR2 |= ADC_CR2_DMA; //Enable ADC DMA function
   

   我是用标准库,hal不熟
hadc1.Instance->CR2 &= ~ADC_CR2_DMA;  //Disable ADC DMA  
hadc1.Instance->CR2 |= ADC_CR2_DMA;   ////Enable ADC DMA
以上两句代码是否可以不用?就让ADC DMA连接一直有效没有什么影响吧?

因为后续是先清除了EOC
__HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_EOC | ADC_FLAG_OVR); //Clear EOC/OVR
接下来才使能DMA
HAL_DMA_Start_IT(&hdma_adc1, (uint32_t)&hadc1.Instance->DR, (uint32_t)Adc_data2, 5);

如你所说就算前面ADC DMA有效,就算产生了DMA请求。 但是只要一执行 //Clear EOC/OVR 语句就都清除掉了。后面使能DMA已经确定没有历史请求存在了。

使用特权

评论回复
15
香水城| | 2020-2-17 23:56 | 只看该作者
GZZXB 发表于 2020-2-17 20:59
我是用标准库,hal不熟
hadc1.Instance->CR2 &= ~ADC_CR2_DMA;  //Disable ADC DMA  
hadc1 ...

用什么库不重要,你尝试将我给你的代码看懂吧。

我不知你的到底怎么写的。可以肯定是EOC事件触发了DMA.

你好好琢磨下你的清EOC的相关代码的有效性。 就你的应用场景我都测试验证过了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

96

主题

331

帖子

10

粉丝