cancel
Showing results for 
Search instead for 
Did you mean: 

Hallo ST, i am programming with the stm32l476 and with stmcubeide. My question is timer related.

MOtto.1
Associate II

I want to implement a timer which would elapse in 3s and gives me an interrupt then. But i want to build a kind of software watchdog which will be always reseted from an external clock 1s. So my idea is, when the external 1s clock is off then after 3s elapse my timer will fire an interrupt which i will use in further processing.

My configurations done in cube:

 TIM_SlaveConfigTypeDef sSlaveConfig = {0};

 TIM_MasterConfigTypeDef sMasterConfig = {0};

 /* USER CODE BEGIN TIM2_Init 1 */

 /* USER CODE END TIM2_Init 1 */

 htim2.Instance = TIM2;

 htim2.Init.Prescaler = 64000;

 htim2.Init.CounterMode = TIM_COUNTERMODE_DOWN;

 htim2.Init.Period = 3000;

 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

 htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;

 if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

 {

   Error_Handler();

 }

 sSlaveConfig.SlaveMode = TIM_SLAVEMODE_RESET;

 sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;

 sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;

 sSlaveConfig.TriggerFilter = 0;

 if (HAL_TIM_SlaveConfigSynchro(&htim2, &sSlaveConfig) != HAL_OK)

 {

   Error_Handler();

 }

 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;

 if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)

 {

   Error_Handler();

 }

 /* USER CODE BEGIN TIM2_Init 2 */

 __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_TRIGGER);

 __HAL_TIM_DISABLE_IT(&htim2, TIM_IT_UPDATE);

 /* USER CODE END TIM2_Init 2 */

i was playing with does enable disable ...IT but i always got both interrupts either the 1s or the 3s after elapsed counter. I thought i can reset the counter without doing an interrupt. Or any ideas who i can implement such behavior.

Thanks

2 REPLIES 2
berendi
Principal

The solution is in the reference manual, in the description of the TIMx_CR1 register.

Bit 2 URS: Update request source

This bit is set and cleared by software to select the UEV event sources.

0: Any of the following events generate an update interrupt or DMA request if enabled.

These events can be:

– Counter overflow/underflow

– Setting the UG bit

– Update generation through the slave mode controller

1: Only counter overflow/underflow generates an update interrupt or DMA request if enabled.

Setting this bit would ensure that the reset through the trigger input would not trigger the interrupt, only the counter overflow.

I have no idea how to do it with CubeMX/HAL. The reference manual however provides a nice description under 26.3.18 Timers and external trigger synchronization.

The description there omits configuring RCC, GPIO, and the timer period.

Enable RCC clocks

RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN |  RCC_AHB2ENR_GPIOEEN;
RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;

Configure GPIO. Map PA0 to TIM2_CH1, the middle button on L476G Discovery.

GPIOA->AFR[0] = (GPIOA->AFR[0] & ~GPIO_AFRL_AFSEL0) | (1 << GPIO_AFRL_AFSEL0_Pos); // PA0 AF1 TIM2_CH1/TIM2_ETR
GPIOA->MODER  = (GPIOA->MODER & ~GPIO_MODER_MODER0) | GPIO_MODER_MODER0_1; // PA0 alternate function

PE8 is an onboard LED, configure as output.

GPIOE->BSRR   = 1 << 24; // LED off
GPIOE->MODER  = (GPIOE->MODER & ~GPIO_MODER_MODER8) | GPIO_MODER_MODER8_0; // PE8 output, LED

Set the URS bit early. This would prevent setting the interrupt pending flag when the prescaler is loaded.

TIM2->CR1 = TIM_CR1_URS;

Set timer period and prescaler. Loading the prescaler requires generating an update event.

TIM2->PSC = 64000 - 1;
TIM2->EGR = TIM_EGR_UG;
TIM2->ARR = 3000 - 1;

Now follow the procedure in the reference manual. Only the bits that should be 1.

TIM2->CCMR1 = TIM_CCMR1_CC1S_0; // "The CC1S bits select the input capture source only, CC1S = 01 in the TIMx_CCMR1 register."
TIM2->SMCR = TIM_SMCR_SMS_2 | // "Configure the timer in reset mode by writing SMS=100 in TIMx_SMCR register"
	TIM_SMCR_TS_2|TIM_SMCR_TS_0; // "Select TI1 as the input source by writing TS=101 in TIMx_SMCR register."

Enable timer interrupt on update event only.

TIM2->DIER = TIM_DIER_UIE;

Start the timer.

TIM2->CR1 |= TIM_CR1_CEN;

Enable interrupts in the MCU core.

NVIC_EnableIRQ(TIM2_IRQn);

Now the timer should start, and call the interrupt handler when 3 seconds have elapsed without a trigger on PA0, so you need a proper interrupt handler.

void toggle_led(void) {
	GPIOE->ODR ^= 1 << 8;
}
void TIM2_IRQHandler(void) {
	uint32_t sr = TIM2->SR;
	TIM2->SR = ~sr;
	if(sr & TIM_SR_UIF) {
		toggle_led();
	}
}

This just clears the update flag, so the interrupt will trigger again after 6, 9, 12 etc seconds if you don't do something about that, but I don't know what should happen then. Disable the timer? Let it run? Something else?

MOtto.1
Associate II

Yes did it for me.

instead of those two macros mentioned before this one

 __HAL_TIM_URS_ENABLE(&htim2);

Thanks