前天发了一个关于使用TIM输出比较+DMA做脉冲控制的帖子,
由于包装了一层步进电机控制使得问题不够简明,遂今天再重新做了一个工程,经过测试HAL库可能存在的bug。
bug的现象是使用HAL_TIM_OC_Start_DMA开启定时器后如果DMA传输未完成时用HAL_TIM_OC_Stop_DMA来结束会导致下次开启定时器的初始发生电平变化。
CubeMX的配置不变,具体如下:
复现Bug的程序
主程序
[C] 纯文本查看 复制代码 __weak void TaskOutput(void const * argument)
{
/* USER CODE BEGIN TaskOutput */
int cnt = 0;
const int size = 20;
uint16_t BUF[size]; //DMA传输比较值到CCR1寄存器
/* 生成测试数据 */
BUF[0] = 100;
for (size_t i = 1; i < size; i++)
{
BUF[i] = BUF[i-1] + 100;
}
/* Infinite loop */
for(;;)
{
TIM2->CNT = 0;
TIM2->CCR1 = BUF[0];
PinDEBUG1(1); //翻转IO,Debug用
HAL_TIM_OC_Start_DMA(&htim2,
TIM_CHANNEL_1,
(uint32_t*)&BUF[1],
19);
osDelay(1);
cnt ++;
if (cnt > 5 && cnt < 15)
{
HAL_TIM_OC_Stop_DMA(&htim2, TIM_CHANNEL_1);
}
osDelay(100);
}
/* USER CODE END TaskOutput */
}
在中断回调里面
一次传输会进入三次中断,DMA传输中断,开启输出比较的中断和最后一次比较发生的中断,
下面分别对三次中断做处理。
[C] 纯文本查看 复制代码 int endflag = 0; //用来跳过因使能中断而产生的中断
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
PinDEBUG2(1);
if (endflag == 1)
{
endflag = 0;
PinDEBUG2(0);
return;
}
if (__HAL_TIM_GET_ITSTATUS(&htim2, TIM_IT_CC1) == RESET)
{
__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_CC1);
endflag = 1;
PinDEBUG2(0);
return;
}
__HAL_TIM_DISABLE_IT(&htim2, TIM_IT_CC1);
HAL_TIM_OC_Stop_DMA(&htim2, TIM_CHANNEL_1);
PinDEBUG2(0);
PinDEBUG1(0);
}
测试
打开逻辑分析仪,复位单片机可以看到以下波形
先看异常波形
再看看异常波形
附件
程序位于 Core/Src/freertos.c Line182、Line271
引脚
TIM2_CH0 --- PA0
debug1Pin --- PF0
debug2Pin --- PF1
STM32F103ZE_TIM_OC_DMA_0517.rar
(1.46 MB, 下载次数: 3)
|