The timer knowledge of STM32 is quite complex. Here are some basic knowledge. I will write about its various applications in later articles.

The general timer is composed of a 16 bit automatic loading counter driven by a programmable prescaler. It is suitable for many occasions, including timing interrupt, measuring the pulse length of input signal (input capture) or generating output waveform (output comparison and PWM). Each timer is completely independent and does not share any resources with each other. They can operate synchronously together.

Stm32f103rc series has four general timers, two advanced timers and two basic timers:

STM32 timer interrupt and misunderstanding

We most often use general timers, including:

1. 16 bit up, down, up / down automatic load counter (timx_cnt), for example, up means that the counter counts from 0 to the automatic load value (timx_arr), then starts counting again from 0 and generates a counter overflow event.

2. 16 bit programmable (real-time modifiable) prescaler (timx_psc), the frequency division coefficient of counter clock frequency is any value between 1 and 65535.

3. 4 independent channels (timx_ch1 ~ 4).

4. Support multiple interrupts, such as overflow interrupt, etc.

Here we describe the interrupt experiment using a general timer:

1、 Timer clock selection

We often use the internal clock (ck_int) by configuring timx_ SMS of smcr [2:0], configured as 000. The clock is 1 times (apb1 does not divide) or 2 times (apb1 divides) of ABP1 clock.

2、 Counter mode

You can select up, down, or up / down.

3、 Timing time calculation

Overflow time = (automatic loading value (ARR) + 1) (prescaled coefficient (PSC) + 1) / timer clock (TCLK)

4、 Library function configuration

1. Enable timer clock.

2. Initialize timer, configure arr and PSC (in stm32f10x_tim. C)

TIM_ TimeBaseInit();

The structure: typedef struct

{

uint16_ t TIM_ Prescaler; // Set frequency division coefficient

uint16_ t TIM_ CounterMode; // restart at

uint16_ t TIM_ Period; // Automatic reload value

uint16_ t TIM_ ClockDivision;

uint8_ t TIM_ RepetitionCounter;

} TIM_ TimeBaseInitTypeDef;

3. Start timer interrupt and configure interrupt priority group NVIC.

void TIM_ ITConfig();

NVIC_ Init();

4. Enable timer.

TIM_ Cmd();

5. Write an interrupt service function.

TIMx_ IRQHandler();

STM32 timer error

When using the update interrupt of STM32 timer, it is found that in some cases, as long as the timer is turned on, it will enter an interrupt immediately. To be exact, as long as the update interrupt permission bit is enabled, it will immediately respond to an update interrupt [of course, provided that the relevant NVIC has also been configured]. In other words, as long as the relevant timer update interrupt is enabled, no matter how long your timing interval is or whether you start the relevant timer, it will immediately enter the timer update interrupt service program.

Taking stm32f051 chip as an example, several combined tests in different sequences are done. According to the test, it is found that there are indeed some cases in which Tim is run at the same time_ ITConfig(TIM1, TIM_IT_Update, ENABLE); [even if the interrupt can be updated] immediately enter the update interrupt service program. Of course, the following interrupts are normal.

To be honest, this problem is easy to ignore, and in some cases it doesn’t matter, but in some cases it may cause trouble to the application. It seems that the appropriate or logical antecedents and consequences of this problem can not be clearly found from the relevant technical manuals of St MCU.

After verification and testing, this problem can be avoided if you pay attention to the sequence of relevant instruction codes.

STM32 timer interrupt and misunderstanding

First clear the update interrupt flag, that is, clear the UIF flag in the timx – “SR register, and then enable the timer update interrupt. As for the command to start the relevant timer, the placement position is not strict. The following is the operation sequence and results of relevant actions, which can be referenced and verified. There are six writing methods listed here, three of which will immediately enter the interrupt, and the other three will not.

TIM_ ClearITPendingBit(TIM1, TIM_IT_Update); // Clear update interrupt request bit

TIM_ ITConfig(TIM1, TIM_IT_Update, ENABLE); // Enable timer 1 update interrupt

TIM_ Cmd(TIM1, ENABLE); // Start timer

(1)。。。。。。 The update interrupt program will not be entered immediately.

TIM_ ClearITPendingBit(TIM1, TIM_IT_Update);// Clear update interrupt request bit

TIM_ Cmd(TIM1, ENABLE);

TIM_ ITConfig(TIM1, TIM_IT_Update, ENABLE);// Enable timer 1 update interrupt

(2)。。。。。。 The update interrupt program will not be entered immediately.

TIM_ Cmd(TIM1, ENABLE);

TIM_ ClearITPendingBit(TIM1, TIM_IT_Update);// Clear update interrupt request bit

TIM_ ITConfig(TIM1, TIM_IT_Update, ENABLE);// Enable timer 1 update interrupt

(3)。。。。。。 The update interrupt program will not be entered immediately.

STM32 timer interrupt and misunderstanding

TIM_ ClearITPendingBit(TIM1, TIM_IT_Update);// Clear update interrupt request bit

TIM_ Cmd(TIM1, ENABLE);

(5)。。。。。。 Enter the update interrupt program immediately.

STM32 timer interrupt and misunderstanding

(6)。。。。。。 Enter the update interrupt program immediately.

Incidentally, the use of UG bit and urs bit in the timer is in timx – “EGR” and timx – “CR1 register respectively. For UG position 1, an update event can be generated and the relevant counters and registers can be reinitialized. If urs bit is 0, an update interrupt will be generated at the same time. If you do not want to generate update interrupt at the same time of UG position 1, you have to set urs bit to 1, otherwise you will enter update interrupt immediately.

STM32 timer interrupt and misunderstanding

in addition

Most timers are on when we use them. The usual timing interrupt writing format is:

void TIM3_ IRQHandler(void)

{

if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)

{

TIM_ ClearITPendingBit(TIM3, TIM_IT_Update);

//The content of the event to be processed….

}

}

However, during the experiment of the project, the timer I used to deal with events is a little special, that is, the timer is not always on, and it is also closed in the interrupt when it is closed. The general form is as follows:

void TIM3_ IRQHandler(void)

{

if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)

{

TIM_ ClearITPendingBit(TIM3, TIM_IT_Update);

//The content of the event to be processed….

TIM_ Cmd(TIM3, DISABLE); // Disable (out of function enable)

}

}

It seems right, and it seems normal. However, there are many unknown errors in the processed event content (because my processed event has a strong timing, and the start and end are strict), which cannot be executed normally. Through the subsequent debugging (changing the processing time to lighting or printout), it is found that Tim_ Cmd(TIM3, DISABLE); Disrupted the timing relationship. After disabling, in fact, the interrupt does not really disable, and it will enter another interrupt. Therefore, the event is executed again. For events with strict timing, problems arise!

The reason is found. Therefore, I guess that although the timer is disabled and the timer is closed, the interrupt flag bit may not be really cleared. Although the interrupt has been cleared once, it is estimated that the flag bit is set again because of the failure. Therefore, I added a sentence to clear the interrupt update flag bit before the failure, as follows:

void TIM3_ IRQHandler(void)

{

if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)

{

TIM_ ClearITPendingBit(TIM3, TIM_IT_Update);

//The content of the event to be processed….

TIM_ ClearITPendingBit(TIM3, TIM_IT_Update);// Then clear the flag bit

TIM_ Cmd(TIM3, DISABLE); // Disable (out of function enable)

}

}

Sure enough, the program can run in normal sequence.

I wonder if I have to clear the flag bit before turning off the timer, so I have another curiosity about whether I have to turn off the timer in other places (such as the main function). So this curiosity was tested. It is found that if the shutdown timer is placed in the main function, there is no need to clear the interrupt flag bit. The timer can be turned off normally without entering interrupt.

Through this problem, we wasted a lot of time to solve, but we also learned some experience, but we haven’t figured out the real internal reason: why the disabling effect in interrupt is different from that outside interrupt… But this can be used as a lesson in the future, as well as everyone’s lesson, and avoid detours.

Leave a Reply

Your email address will not be published. Required fields are marked *