
STM32F103C8T6 TIM1 CH2输入捕获触发DMA的问题 最近在基于STM32F103C8T6同时使用LL库调试 TIM1 CH2输入捕获触发DMA的时候遇到点问题: 我的期望是,通过TIM1 CH2捕获到上升沿后,触发DMA传输,将内存数据搬运到TIM1 CCR1寄存器,以修改PWM占空比; 现状是: 1.DMA TC中断远比我想象来的慢,表现为触发脉冲以及经过数十个后,才能进入一次TC中断; 2.在整个过程中TIM1 CCR1寄存器的值没有改变,那为什么还会触发DMA TC中断呢?整个过程中传输的数据去哪了? 3.在DMA请求映像中 DMA1 CH3可以被TIM1 CH2所触发,但是在CUBEMX中却没有对应的配置,是否意味着这样操作不可行亦或是CUBEMX本身的问题? 期待路过的诸位能帮忙解答,不胜感激! 相关代码如下: “/* TIM1 init function */void MX_TIM1_Init(void){ /* USER CODE BEGIN TIM1_Init 0 */ /* USER CODE END TIM1_Init 0 */ LL_TIM_InitTypeDef TIM_InitStruct = {0}; LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; LL_TIM_BDTR_InitTypeDef TIM_BDTRInitStruct = {0}; LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; /* Peripheral clock enable */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1); LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA); /**TIM1 GPIO Configuration PA9 ------> TIM1_CH2 */ GPIO_InitStruct.Pin = LL_GPIO_PIN_9; GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING; LL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN TIM1_Init 1 */ /* USER CODE END TIM1_Init 1 */ TIM_InitStruct.Prescaler = 0; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.Autoreload = 2; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; TIM_InitStruct.RepetitionCounter = 0; LL_TIM_Init(TIM1, &TIM_InitStruct); LL_TIM_EnableARRPreload(TIM1); LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL); LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1); TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1; TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE; TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE; TIM_OC_InitStruct.CompareValue = 0; TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; TIM_OC_InitStruct.OCNPolarity = LL_TIM_OCPOLARITY_HIGH; TIM_OC_InitStruct.OCIdleState = LL_TIM_OCIDLESTATE_LOW; TIM_OC_InitStruct.OCNIdleState = LL_TIM_OCIDLESTATE_LOW; LL_TIM_OC_Init(TIM1, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct); LL_TIM_OC_EnableFast(TIM1, LL_TIM_CHANNEL_CH1); LL_TIM_SetTriggerInput(TIM1, LL_TIM_TS_TI2FP2); LL_TIM_SetSlaveMode(TIM1, LL_TIM_SLAVEMODE_RESET); LL_TIM_CC_DisableChannel(TIM1, LL_TIM_CHANNEL_CH2); LL_TIM_IC_SetFilter(TIM1, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); LL_TIM_IC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING); LL_TIM_DisableIT_TRIG(TIM1); LL_TIM_DisableDMAReq_TRIG(TIM1); LL_TIM_SetTriggerOutput(TIM1, LL_TIM_TRGO_RESET); LL_TIM_DisableMasterSlaveMode(TIM1); LL_TIM_IC_SetActiveInput(TIM1, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI); LL_TIM_IC_SetPrescaler(TIM1, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); TIM_BDTRInitStruct.OSSRState = LL_TIM_OSSR_DISABLE; TIM_BDTRInitStruct.OSSIState = LL_TIM_OSSI_DISABLE; TIM_BDTRInitStruct.LockLevel = LL_TIM_LOCKLEVEL_OFF; TIM_BDTRInitStruct.DeadTime = 0; TIM_BDTRInitStruct.BreakState = LL_TIM_BREAK_DISABLE; TIM_BDTRInitStruct.BreakPolarity = LL_TIM_BREAK_POLARITY_LOW; TIM_BDTRInitStruct.AutomaticOutput = LL_TIM_AUTOMATICOUTPUT_DISABLE; LL_TIM_BDTR_Init(TIM1, &TIM_BDTRInitStruct); /* USER CODE BEGIN TIM1_Init 2 */ /* TIM1 OC配置修正 */ TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; // 启用主通道 TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_ENABLE; // 启用互补通道 LL_TIM_OC_Init(TIM1, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct); LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH2);// 启用TIM1通道2的捕获功能/* DMA触发配置修正 */ LL_TIM_SetSlaveMode(TIM1, LL_TIM_SLAVEMODE_TRIGGER); LL_TIM_DisableDMAReq_UPDATE(TIM1); LL_TIM_EnableDMAReq_CC2(TIM1); // 使用通道2的捕获事件触发DMA LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3, LL_DMA_DIRECTION_PERIPH_TO_MEMORY); LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PRIORITY_LOW); LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MODE_CIRCULAR); LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PERIPH_NOINCREMENT); LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MEMORY_INCREMENT); LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_BYTE); LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_BYTE); LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_3, (uint32_t)&TIM1->CCR1); LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_3, (uint32_t)line_buffer0); LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_3, (sizeof(line_buffer0) / sizeof(line_buffer0[0]))); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_3); LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_3); NVIC_SetPriority(DMA1_Channel3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); NVIC_EnableIRQ(DMA1_Channel3_IRQn); LL_TIM_EnableAllOutputs(TIM1); LL_TIM_EnableCounter(TIM1); /* USER CODE END TIM1_Init 2 */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB); LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA); /**TIM1 GPIO Configuration PB13 ------> TIM1_CH1N PA8 ------> TIM1_CH1 */ GPIO_InitStruct.Pin = CURSOR_Pin; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; LL_GPIO_Init(CURSOR_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = CROSSHAIR_Pin; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; LL_GPIO_Init(CROSSHAIR_GPIO_Port, &GPIO_InitStruct); }” |
触发波形
STM32的低功耗模式
四轴飞行器
不清楚为什么正点原子的例程,想添加SCB添加到watch1却是无效的(在core_cm3.h定义的寄存器都不可以),但是可以添加GPIOA并且有效(stm32f10x.h定义的寄存器都可以)
不知道为什么用正点原子的开源例程硬件仿真时。想观察寄存器的值,所以添加到watch1观察,不清楚为啥SCB,NVTC等都添加了但是无效,但是GPIOA却又可以。
STM32的上电启动过程
STM32中如何实现数据加密
STM32的I2S外设
为何Tim2自动装载定时的首次中断时间总是设定时间的2倍?
如何提高开发板的抗干扰能力?
Keil编译为何慢?
这里就你的问题逐一做些交流:
1.DMA TC中断远比我想象来的慢,表现为触发脉冲以及经过数十个后,才能进入一次TC中断;
==》应该没有这个说法。DMA TC中断基于DMA传输完成事件而产生,它的快慢跟一轮传输中请求个数和快慢有关。
比方一轮传输涉及5个请求和50个请求的TC产生时间自然不一样,每1秒产生1个请求和每10秒产生1个请求使得最终产生DMA TC事件的时间肯定也不一样。
具体到你这里,到底触发几次后进TC中断是你决定的。当然,前提是DMA已经正常工作了。
2.在整个过程中TIM1 CCR1寄存器的值没有改变,那为什么还会触发DMA TC中断呢?整个过程中传输的数据去哪了?
==》这个要具体看。首先要看硬件上是否支持,即所选择的DMA通道是否能前往源端和目的端。如果硬件上支持而你实际上又没实现,那就得检查你的配置。
我这边查阅了技术手册相关内容,硬件是支持的。那么问题可能就出在你的配置方面。
3.在DMA请求映像中 DMA1 CH3可以被TIM1 CH2所触发,但是在CUBEMX中却没有对应的配置,是否意味着这样操作不可行亦或是CUBEMX本身的问题?
==》估计你看漏了,或者是哪里理解错了。使用cubeMx配置,可以看到基于TIM1-CH2事件所申请的DMA通道正是DMA1-CH3.
针对上面第2点,我找到F1系列开发板做了进一步验证确认,的确是可以实现的。即TIM1-CH2的捕获事件触发DMA,DMA将内存数据搬运到TIM1-CCR1寄存器以调整PWM输出。我使用HAL库验证,而不是LL库。验证结果可以给你信心。这里特意提醒的是,DMA的源端、目的端别配置错了,尤其是别配反了。
我这里基于CH2的捕获事件触发DMA传输,DMA做4次传输后就 停下,那么CCR1的数据应该停止0x12ab。
另外改变CCR去调整PWM,不能立刻生效,否则会引起脉冲过长或过短。 通常都是用更新事件触发的。
感谢!
请问你的意思是通过TI2FP2捕获,产生更新事件,之后由更新事件触发DMA,将内存数据写入CCR1寄存器吗?