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

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