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

关于TIM1 DMA方式产生单次固定不同频率脉冲不解

[复制链接]
黑皮男 提问时间:2018-3-2 11:47 /
15ST金币
本帖最后由 黑皮男 于 2018-3-2 11:49 编辑

最近用NUCLEO-F303RE搞了一下TIM1的DMA方式产生固定脉冲。但是参考官方的配置中有一个很不解的地方。在初始化的时候,EGR的UG位被设置了两次,虽然有注释,但实在是不解。DMA启动第一次传输是不是在UG被第一次置位的时候?请各位指点一下。
下面是官方手册的配置
DMA configuration

  1. /* DMA1 clock enable */
  2. RCC->AHBENR |= RCC_AHBENR_DMA1EN;
  3. /* Configure DMA1 Channel5 CR register */
  4. /* Reset DMA1 Channel5 control register */
  5. DMA1_Channel5->CCR = 0;
  6. /* Set CHSEL bits according to DMA Channel 5 */
  7. /* Set DIR bits according to Memory to peripheral direction */
  8. /* Set PINC bit according to DMA Peripheral Increment Disable */
  9. /* Set MINC bit according to DMA Memory Increment Enable */
  10. /* Set PSIZE bits according to Peripheral DataSize = Word */
  11. /* Set MSIZE bits according to Memory DataSize Word */
  12. /* Set CIRC bit according to circular mode */
  13. /* Set PL bits according to very high priority */
  14. /* Set MBURST bits according to single memory burst */
  15. /* Set PBURST bits according to single peripheral burst */
  16. DMA1_Channel5->CCR |= DMA_MEMORY_TO_PERIPH |
  17. DMA_PINC_DISABLE| DMA_MINC_ENABLE|
  18. DMA_PDATAALIGN_WORD| DMA_MDATAALIGN_WORD |
  19. DMA_CIRCULAR | DMA_PRIORITY_HIGH;
  20. /* Write to DMA1 Channel5 number of data’s register */
  21. DMA1_Channel5->CNDTR = 9;
  22. /* Write to DMA1 Channel5 peripheral address register */
  23. DMA1_Channel5->CPAR = (uint32_t)TIM1_DMAR_ADDRESS;
  24. /* Write to DMA1 Channel5 Memory address register */
  25. /* Set the address to the memory buffer “aSRC_Buffer” */
  26. DMA1_Channel5->CMAR = (uint32_t)aSRC_Buffer;
  27. /* Enable DMA1 Channel5 */
  28. DMA1_Channel5->CCR |= (uint32_t)DMA_CCR_EN;

复制代码
• TIM1 configuration  

  1. /* set the Timer prescaler */
  2. Tim1Prescaler= (uint16_t) (SystemCoreClock / 32000000) - 1;
  3. /* Configure the period */
  4. TIM1->ARR = 0xFFFF;
  5. /* Configure the Timer prescaler */
  6. TIM1->PSC = Tim1Prescaler;
  7. /* Configure pulse width */
  8. TIM1->CCR1 = 0xFFF;
  9. /* Select the ClockDivison to 1 */
  10. /* Reset clockDivision bit field */
  11. TIM1->CR1 &= ~ TIM_CR1_CKD;
  12. /* Select DIV1 as clock division*/
  13. TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1;
  14. /* Select the Up-counting for TIM1 counter */
  15. /* Reset mode selection bit fiels*/
  16. TIM1->CR1 &= ~( TIM_CR1_DIR | TIM_CR1_CMS);
  17. /* selct Up-counting mode */
  18. TIM1->CR1 |= TIM_COUNTERMODE_UP;
  19. /* SET PWM1 mode */
  20. /* Reset the Output Compare Mode Bits */
  21. TIM1->CCMR1 &= ~TIM_CCMR1_OC1M;
  22. TIM1->CCMR1 &= ~TIM_CCMR1_CC1S;
  23. /* Select the output compare mode 1*/
  24. TIM1->CCMR1 |= TIM_OCMODE_PWM1;
  25. /* Enable the output compare 1 Preload */
  26. TIM1->CCMR1 |= TIM_CCMR1_OC1PE;
  27. /* Enable auto-reload Preload */
  28. TIM1->CR1 |= TIM_CR1_ARPE;
  29. /* TIM1 DMA Update enable */
  30. TIM1->DIER |= TIM_DMA_UPDATE;
  31. /* Configure of the DMA Base register and the DMA Burst Length */
  32. /* Reset DBA and DBL bit fields */
  33. TIM1->DCR &= ~TIM_DCR_DBA;
  34. TIM1->DCR &= ~TIM_DCR_DBL;
  35. /* Select the DMA base register and DMA burst length */
  36. TIM1->DCR = TIM_DMABase_ARR | TIM_DMABurstLength_3Transfers;
  37. /* Enable UEV by setting UG bit to Load buffer data into preload registers
  38. */
  39. TIM1->EGR |= TIM_EGR_UG;
  40. /* wait until the RESET of UG bit*/
  41. while((TIM1->EGR & TIM_EGR_UG) == SET){}
  42. /* Enable UEV by setting UG bit to load data from preload to active
  43. registers */
  44. TIM1->EGR |= TIM_EGR_UG;
  45. /* Enable the TIM1 Main Output */
  46. TIM1->BDTR |= TIM_BDTR_MOE;
  47. /* Enable CC1 output*/
  48. TIM1->CCER |= TIM_CCER_CC1E;
  49. /* Enable the TIM Counter */
  50. TIM1->CR1 |= TIM_CR1_CEN;
复制代码


最佳答案

查看完整内容

DMA启动传输应该是UG被第二次置位的时候。 起用了缓存,你的第29行用了,TIM1->CR1 |= TIM_CR1_ARPE; 因此,就像注释38行、43行说的那样,第一次是把数据从buffer加载到preload寄存器,第二次是把preload寄存器中的数据加载到active寄存器寄存器。
收藏 1 评论6 发布时间:2018-3-2 11:47

举报

6个回答
七哥 回答时间:2018-3-2 11:48:00
DMA启动传输应该是UG被第二次置位的时候。
起用了缓存,你的第29行用了,TIM1->CR1 |= TIM_CR1_ARPE;
因此,就像注释38行、43行说的那样,第一次是把数据从buffer加载到preload寄存器,第二次是把preload寄存器中的数据加载到active寄存器寄存器。


傲游截图20180307095701.png

评分

参与人数 2ST金币 +10 蝴蝶豆 +3 收起 理由
黑皮男 + 10 确实有道理
zero99 + 3

查看全部评分

zhjb1 回答时间:2018-3-7 09:09:09
看的好复杂。采用Tick[Timer也可]中断产生脉冲比这个简单多了,并且频率仅由Tick控制。想想是吗?

评分

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

查看全部评分

无薪税绵 回答时间:2018-3-7 10:31:44
TIM1_EGR为事件触发寄存器。
UG位是事件更新位,由软件置1,硬件自动清零。
当置1时,重新初始化定时器计数器并生成寄存器的更新。
请注意预分频计数器也被清零(但预分频比不受影响)。

我个人理解为:刚上电时,TIM1_EGR的数据全为零,
通过UG位置1来判断系统预加载是否已经完成。

而第二次 TIM1->EGR |= TIM_EGR_UG; 
是为了计数器清零的。

评分

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

查看全部评分

黑皮男 回答时间:2018-3-7 14:56:16
zhjb1 发表于 2018-3-7 09:09
看的好复杂。采用Tick[Timer也可]中断产生脉冲比这个简单多了,并且频率仅由Tick控制。想想是吗? ...

你说的这个频率不能很高,太高的话中断响应不过来,不过高级定时器的话可以达到很高频率,但是频率切换之间的时间间隔会相对较长
黑皮男 回答时间:2018-3-8 11:25:09
无薪税绵 发表于 2018-3-7 10:31
TIM1_EGR为事件触发寄存器。
UG位是事件更新位,由软件置1,硬件自动清零。
当置1时,重新初始化定时器计 ...

按理来说,两次置位UG的效果应该相同,都会重新开始计数吧。有点迷惑。还有一个问题就是定时器刚启动的时候,DMA传输是在定时器启动前还是第一次计数溢出后开始传输的,还是定时器启动前才开始传输的,从现象来看,启动前就已经出发了传输。
无薪税绵 回答时间:2018-3-8 13:05:58
硬件刚上电时,其电压尚未稳定,系统时钟也未稳定,
所以一般在程序启动时,会加入一定的延时时间,
作为让系统稳定的过程。

而第一次UG置位,正常情况下是相当于清零,
但是也是防止系统未预加载成功时,作为延时用的。

第二次置位,其实就是纯淬的清零动作了。

你可以试试,注释掉第二句,其实也是可以运行的,
只是在特殊的情况下(比如:未预加载成功时),
就会出现问题了。


第二个问题,其实toofree大神已经解释的很清楚了:
DMA启动传输应该是UG被第二次置位的时候。
第一次是把数据从buffer加载到preload寄存器,
第二次是把preload寄存器中的数据加载到active寄存器寄存器。

评分

参与人数 2ST金币 +5 蝴蝶豆 +4 收起 理由
黑皮男 + 5 非常感谢
zero99 + 4

查看全部评分

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版