本帖最后由 黑皮男 于 2018-3-2 11:49 编辑 最近用NUCLEO-F303RE搞了一下TIM1的DMA方式产生固定脉冲。但是参考官方的配置中有一个很不解的地方。在初始化的时候,EGR的UG位被设置了两次,虽然有注释,但实在是不解。DMA启动第一次传输是不是在UG被第一次置位的时候?请各位指点一下。 下面是官方手册的配置 DMA configuration /* DMA1 clock enable */ RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* Configure DMA1 Channel5 CR register */ /* Reset DMA1 Channel5 control register */ DMA1_Channel5->CCR = 0; /* Set CHSEL bits according to DMA Channel 5 */ /* Set DIR bits according to Memory to peripheral direction */ /* Set PINC bit according to DMA Peripheral Increment Disable */ /* Set MINC bit according to DMA Memory Increment Enable */ /* Set PSIZE bits according to Peripheral DataSize = Word */ /* Set MSIZE bits according to Memory DataSize Word */ /* Set CIRC bit according to circular mode */ /* Set PL bits according to very high priority */ /* Set MBURST bits according to single memory burst */ /* Set PBURST bits according to single peripheral burst */ DMA1_Channel5->CCR |= DMA_MEMORY_TO_PERIPH | DMA_PINC_DISABLE| DMA_MINC_ENABLE| DMA_PDATAALIGN_WORD| DMA_MDATAALIGN_WORD | DMA_CIRCULAR | DMA_PRIORITY_HIGH; /* Write to DMA1 Channel5 number of data’s register */ DMA1_Channel5->CNDTR = 9; /* Write to DMA1 Channel5 peripheral address register */ DMA1_Channel5->CPAR = (uint32_t)TIM1_DMAR_ADDRESS; /* Write to DMA1 Channel5 Memory address register */ /* Set the address to the memory buffer “aSRC_Buffer” */ DMA1_Channel5->CMAR = (uint32_t)aSRC_Buffer; /* Enable DMA1 Channel5 */ DMA1_Channel5->CCR |= (uint32_t)DMA_CCR_EN; 复制代码• TIM1 configuration /* set the Timer prescaler */ Tim1Prescaler= (uint16_t) (SystemCoreClock / 32000000) - 1; /* Configure the period */ TIM1->ARR = 0xFFFF; /* Configure the Timer prescaler */ TIM1->PSC = Tim1Prescaler; /* Configure pulse width */ TIM1->CCR1 = 0xFFF; /* Select the ClockDivison to 1 */ /* Reset clockDivision bit field */ TIM1->CR1 &= ~ TIM_CR1_CKD; /* Select DIV1 as clock division*/ TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1; /* Select the Up-counting for TIM1 counter */ /* Reset mode selection bit fiels*/ TIM1->CR1 &= ~( TIM_CR1_DIR | TIM_CR1_CMS); /* selct Up-counting mode */ TIM1->CR1 |= TIM_COUNTERMODE_UP; /* SET PWM1 mode */ /* Reset the Output Compare Mode Bits */ TIM1->CCMR1 &= ~TIM_CCMR1_OC1M; TIM1->CCMR1 &= ~TIM_CCMR1_CC1S; /* Select the output compare mode 1*/ TIM1->CCMR1 |= TIM_OCMODE_PWM1; /* Enable the output compare 1 Preload */ TIM1->CCMR1 |= TIM_CCMR1_OC1PE; /* Enable auto-reload Preload */ TIM1->CR1 |= TIM_CR1_ARPE; /* TIM1 DMA Update enable */ TIM1->DIER |= TIM_DMA_UPDATE; /* Configure of the DMA Base register and the DMA Burst Length */ /* Reset DBA and DBL bit fields */ TIM1->DCR &= ~TIM_DCR_DBA; TIM1->DCR &= ~TIM_DCR_DBL; /* Select the DMA base register and DMA burst length */ TIM1->DCR = TIM_DMABase_ARR | TIM_DMABurstLength_3Transfers; /* Enable UEV by setting UG bit to Load buffer data into preload registers */ TIM1->EGR |= TIM_EGR_UG; /* wait until the RESET of UG bit*/ while((TIM1->EGR & TIM_EGR_UG) == SET){} /* Enable UEV by setting UG bit to load data from preload to active registers */ TIM1->EGR |= TIM_EGR_UG; /* Enable the TIM1 Main Output */ TIM1->BDTR |= TIM_BDTR_MOE; /* Enable CC1 output*/ TIM1->CCER |= TIM_CCER_CC1E; /* Enable the TIM Counter */ TIM1->CR1 |= TIM_CR1_CEN;复制代码
起用了缓存,你的第29行用了,TIM1->CR1 |= TIM_CR1_ARPE;
因此,就像注释38行、43行说的那样,第一次是把数据从buffer加载到preload寄存器,第二次是把preload寄存器中的数据加载到active寄存器寄存器。
评分
查看全部评分
评分
查看全部评分
UG位是事件更新位,由软件置1,硬件自动清零。
当置1时,重新初始化定时器计数器并生成寄存器的更新。
请注意预分频计数器也被清零(但预分频比不受影响)。
我个人理解为:刚上电时,TIM1_EGR的数据全为零,
通过UG位置1来判断系统预加载是否已经完成。
而第二次 TIM1->EGR |= TIM_EGR_UG;
是为了计数器清零的。
评分
查看全部评分
你说的这个频率不能很高,太高的话中断响应不过来,不过高级定时器的话可以达到很高频率,但是频率切换之间的时间间隔会相对较长
按理来说,两次置位UG的效果应该相同,都会重新开始计数吧。有点迷惑。还有一个问题就是定时器刚启动的时候,DMA传输是在定时器启动前还是第一次计数溢出后开始传输的,还是定时器启动前才开始传输的,从现象来看,启动前就已经出发了传输。
所以一般在程序启动时,会加入一定的延时时间,
作为让系统稳定的过程。
而第一次UG置位,正常情况下是相当于清零,
但是也是防止系统未预加载成功时,作为延时用的。
第二次置位,其实就是纯淬的清零动作了。
你可以试试,注释掉第二句,其实也是可以运行的,
只是在特殊的情况下(比如:未预加载成功时),
就会出现问题了。
第二个问题,其实toofree大神已经解释的很清楚了:
DMA启动传输应该是UG被第二次置位的时候。
第一次是把数据从buffer加载到preload寄存器,
第二次是把preload寄存器中的数据加载到active寄存器寄存器。
评分
查看全部评分