Embedded study notes - basic timer of M4

foreword

In the previous article, the timer SysTick in the kernel was introduced. In the entire STM32F407, in addition to this kernel timer, there are many on-chip peripheral timers, which are roughly divided into three categories: basic timers and general timers. timer, advanced timer. Starting from this article, we will introduce the big family of timers.

Basic Timer Concepts

First of all, let's take a look at the relevant description of the basic timer to find out what it is and what it can do?
The description of the basic timer is as follows: the specific location is in Chapter 17 of the Chinese Reference Manual.

From the above description, we can find that
1. The basic timer is a 16-bit auto-reload increment (upward) calculator. I don’t know if you have any images. The system tick in the previous article is a 24-bit direction Lower the counter; a comparison shows that the maximum reload value of this basic timer is smaller than the system tick, it should be 2^16-1=65536-1=65535, and the counting direction is different, one is to subtract from the reload value to 0, one is added from 0 to the reload value;
2. The counter can be programmed to prescale the drive. To put it bluntly, the clock reference of this counter can be programmed to adjust the frequency division coefficient. There is no programmed prescaler for the ticking clock;
3. In addition to realizing the delay and timing interrupt similar to system ticking, this timer can also be specially used for DAC (digital-to-analog converter);
4. Timer and timer They are completely independent and do not share any resources.
By comparing with the system tick, it can be found that the use of the basic timer is also realized by controlling the reload value and time base. Here is one more point:
The basic timers of STM32F407 are TIM6 and TIM7, not all chips have basic timers, or both are TIM6 and TIM7.

Block diagram analysis

Well, after roughly having an image, the next step is to analyze its block diagram, and see if we can figure out the general workflow of the basic timer based on the block diagram. The overall block diagram is as follows: For the convenience of understanding, let's look at it separately.
insert image description here

clock selection

Before looking at the clock block diagram, you need to review a little knowledge. In the introduction of the clock tree, the clock about the timer is specifically mentioned.
insert image description here
The clock size of the timer:
first check whether the attached clock bus is divided by 1 of the main frequency. If it is divided by 1, the size of the timer clock is the size of the clock line. If it is not divided by 1, the size of the timer clock is the clock The line size x2
insert image description here
can be found in the data sheet, TIM6 and TIM7 are on APB1, and the clock of APB1 is 42MHZ, indicating that its frequency division factor ≠ 1; therefore, the clocks of TIM6 and TIM7 should be 42MHZ×2=84MHZ However, this is not the
actual The frequency used by the timer, as we mentioned in the overview, the clock input of the calculator can be prescaled by programming. Next, let's take a look at the specific description in the structure diagram.
insert image description here
First of all, the TIMxCLK clock from RCC on the right, which is the frequency 42MHZ on APB1 we mentioned above, has passed through two controllers. According to the previous experience, these two controllers can be programmed and controlled internally. One of them The output of the trigger controller is the DAC in the orange box, indicating that this is not necessary for the time being; the other controller outputs a CK_PSC, which is the clock signal, and the frequency at this time has become 42*2=84MHZ calculated above; The 84Mhz clock does not go directly to the counter, there is a prescaler in between, indicating that we can modify the frequency by operating the prescaler.
It should be noted that as shown in the figure below, there is a shaded part below the prescaler. This is not just a shadow added for good looks. This shaded part is its meaning, and its name is called the shadow register.
insert image description here
Pay attention to the description of the legend below. Only when an update event occurs, the data in the prescaler will be actually written into the actual frequency division register. That is to say, although we have written the prescaler register, the actual frequency division does not become the expected value after writing, and we still need to wait for an update event. That's why this divider is named "pre" divider.
Frequency division: Refers to how many times the frequency is divided into the frequency coefficient and needs -1
If you want to do 74 frequency division, the actual value written into the frequency divider is the
frequency division of 73 basic timers:
TIM6 and TIM7: 84MHZ
84000 000/s 84000/ms 84/us
84 frequency division: 1000 000/s 1000/ms 1 /us //Maximum delay 65.6ms
8400 frequency division: 10000/s 10/ms //Maximum delay 6553ms
42 frequency division 2/us

counter structure

The structure of the counter looks roughly the same as the system tick. First, the orange box is an increment counter. Its main job is to increment once by a clock. Then there is the input part. The left side is the prescaler mentioned above. The clock above is the auto-reload register, and its main job is to write the reload value, but there is also a shadow here, indicating that it has a shadow register just like the prescaler, so its working process is also the same as the prescaler It is the same?
The answer is no, although the reload value also has a shadow register, it is controllable whether the shadow register works or not, that is, if you want to have a preload function, you can turn it on, and if you don’t want to use it, turn it off.
insert image description here

The working timing diagram of the shadow register that enables the reload value register

As shown in the figure below, after enabling the reload shadow register, we wrote 36 to the automatic pre-reload register in the green box at the time of the red line. At this time, the auto-reload shadow register in the orange box below has not been directly modified to 36. Wait until the last round of counter counts to "F5" and complete the counting cycle of the previous reload value and generate an update event (position of the green line), then write 36 into the auto-reload shadow register.
insert image description here

The working timing diagram of the shadow register without reloading the value register

The timing diagram at this time is as shown below: We wrote 36 to the reload register at the orange line position, and there
is no shadow register at this time, so the reload value is directly modified, and the current count will also use the value written at this time The new reload value. As shown by the green line in the figure below, an update event has already occurred at 36, instead of being modified after the technology reaches "FF".
insert image description here

Update events and interrupts

After talking about the above, there is only a little thing left about this block diagram, which is the arrow in the orange box below and U, UI, etc. This is the corresponding interrupt, update event, and DMA output, etc., and the details are left below Let's talk about the register. There is an image.
insert image description here

Block Diagram Summary

It can be found that the overall block diagram is not much different from the system ticking, mainly because of the addition of a prescaler and shadow register concept.
The shadow register of the prescaler: must have
the shadow register of the reload value: configure by yourself

Thinking: How to write the value into the shadow register when configuring the frequency division register for the first time
Answer: An update event is artificially generated, and there is a corresponding register interface for operation.

Basic timer related registers

TIM6 and TIM7 control register 1 (TIMx_CR1)
writing method: TIM6->CR1
TIM7->CR1
X: Indicates which register to use
Function: Mainly control the function of the basic timer Bit
0 CEN: Counter enable (Counter enable)
set to 0 : Turn off the counter
Set 1: Turn on the counter

Bit 1 UDIS: Update disable (Update disable)
set to 0: can update shadow registers
set to 1: cannot update shadow registers

Bit 2 URS: Update request source (Update request source)
Set 0: Underflow event and UG bit 1 can be used to trigger update interrupt
Set 1: Only underflow event can generate update interrupt

Bit 3 OPM: One-pulse mode (One-pulse mode)
Set 0: The counter will always work
Set 1: The counter only works once, and it will be cleared after counting once
. single pulse)

位 7 ARPE:自动重载预装载使能 (Auto-reload preload enable)

Set to 0: Indicates that the shadow register of the reload value is not enabled.
Set to 1: The shadow register of the reload value is enabled

TIM6 and TIM7 control register 2 (TIMx_CR2)
writing method: TIM6->CR2
TIM7->CR2
function: used to configure the main mode of the timer,
configure when the DAC function is needed, and generate TRGO

TIM6 and TIM7 DMA/interrupt enable register (TIMx_DIER)
writing method: TIM6->DIER
TIM7->DIER
function: enable interrupt signal
bit 0 UIE: update interrupt enable (Update interrupt enable)
set 1: enable update interrupt
set 0 : disable update interruption

TIM6 and TIM7 status register (TIMx_SR)
writing method: TIM6->SR
TIM7->SR
bit 0 UIF: Update interrupt flag (Update interrupt flag)
read:
0: no update event occurred
1: update event occurred

Write: Write 0 to clear the flag bit

TIM6 and TIM7 event generation register (TIMx_EGR)
writing method: TIM6->EGR
TIM7->EGR
function: Artificially generate an event
Bit 0 UG: Update generation (Update generation)
Set 1: Generate an update event
Set 0: Do not perform any operation

TIM6 and TIM7 counter (TIMx_CNT)
writing method: TIM6->CNT
TIM7->CNT
function: record the current value of the counter
Usage direct assignment: TIM6->CNT=0;

TIM6 and TIM7 prescaler (TIMx_PSC)
writing method: TIM6->PSC
TIM7->PSC
function: configure prescaler value
Direct assignment of usage: TIM6->PSC = 84-1;

TIM6 and TIM7 automatic reload register (TIMx_ARR)
writing method: TIM6->ARR
TIM7->ARR
function: write reload value
Usage direct assignment: TIM6->ARR = 1000-1;

code flow

1. Delay function: directly encapsulate the function

//直接新建一个 timer.c文件存放定时器代码
实现TIM6的ms延时函数
{
    
    
   //打开TIM6的时钟
   //更新禁止
   //更新请求源
   //单脉冲模式
   //重装载值影子寄存器
   
   //配置预分配
   //重装载值
   //人为产生一次更新事件
   
   //清除计数标志
   //使能计数器
   //等待计数完成
}

2. Basic timer timing interrupt

Take tim7 as an example:

基本定时器的中断初始化函数
{
    
    
   //TIM7基础配置
   //打开TIM7的时钟
   //更新禁止
   //更新请求源
   //关闭单脉冲模式
   //重装载值影子寄存器
   
   //配置预分配
   //重装载值
   //人为产生一次更新事件
   //开启中断使能
   
   //NVIC控制器
   //使能计数器    一直工作
}
Tim7的中断服务函数
{
    
    
  判断中断
  //清除标志位
  //紧急事件
}

configuration code

Delay:


/*******************************
函数名:Time6_Delay_ms
函数功能:定时器6实现ms延时
函数形参:u32 nms
函数返回值:void
备注:
********************************/
void Time6_Delay_ms(u32 nms)
{
    
    
	RCC->APB1ENR |=(1<<4);//打开APB1的Time6时钟使能
	TIM6->CR1 &=~(7<<1);	//清零
	TIM6->CR1 |=(4<<1);   //更新禁止,更新请求源,单脉冲模式
//	TIM6->CR1 &=~(1<<1);  //	0:使能 UEV。
//	TIM6->CR1 &=~(1<<2);  //URS:更新请求源0使能
//	TIM6->CR1 |=(1<<3);   // 单脉冲模式,只执行一次后自动关闭
	TIM6->CR1 |=(1<<7);   //使能重装载值的影子寄存器
	
	TIM6->PSC =8400-1;    //频率为42*2=84Mhz,为了方便计算,进行8400分频为10 000
	TIM6->ARR =10*nms-1;  //向上计数
	TIM6->EGR |=(1<<0);   //手动产生一次更新事件 ,将预分频和重装载值写入
	
	TIM6->SR &=~(1<<0);   //清除计数标志
	TIM6->CR1 |=(1<<0);   //使能计数器。
	while(!(TIM6->SR &(1<<0)));//等待计数完成
}

/*******************************
函数名:Time6_Delay_us
函数功能:定时器6实现us延时
函数形参:u32 nus
函数返回值:void
备注:

********************************/
void Time6_Delay_us(u32 nus)
{
    
    
	RCC->APB1ENR |=(1<<4);//打开APB1的Time6时钟使能
	TIM6->CR1 &=~(7<<1);	//清零
	TIM6->CR1 |=(4<<1);   //更新禁止,更新请求源,单脉冲模式
//	TIM6->CR1 &=~(1<<1);  //	0:使能 UEV。
//	TIM6->CR1 &=~(1<<2);  //URS:更新请求源0使能
//	TIM6->CR1 |=(1<<3);   // 单脉冲模式,只执行一次后自动关闭
	TIM6->CR1 |=(1<<7);   //使能重装载值的影子寄存器
	
	TIM6->PSC =42-1;    //频率为42*2=84Mhz,为了方便计算,进行8400分频为10 000
	TIM6->ARR =2*nus-1;  //向上计数
	TIM6->EGR |=(1<<0);   //手动产生一次更新事件 ,将预分频和重装载值写入
	
	TIM6->SR &=~(1<<0);   //清除计数标志
	TIM6->CR1 |=(1<<0);   //使能计数器。
	while(!(TIM6->SR &(1<<0)));//等待计数完成
}

Timed interrupt:

/*******************************
函数名:Time7_Interrupt
函数功能:Time7_定时中断
函数形参:u16 arr重装载值   u16 psc预分频系数
函数返回值:void
备注:
预分频系数  重装载值
********************************/
void Time7_Interrupt(u16 psc,u16 arr)
{
    
    
	RCC->APB1ENR |=(1<<5);//打开APB1的Time6时钟使能
	TIM7->CR1 &=~(7<<1);	//清零  //更新禁止,更新请求源,关闭单脉冲模式


	TIM7->CR1 |=(1<<7);   //使能重装载值的影子寄存器
	
	TIM7->PSC =psc-1;   //频率为42*2=84Mhz
	TIM7->ARR =arr-1;   
	TIM7->EGR |=(1<<0);   //手动产生一次更新事件 ,将预分频和重装载值写入
	TIM7->DIER |=(1<<0);  //使能中断
	
			//NVIC控制器配置EXTI0
		u32 pri=NVIC_EncodePriority(7-2,1,3);
		NVIC_SetPriority(TIM7_IRQn,pri);
		NVIC_EnableIRQ(TIM7_IRQn);
	
	TIM7->CR1 |=(1<<0);//使能计数器
}


final effect

With the help of the idea of ​​the previous time slice, the data is sent every 500ms to see the timestamp.
insert image description here
The corresponding interrupt service function function:

/*******************************
函数名:TIM7_IRQHandler
函数功能:定时器7中断服务函数函数
函数形参:无
函数返回值:void
备注:1ms中断
********************************/
void TIM7_IRQHandler(void)
{
    
    
	static u16 Time7_Cnt[10]; 
	if(TIM7->SR & (1<<0))
	{
    
    
		TIM7->SR &=~(1<<0);
		Time7_Cnt[0]++;
		if(Time7_Cnt[0]>=500)
		{
    
    
			printf("1\r\n");
			Time7_Cnt[0]=0;
			LED_1_TURN;
		}
	}
}


//初始化代码Time7_Interrupt(84-1,1000-1);//1ms进入一次中断

Guess you like

Origin blog.csdn.net/qq_41954556/article/details/129717475