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

STM32F103C8T6 TIM1 CH2输入捕获触发DMA的问题

[复制链接]
托卡马克 提问时间:2025-2-20 11:36 / 未解决
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);
}”

触发波形

触发波形
屏幕截图 2025-02-20 113306.png
收藏 评论3 发布时间:2025-2-20 11:36

举报

3个回答
xmshao 回答时间:前天 14:57
对于你的需求,“通过TIM1 CH2捕获到上升沿后,触发DMA传输,将内存数据搬运到TIM1 CCR1寄存器,以修改PWM占空比” ,原理上讲是可以实现的。


这里就你的问题逐一做些交流:


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。
butterflyspring 回答时间:前天 12:01
从思路上看,DMA的request 就受限的。 定时器1的通道2 的DMA request 只有从该寄存器捕获值到内存,或内存到CCR2 寄存器。  或者说传递到CCR1的request没有CH2 捕获的RQUEST。 因此硬件不支持。


另外改变CCR去调整PWM,不能立刻生效,否则会引起脉冲过长或过短。 通常都是用更新事件触发的。

TIMER1 CH DMA mode.PNG
托卡马克 回答时间:前天 13:11

butterflyspring 发表于 2025-2-20 12:01
从思路上看,DMA的request 就受限的。 定时器1的通道2 的DMA request 只有从该寄存器捕获值到内存,或内存 ...

感谢!

请问你的意思是通过TI2FP2捕获,产生更新事件,之后由更新事件触发DMA,将内存数据写入CCR1寄存器吗?

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版