cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F1 TIMER OPM exampe code.

parth kothiya
Senior

i want to use timer in one pulse mode is there any sample code for TIMER OPM mode.

1 ACCEPTED SOLUTION

Accepted Solutions

It is an external signal, isn't it?

EXTI interrupts are not really useful for synchronization, because interrupt latency is variable, maybe between 10-40 cycles, depending on the timing w.r.t. other interrupts in the system.

Exact synchronization down to a system clock cycle can be achieved by using a timer trigger input, which can be the timer CH1, CH2, or ETR pin.

I've changed the above code a bit, using the timer in downcounting mode, so that the compare register can be set to a fixed value, which is the number of cycles before the downcounter reaches 0, to start the pulse. The reload (ARR) value should be the sum of Toff and Ton, minus the adjustment required because of the 2 cycles trigger latency. It can be changed anytime, when the new Toff value becomes available.

TIM3->ARR    = 0xFFFF; // set it to Toff + Ton - 3, as the trigger takes 2 cycles to have an effect
TIM3->SMCR   =
    TIM_SMCR_TS_2|TIM_SMCR_TS_1|TIM_SMCR_TS_0| // TS=111: External Trigger input (ETRF)
    TIM_SMCR_SMS_2|TIM_SMCR_SMS_1; // SMS=110: Trigger Mode - The counter starts at a rising edge of the trigger TRGI
TIM3->CCR3   = 360 - 1; // start the pulse 360 cycles ( = 10 μs ) before the counter reaches 0
TIM3->CCMR2 |=
    TIM_CCMR2_OC3M_2|TIM_CCMR2_OC3M_1; // 110: PWM mode 1
TIM3->CCER  |= TIM_CCER_CC3E; // Enable PWM output on channel 3
TIM3->CR1   |= TIM_CR1_OPM | TIM_CR1_DIR; // enable one pulse mode, downcounting

View solution in original post

9 REPLIES 9
dbgarasiya
Senior II

what your requirement , you want to generate delay ?

OPM is exactly the same as any other time mode, except that you set TIMx_CR1.OPM bit before enabling the timer.

That tells the timer to disable itself after having counted one cycle up to TIMx_ARR.

JW

can i write code using HAL driver or it need LL driver for it ?

because here i found it need LL driver.

total time of pulse(on+off) is (10ms = 10,000 us).

now pulse on time is fix let say 10 us.

now i need to very off time between( 0-9,990 us).

for exampe: OFF-ON-OFF , ON-OFF, OFF-ON (here total time 10ms on time fix 10us)

and every 10 ms external interrupt comes so i need to reset counter back to 0 for synchronous operation with external interrupt.

that is my requirement.

total time of pulse(on+off) is (10ms = 10,000 us).

now pulse on time is fix let say 10 us.

now i need to very off time between( 0-9,990 us).

for example: OFF-ON-OFF , ON-OFF, OFF-ON (here total time 10ms on time fix 10us)

and every 10 ms external interrupt comes so i need to reset counter back to 0 for synchronous operation with external interrupt.

that is my requirement.

I don't quite understand, please draw a timing diagram.

JW

Neither HAL nor LL is documented in sufficient detail for such everyday requirements.

There is an example of one-pulse mode in the TIMx functional description chapters of the reference manual. I have simplified it a bit, using the timer ETR pin as a trigger as it is somewhat easier as using the timer channels, and configured channel 3 as PWM output, because that's where I happen to have a LED connected.

Timer and GPIO should be enabled in RCC beforehand, and the trigger and PWM pin should be configured as alternate function input and output respectively.

Set the length of the pulse. This value will result in a 10 μs pulse if the timer clock is 36 MHz.

TIM3->ARR    = 360;

Set trigger source ETR and slave mode trigger mode

TIM3->SMCR   =
    TIM_SMCR_TS_2|TIM_SMCR_TS_1|TIM_SMCR_TS_0| // TS=111: External Trigger input (ETRF)
    TIM_SMCR_SMS_2|TIM_SMCR_SMS_1; // SMS=110: Trigger Mode - The counter starts at a rising edge of the trigger TRGI

Start the pulse at the first cycle after the trigger.

TIM3->CCR3   = 1;

Channel 3 in PWM mode 2

TIM3->CCMR2 |=
    TIM_CCMR2_OC3M_2|TIM_CCMR2_OC3M_1|TIM_CCMR2_OC3M_0; // 111: PWM mode 2

Enable PWM output on channel 3

TIM3->CCER  |= TIM_CCER_CC3E;

Enable one-pulse mode

TIM3->CR1   |= TIM_CR1_OPM;

Now the timer would start each time a rising edge is detected on the ETR pin, outputting a single pulse on channel 3. Set the TIM_SMR_ETP (external trigger polarity) bit if you want it to start on the falling edge instead.

here i want to do it.0693W0000000KEkQAM.jpg

It is an external signal, isn't it?

EXTI interrupts are not really useful for synchronization, because interrupt latency is variable, maybe between 10-40 cycles, depending on the timing w.r.t. other interrupts in the system.

Exact synchronization down to a system clock cycle can be achieved by using a timer trigger input, which can be the timer CH1, CH2, or ETR pin.

I've changed the above code a bit, using the timer in downcounting mode, so that the compare register can be set to a fixed value, which is the number of cycles before the downcounter reaches 0, to start the pulse. The reload (ARR) value should be the sum of Toff and Ton, minus the adjustment required because of the 2 cycles trigger latency. It can be changed anytime, when the new Toff value becomes available.

TIM3->ARR    = 0xFFFF; // set it to Toff + Ton - 3, as the trigger takes 2 cycles to have an effect
TIM3->SMCR   =
    TIM_SMCR_TS_2|TIM_SMCR_TS_1|TIM_SMCR_TS_0| // TS=111: External Trigger input (ETRF)
    TIM_SMCR_SMS_2|TIM_SMCR_SMS_1; // SMS=110: Trigger Mode - The counter starts at a rising edge of the trigger TRGI
TIM3->CCR3   = 360 - 1; // start the pulse 360 cycles ( = 10 μs ) before the counter reaches 0
TIM3->CCMR2 |=
    TIM_CCMR2_OC3M_2|TIM_CCMR2_OC3M_1; // 110: PWM mode 1
TIM3->CCER  |= TIM_CCER_CC3E; // Enable PWM output on channel 3
TIM3->CR1   |= TIM_CR1_OPM | TIM_CR1_DIR; // enable one pulse mode, downcounting

i tried code as you say it works fine but i don't get my desired out put so where is my mistake.

code i tried is below.

timer.c

/* Includes ------------------------------------------------------------------*/
#include "tim.h"
 
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
TIM_HandleTypeDef htim1;
 
/* TIM1 init function */
void MX_TIM1_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
 
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 179;
  htim1.Init.CounterMode = TIM_COUNTERMODE_DOWN;
  htim1.Init.Period = 900;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) != HAL_OK)
  {
    Error_Handler();
  }
  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
  sSlaveConfig.InputTrigger = TIM_TS_ETRF;
  sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_NONINVERTED;
  sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
  sSlaveConfig.TriggerFilter = 0;
  if (HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 880;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW;
  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != 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(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim1);
 
}
 
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(tim_baseHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspInit 0 */
 
  /* USER CODE END TIM1_MspInit 0 */
    /* TIM1 clock enable */
    __HAL_RCC_TIM1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM1 GPIO Configuration    
    PA12     ------> TIM1_ETR 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* USER CODE BEGIN TIM1_MspInit 1 */
 
  /* USER CODE END TIM1_MspInit 1 */
  }
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(timHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspPostInit 0 */
 
  /* USER CODE END TIM1_MspPostInit 0 */
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM1 GPIO Configuration    
    PA8     ------> TIM1_CH1 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* USER CODE BEGIN TIM1_MspPostInit 1 */
 
  /* USER CODE END TIM1_MspPostInit 1 */
  }
 
}
 
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
 
  if(tim_baseHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspDeInit 0 */
 
  /* USER CODE END TIM1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM1_CLK_DISABLE();
  
    /**TIM1 GPIO Configuration    
    PA8     ------> TIM1_CH1
    PA12     ------> TIM1_ETR 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8|GPIO_PIN_12);
 
  /* USER CODE BEGIN TIM1_MspDeInit 1 */
 
  /* USER CODE END TIM1_MspDeInit 1 */
  }
} 
 
/* USER CODE BEGIN 1 */
 
/* USER CODE END 1 */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

main.c

HAL_TIM_OnePulse_Start(&htim1,TIM_CHANNEL_1);

using above code i got as op(yellow).

0693W000000UNboQAG.jpg

Here i want as out put waveform.

0693W000000UNcIQAW.jpg

in idle state timer CH1 op remain HIGH . but here no effect of setting idle op SET & RESET in code.