2025-04-28 6:31 AM
I am using output compare with TIM3 on a STM32H755
I am able to use Output Compare to generate a single pulse on pin PC7 using TIM3, Channel 2.
I am using Active Level on Match.
However, I can find no way to restart the process.
I have tried resetting the timer calling HAL_TIM_OC_Stop(&htim3, TIM_CHANNEL_2) and HAL_TIM_OC_Start(&htim3, TIM_CHANNEL_2), but the pin remains low. I've even tried calling the initialisation code again.
I assume I am missing something fundamental here?
Settings: (see screen shot attached )
Auto-reload preload: Disable
Mode: Active Level on Match
Output Compare Preload: Disable
CH Polarity: Low
2025-04-28 8:19 AM
Hello @NickO,
You can consider one pulse mode, this mode stops the counter at the next update event, and you might need to reconfigure or reset this setting to restart the pulse generation!
Otherwise, could you share the timer configuration?
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2025-04-28 8:32 AM - edited 2025-04-28 8:34 AM
As @Sarra.S said above, this works exactly as expected: once a match occurs, OCxRef goes Active, and any further match sets it again to Active i.e. does nothing.
If you don't want to use one of the PWM modes of TIMx_CHx (possibly with running the timer in One-Pulse mode, TIMx_CR1.OPM=1), set the given OCxRef Inactive, you can use for example the Force inactive level i.e. set TIMx_CCMRx.OCxM to 0b100.
I don't think this is something you can simply click in CubeMX. See description of TIMx_CCMR.OCxM in the TIM chapter in RM.
JW
2025-04-28 8:32 AM
Hi
Thank you for responding.
I did look at one-pulse mode, but I struggled to get it to work. I may need to find an example as reading the reference guide didn't help. What I actually need is a re-triggerable one-pulse (the thinking being that it needs to be constantly tr-triggered to sustain the the pin in a high state).
As I could not get it to work, I achieve this by using output capture, where producer threads are pushing data into a queue. With each new sample, the counter is reset to zero (thus preventing a match) as follows:
__HAL_TIM_SET_COUNTER(&htim3, 0);
If the producer thread was to freeze (or miss the deadline), the output drops to zero and stays there, which is the intended behaviour. However, should I wish to reset this, it seems "challenging"
As for my current approach, here is the initialisation code (ignore the reference to tim8):
void MX_TIM3_Init(void)
{
/* USER CODE BEGIN TIM3_Init 0 */
/* USER CODE END TIM3_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM3_Init 1 */
/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 50000-1;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 4000-1;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_OC_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_ACTIVE;
sConfigOC.Pulse = 2000;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM3_Init 2 */
/* USER CODE END TIM3_Init 2 */
HAL_TIM_MspPostInit(&htim3);
}
And here:
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspPostInit 0 */
/* USER CODE END TIM3_MspPostInit 0 */
__HAL_RCC_GPIOC_CLK_ENABLE();
/**TIM3 GPIO Configuration
PC7 ------> TIM3_CH2
*/
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* USER CODE BEGIN TIM3_MspPostInit 1 */
/* USER CODE END TIM3_MspPostInit 1 */
}
else if(timHandle->Instance==TIM8)
{
/* USER CODE BEGIN TIM8_MspPostInit 0 */
/* USER CODE END TIM8_MspPostInit 0 */
__HAL_RCC_GPIOC_CLK_ENABLE();
/**TIM8 GPIO Configuration
PC8 ------> TIM8_CH3
*/
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF3_TIM8;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* USER CODE BEGIN TIM8_MspPostInit 1 */
/* USER CODE END TIM8_MspPostInit 1 */
}
}
I start the timer using:
HAL_TIM_OC_Start(&htim3, TIM_CHANNEL_2);