[Bare-metal development] GPT timer (3) - use GPT to achieve high-precision delay

The simplest and rude way to delay is to use an empty loop to delay, relying on the clock frequency (default is 396M) to count, once the clock frequency of 6ull is modified, the delay effect will be biased.

Therefore, we can use the counting function of EPIT or GPT to achieve high-precision delay. EPIT is counting down (self-decrementing), and GPT is counting up (self-increasing).


Table of contents

1. GPT initialization

2. Delay function delayus (us level)

1. Principle analysis

2. Realization

3. Delay function delayms (ms level)


1. GPT initialization

Unlike the previous timing interrupt, if you just want to implement the delay function, there is no need to initialize the interrupt , because the delay only uses the counting function of GPT.

  • GPT reset, and wait for the reset to complete
  • Configure the GPT timer (set the initial value of the counter, select the clock source, select the working mode)
  • Set the frequency division number (66 frequency division)
  • start timer
/*
 * @description	: gpt 定时初始化(不会产生中断,只是单纯的计数)
 * @param 		: 定时器时间间隔
 * @return 		: 无
 */
void delay_init()
{
	// 禁用GPT定时器
    GPT1_CR = 0;
	GPT1_CR |= (1 << 15);
	while((GPT1_CR >> 15) & 0x01);		// 等待复位完成

	/* 
     * 配置GPT定时器
     * bit 1: 1 设置计数器初始值为0
     * bit 8-6: 001 选择时钟源ipg_clk
     * bit 9: 1 选择工作模式free-run
     */
    GPT1_CR |= ((1 << 1) | (1 << 6) | (1 << 9));

	// 分频
	GPT1_PR &= ~(0xFFF << 0);    // 低 12 bit 清零
	GPT1_PR |= (65 << 0);        // 66 分频

	// 启动定时器
    GPT1_CR |= (1 << 0);
}

2. Delay function delayus (us level)

For example, we want to delay 500ms, 66MHz clock source, under the condition of 66 frequency division, 500ms is converted into a count value of 500000, so when delta >= 500000, it means that the delay is over, so the key to the problem is to find the time from the beginning to the present How many counts have been counted.

1. Principle analysis

In Free-Run mode, when the counter reaches 0xFFFF FFFF, it will overflow and start counting from 0 again. If the counter does not overflow , the difference in counts from the beginning to the present is as follows. (The difference in counts is time-dependent)

delta = newcount - oldcount;

If the counter overflows, the difference in counts from the beginning to the present is as follows

delta = delta1 + delta2 = 0xFFFFFFFF - oldcount + newcount;

Note: The period here has nothing to do with the clock cycle

2. Realization

To judge whether to remove, you need to use the ROV bit (bit 5) of GPT1_SR.

/*
 * @description	: 延时函数(us级)
 * @param - n	: 要延时的us数
 * @return 		: 无
 */
void delayus(unsigned int val)
{
	// 获取到当前计数器的值
	unsigned int oldcount = GPT1_CNT;
	unsigned int delta = 0;
	while (1)
	{
		unsigned int newcount = GPT1_CNT;
		// 判断是否溢出
		if ((GPT1_SR >> 5) & 0x01)			// 说明溢出了
		{
			delta = 0xFFFFFFFF - oldcount + newcount;
		}
		else
		{
			delta = newcount - oldcount;
		}

		if (delta >= val)	break;    // 延时完毕,跳出循环
	}
	GPT1_SR &= ~(1 << 5);			// 清除溢出标志位
}

Parsing: if (delta >= val)

66 MHz clock source, 66 frequency division = "the interval of a clock cycle is 1/1M = 1/10^6

The unit of val is us:

  • Convert to s, result = val / 10^6
  • Converted to the corresponding count value = 10^6 * val / 10^6 = val

Therefore, after val (us) is converted, the final count value is val

3. Delay function delayms (ms level)

/*
 * @description	: 延时函数(ms级)
 * @param - n	: 要延时的ms数
 * @return 		: 无
 */
void delayms(unsigned int val)
{
	delayus(val * 1000);
}

Guess you like

Origin blog.csdn.net/challenglistic/article/details/131424241
GPT