Understanding/Debugging Timers on STM32F4
I am having trouble understanding the behavior of the Timers on the STM32F429I-DISC board. I have an application using TouchGFX with FreeRTOS, which is kind of working as expected but the timer-based activity seems to be too slow, so I am trying to debug and verify the clock frequency (which is triggering my ADC conversions), but nothing is matching or giving anything as expected. I commented out everything else on the code (including FreeRTOS, TouchGFX etc) and leaving just the timer and ADC initialization. Main system clock is set to PLL with a frequency of 144MHz and I am using Timer8 to trigger ADC on triple simultaneous regular mode and Timer11 to try to measure this interval.
At first I've set Timer8 also to trigger an output event (pin toggle), and measuring it with the oscilloscope gave me exactly the expected frequency (Timer frequency / 2). But debugging is not showing anything useful at all. Here is the initialization of the timers:
void MX_TIM8_Init(void)
{
/* USER CODE BEGIN TIM8_Init 0 */
/* USER CODE END TIM8_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM8_Init 1 */
/* USER CODE END TIM8_Init 1 */
htim8.Instance = TIM8;
htim8.Init.Prescaler = 1;
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
htim8.Init.Period = 1499;
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim8.Init.RepetitionCounter = 0;
htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_OC_Init(&htim8) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_OC_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM8_Init 2 */
HAL_TIM_Base_Start_IT(&htim8);
HAL_TIM_OC_Start(&htim8, TIM_CHANNEL_3);
/* USER CODE END TIM8_Init 2 */
HAL_TIM_MspPostInit(&htim8);
}
void MX_TIM11_Init(void)
{
/* USER CODE BEGIN TIM11_Init 0 */
/* USER CODE END TIM11_Init 0 */
/* USER CODE BEGIN TIM11_Init 1 */
/* USER CODE END TIM11_Init 1 */
htim11.Instance = TIM11;
htim11.Init.Prescaler = 143;
htim11.Init.CounterMode = TIM_COUNTERMODE_UP;
htim11.Init.Period = 65535;
htim11.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim11.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim11) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM11_Init 2 */
HAL_TIM_Base_Start(&htim11);
/* USER CODE END TIM11_Init 2 */
}
So it is expected that Timer8 has clock of 48kHz and Timer11 has clock 1MHz. So I was trying to measure Timer8 using Timer11. As the Timer8 is triggering ADC conversions, I expect that the conversions are also happening on a 48kHz basis and that the callbacks are also called on that frequency. Here is my callback function:
void HAL_ADC_ConvCpltCallback (ADC_HandleTypeDef * hadc)
{
TIM11->CR1 &= 0xFFFE;
TIM11->EGR |= 0x0001;
TIM11->SR = 0x00;
TIM11->CR1 |= 0x0001;
foo = (uint16_t)hadc1.Instance->DR;
foo = (uint16_t)hadc2.Instance->DR;
foo = (uint16_t)hadc3.Instance->DR;
}Firstly I tried without reinitializing the TIM11 (did not have line 3 and 6) but it seemed not to having any effect on the registers. Now disabling and enabling seems to work but I get random results when placing a breakpoint on line 3. I let it run first so nothing gets accumulated, then i place a breakpoint on line 3 and analyze the CNT register from Timer11 to see how many cycles it counted since last reset. Sometimes i get random numbers but most of times i was getting values like ~12000, which from my calculations gives me something around 80Hz. If i set the breakpoint at line 8, which is right after initializing the Timer again, i get random values like CNT above 50.000 and UIF flag already set. So nothing seems to making much sense. So basically two questions:
- Am I missing concepts here?
- Is there a better way to measure/verify this clock via software?
My initialization code is only:
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_ADC1_Init();
MX_ADC2_Init();
MX_ADC3_Init();
MX_TIM8_Init();
MX_TIM11_Init();
while (1) {}
}