[SOLVED]Interruptions in the timer do not work

STM32F103 Nucleo boards e.g. STM Nucleo F103RB
dannyf
Posts: 231
Joined: Wed May 11, 2016 4:29 pm

Re: Use of the timer?

Post by dannyf » Fri Nov 24, 2017 1:24 pm

i have a set of timer routines for the f3, but that's built on top of spl.

take a look at the datasheet and it is not that difficult to work out a set of routines of your own, with direct register access.

if i get some time, i may write one myself.

FRANCISCOGIMENO
Posts: 38
Joined: Wed Nov 08, 2017 12:30 pm

Re: Use of the timer?

Post by FRANCISCOGIMENO » Fri Nov 24, 2017 3:30 pm

I would appreciate it, I just need an example and I continue.
The strange thing is that not even the code of st works.

dannyf
Posts: 231
Joined: Wed May 11, 2016 4:29 pm

Re: Use of the timer?

Post by dannyf » Fri Nov 24, 2017 10:13 pm

I actually ended up just using my F1 code.

Code: Select all

	tim3_init(100);								//set prescaler to 100
	tim3_setpr1(50000ul);						//oc1 period to be 50000 ticks
	tim3_act1(led12_flp);						//install user handler
	ei();										//enable global interrupts
it sets up tim3's output compare ch1 to periodically call led12_flp: it flips PE12 pin repeatedly.

the basic principle is simple: it increments TIM_CCRx in the ISR and then run a user-installed handler, as shown below - only OC1 portion is shown.

Code: Select all

//isr for timer3 capture / compare
void TIM3_IRQHandler(void) {
	//oc1 portion
	if (TIMx->SR & TIM_SR_CC1IF) {		//output compare 1 flag is set
		TIMx->SR &=~TIM_SR_CC1IF;		//clear the flag
		TIMx->CCR1 += _tim_oc1;			//update the output compare register
		_tim_oc1isrptr();				//execute user handler
	}
	...
the timer is initialized by tim3_init():

Code: Select all

//initialize tim3 to use compare channels as timers
//16-bit prescaler. 32-bit used for compatibility
void tim3_init(uint32_t ps) {
	//route the clock to timer
	RCC->APB1ENR |= RCC_APB1ENR_TIMxEN;

	//source from internal clock -> disable slave mode
	TIMx->SMCR &=~TIM_SMCR_SMS;			//clear sms->use internal clock

	//stop the timer to configure it
	TIMx->CR1 &=~TIM_CR1_CEN;			//clear cen. 0=disable the timer, 1=enable the timer
	TIMx->CR1 &=~TIM_CR1_CKD;			//clear CKD0..1. 0b00->1x clock; 0b01->2:1 clock, 0b10->4:1 clk; 0b11->reserved
	TIMx->CR1 &=~TIM_CR1_DIR;			//clear DIR bit. 0=upcounter, 1=downcounter
	TIMx->CR1 &=~TIM_CR1_OPM;			//clear opm bit. 0=periodic timer, 1=one-shot timer
	TIMx->CR1 &=~TIM_CR1_ARPE;			//1=arr is buffered, 0=arr not buffered
	//or to simply zero the register
	//TIMx->CR1 = 0;						//much easier

	//clear the status register bits for capture / compare flags
	TIMx->SR &=~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF);
	//disable the interrupt by clearing the enable bits
	TIMx->DIER &=~(TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE);

	//set the prescaler
	TIMx->PSC = ps - 1;					//set the prescaler
	TIMx->RCR = 0;						//repetition counter = 0 (=no repetition)
	TIMx->ARR = -1;						//auto reload register / period = 0; - need to change for downcounters
	TIMx->CNT = 0;						//reset the counter

	//enable the timer.
	TIMx->CR1 |= TIM_CR1_CEN;			//enable the timer
}
user period is set by tim3_setpr():

Code: Select all

//set tim3_oc1 period
//pr is 16-bit. 32-bit used for compatability;
void tim3_setpr1(uint32_t pr) {
	//save the period value
	_tim_oc1 = pr - 1;
	TIMx->CCR1 = TIMx->CNT + _tim_oc1;

	//clear the flag
	//TIMx->SR &=~TIM_SR_CC1IF;			//clear the interrupt flag
	//TIMx->DIER &=~TIM_DIER_CC1IE;		//disable the isr
}
tim3_act1() activates the user handler.

Code: Select all

//install user handler
void tim3_act1(void (*isr_ptr)(void)) {
	NVIC_DisableIRQ(TIMx_CC_IRQn);		//disable irq

	_tim_oc1isrptr = isr_ptr;			//install user handler

	//clear the flag
	TIMx->SR &=~TIM_SR_CC1IF;			//clear the interrupt flag
	TIMx->DIER |= TIM_DIER_CC1IE;		//enable the isr

	NVIC_EnableIRQ(TIMx_CC_IRQn);		//enable irq
	//priorities not set -> default values used.
}
a word of caution: TIM2 is a 32-bit timer. it is entirely possible, depending on the prescaler setting and how you set up the timer, that by the time tim_act() is called, the timer counter has passed the associated CCR and you may have to wait a long time for the timer to roll-over, not an issue for a 16-bit timer.

dannyf
Posts: 231
Joined: Wed May 11, 2016 4:29 pm

Re: Use of the timer?

Post by dannyf » Fri Nov 24, 2017 10:27 pm

BTW, this approach (of using output compare channels for timing) allows you to create 4 timing events per TIM2/3/4 (each has 4 output compare channels) with differing periods.

it can be expanded to other chips as well. for more, see here: https://dannyelectronics.wordpress.com/ ... ollection/

the basic code should run on other STM32 chips, with minimum re-configuration: mostly to change clock sourcing.

FRANCISCOGIMENO
Posts: 38
Joined: Wed Nov 08, 2017 12:30 pm

Re: Use of the timer?

Post by FRANCISCOGIMENO » Mon Nov 27, 2017 8:43 am

Hello friend, thank thank you very much for your code.

I have managed to prove it but interruptions do not trigger

FRANCISCOGIMENO
Posts: 38
Joined: Wed Nov 08, 2017 12:30 pm

Re: Use of the timer?

Post by FRANCISCOGIMENO » Tue Nov 28, 2017 9:51 am

At the end I solved it by putting a function
in the SysTick_Handler, a fudge since there are a lot of timers
without using.

In the timer interrupts do not work.
I have tried with the timer 6, 7, 1,3 and it does not work.

For example the basic timer 6 counts correctly but
even if you set the active interrupt, it never triggers it.

Also if in any timer active this:

Code: Select all

TIM6->DIER |= TIM_DIER_UIE;
The micro is blocked and does not make any process.

I have tested the timers with interrupts with the embed compiler and if they work.
But if you use the configuration for the arduino ide no.

My question is:
Someone has managed with the arduino ide to do a basic timer for example with the timer 6, simply that every time that it reaches the maximum count it activates an interruption?

I've been here for 4 days and there's no way to do it.

Ok, Working with the simplest:
This is my code a basic configuration of the timer 6:

Code: Select all

void tim6_init()
 {
 RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
 TIM6->CR1 = 0;	
 TIM6->PSC = 100;  
 TIM6->CNT = 0;
 TIM6->DIER |=TIM_DIER_UDE;
//////////TIM6->DIER |= TIM_DIER_UIE;  //If this line is included (which I think is necessary) the micro does not execute the program
 NVIC_EnableIRQ(TIM6_DAC_IRQn);
 TIM6->CR1 |= TIM_CR1_CEN;		
}



void TIM6_DAC_IRQHandler()
{
digitalWrite(8, HIGH);
}

With this code (without putting the commented line) the timer counts indefinitely 0,1...but never triggers the interruption

dannyf
Posts: 231
Joined: Wed May 11, 2016 4:29 pm

Re: Interruptions in the timer do not work

Post by dannyf » Tue Nov 28, 2017 4:54 pm

The way you isr is written it is hard for it not to hang.

1. Read the datasheet and see what you have to do there.

2. Flip a pin in the isr to help you understand what's going on.

FRANCISCOGIMENO
Posts: 38
Joined: Wed Nov 08, 2017 12:30 pm

Re: Interruptions in the timer do not work

Post by FRANCISCOGIMENO » Tue Nov 28, 2017 6:32 pm

Well I do not know, even though I look at the data sheet RM0316 Reference manual
and the modes of configuration:
AN4013 Application note STM32 cross-series timer overview
AN4776 Application note General-purpose timer cookbook

I do not see the fault.

:shock:

FRANCISCOGIMENO
Posts: 38
Joined: Wed Nov 08, 2017 12:30 pm

Re: Interruptions in the timer do not work

Post by FRANCISCOGIMENO » Tue Nov 28, 2017 7:06 pm

This does not trigger the event either:


void tim6_init()
{
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // Enable TIM6 clock
TIM6->PSC = 41999; // Set prescaler to 41999
TIM6->ARR = 5999; // Set auto-reload to 5999
TIM6->CR1 |= TIM_CR1_OPM; // One pulse mode
TIM6->EGR |= TIM_EGR_UG; // Force update
TIM6->SR &= ~TIM_SR_UIF; // Clear the update flag
TIM6->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
NVIC_EnableIRQ(TIM6_DAC_IRQn); // Enable TIM6 IRQ
TIM6->CR1 |= TIM_CR1_CEN; // Enable TIM6 counter
}



void TIM6_DAC_IRQHandler()
{
if (TIM6->SR & TIM_SR_UIF != 0) // If update flag is set
{
TIM6->SR &= ~TIM_SR_UIF; // Interrupt has been handled
Serial.println("INTERRUPT");
}

}

dannyf
Posts: 231
Joined: Wed May 11, 2016 4:29 pm

Re: Interruptions in the timer do not work

Post by dannyf » Tue Nov 28, 2017 11:52 pm

you are close. so keep working on it.

the following:

Code: Select all

	IO_OUT(LED_PORT, LED12);					//led as output
	tim6_init(100); tim6_setpr(10000); tim6_act(led12_flp);
	tim7_init(100); tim7_setpr(10000*1.01); tim7_act(led12_flp);
	ei();										//enable global interrupts
edit: the code above sets tim6 prescaler to 100, tim6 period to 10000, and install led12_flp() as the timer handler; it also sets tim7 prescaler to 100, tim7 period to 10000*1.01, and install led12_flp() as handler. As such, they create a beat frequency -> turns on / off led12 gradually: the intensity goes up and down, utilizing tim6/7 on a stm32f3, utilizing code that was originally written for stm32f1.

Post Reply