全志T113-S3裸机定时器驱动(timer0,timer1操作)

虽然只有2个定时器,但是好在是32bit的,日常使用刚好够,1个定时器当做StopWatch定时器,1us精度,用于时间测量,1个定时器给OS作为滴答时钟使用。

直接上代码:

cpp 复制代码
/*************************************************************************************************************
 * 文件名:		t113_timer.c
 * 功能:		t113定时器支持
 * 作者:		cp1300@139.com
 * 邮箱:		cp1300@139.com
 * 创建时间:	2023-09-30
 * 最后修改时间:2023-09-30
 * 详细:		支持timer0 timer1 2个32bit定时器
*************************************************************************************************************/
#include "t113_system.h"
#include "t113_map.h"
#include "typedef.h"
#include "t113_timer.h"
#include "t113_const.h"

/*
writel(0x2EE0, TMR_0_INTV); //Set the interval value
writel(0x94, TMR_0_CTRL); //Select Single mode, 24 MHz clock source, 2 pre-scale
writel(readl(TMR_0_CTRL)|(1<<1), TMR_0_CTRL); //Set the Reload bit
while((readl(TMR_0_CTRL)>>1)&1); //Waiting the Reload bit turns to 0
writel(readl(TMR_0_CTRL)|(1<<0), TMR_0_CTRL); //Enable Timer0
*/

static void (*sg_pTimer0_Callback)(void) = NULL;	//定时器0中断回调,外部初始化
static void (*sg_pTimer1_Callback)(void) = NULL;	//定时器0中断回调,外部初始化


void TIMER0_IRQHandler(void);	//中断处理函数
void TIMER1_IRQHandler(void);	//中断处理函数


/*************************************************************************************************************************
* 函数			:	void T113_TimerSet(TIMER_CH ch, bool isPeriodicMode,TIMER_PRES_TYPE Pers, u32 Cycle, bool isEnableInt, void (*pCallback)())
* 功能			:	定时器设置
* 参数			:	ch:定时器通道选择;isPeriodicMode:是否为周期模式(否则为单次模式);Pers:分频设置;Cycle:计数周期;
					isEnableInt:是否使能中断;pCallback:中断回调
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2023-09-30
* 最后修改时间 	: 	2023-09-30
* 说明			:	会关闭定时器,不会启动定时器
*************************************************************************************************************************/
void T113_TimerSet(TIMER_CH ch, bool isPeriodicMode, TIMER_PRES_TYPE Pers, u32 Cycle, bool isEnableInt, void (*pCallback)())
{
	switch (ch)
	{
		case TIMER_CH0:
		{
			r_TMR_IRQ_EN &= ~BIT0;	//关闭定时器0 中断
			r_TMR0_CTRL = 0;									//关闭定时器0
			if (FALSE == isPeriodicMode) r_TMR0_CTRL |= BIT7;	//单次模式
			r_TMR0_CTRL |= (Pers & 0x07) << 4;					//设置分频
			if (Pers & 0x0100) r_TMR0_CTRL |= 1 << 2;			//使用24MHz时钟

			r_TMR0_INTV_VALUE = Cycle;							//设置初值
			r_TMR0_CUR_VALUE = Cycle;							//计数器值

			r_TMR0_CTRL |= BIT1;								//使能自动重载,会自动清除
			if (TRUE == isEnableInt)	//使能中断了
			{
				r_TMR_IRQ_STA |= BIT0;	//清除中断0状态
				r_TMR_IRQ_EN |= BIT0;	//使能中断
				sg_pTimer0_Callback = pCallback;				//设置中断回调

				GIC_SetIrqPriority(GIC_IRQ_TIMER0, 1);	                    		//GIC设置一个中断的优先级
				GIC_SetIrqEdgeTriggered(GIC_IRQ_TIMER0, TRUE);              		//GIC设置一个中断为边沿触发
				GIC_RegisterIRQHandler(GIC_IRQ_TIMER0, TIMER0_IRQHandler);   		//注册中断服务程序
				GIC_IrqEnable(GIC_IRQ_TIMER0, TRUE);	                    		//GIC中断使能-中断使能
			}
			else
			{
				sg_pTimer0_Callback = NULL;
				GIC_IrqEnable(GIC_IRQ_TIMER0, FALSE);	                    		//GIC中断使能-中断关闭
			}
		}break;
		case TIMER_CH1:
		{
			r_TMR_IRQ_EN &= ~BIT1;	//关闭定时器1中断

			r_TMR1_CTRL = 0;									//关闭定时器1
			if (FALSE == isPeriodicMode) r_TMR1_CTRL |= BIT7;	//单次模式
			r_TMR1_CTRL |= (Pers & 0x07) << 4;					//设置分频
			if (Pers & 0x0100) r_TMR1_CTRL |= 1 << 2;			//使用24MHz时钟

			r_TMR1_INTV_VALUE = Cycle;							//设置初值
			r_TMR1_CUR_VALUE = Cycle;							//计数器值

			r_TMR1_CTRL |= BIT1;								//使能自动重载,会自动清除
			if (TRUE == isEnableInt)	//使能中断了
			{
				r_TMR_IRQ_STA |= BIT1;	//清除中断1状态
				r_TMR_IRQ_EN |= BIT1;	//使能中断
				sg_pTimer1_Callback = pCallback;				//设置中断回调

				GIC_SetIrqPriority(GIC_IRQ_TIMER1, 3);	                    		//GIC设置一个中断的优先级
				GIC_SetIrqEdgeTriggered(GIC_IRQ_TIMER1, TRUE);              		//GIC设置一个中断为边沿触发
				GIC_RegisterIRQHandler(GIC_IRQ_TIMER1, TIMER1_IRQHandler);   		//注册中断服务程序
				GIC_IrqEnable(GIC_IRQ_TIMER1, TRUE);	                    		//GIC中断使能-中断使能
			}
			else
			{
				sg_pTimer1_Callback = NULL;
				GIC_IrqEnable(GIC_IRQ_TIMER1, FALSE);	                    		//GIC中断使能-中断关闭
			}
		}break;
		default: return;
		
	}
}


/*************************************************************************************************************************
* 函数			:	void T113_TimerEnable(TIMER_CH ch, bool isEnable)
* 功能			:	使能定时器(开启或关闭定时器)
* 参数			:	ch:定时器通道选择;isEnable:TRUE:开启定时器;FALSE:关闭定时器
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2023-09-30
* 最后修改时间 	: 	2023-09-30
* 说明			:	需要提前初始化定时器
*************************************************************************************************************************/
void T113_TimerEnable(TIMER_CH ch, bool isEnable)
{
	switch (ch)
	{
		case TIMER_CH0:
		{
			if (TRUE == isEnable)
			{
				r_TMR0_CTRL |= BIT0;	//使能定时器
			}
			else
			{
				r_TMR0_CTRL &= ~BIT0;	//关闭定时器
			}
		}break;
		case TIMER_CH1:
		{
			if (TRUE == isEnable)
			{
				r_TMR1_CTRL |= BIT0;	//使能定时器
			}
			else
			{
				r_TMR1_CTRL &= ~BIT0;	//关闭定时器
			}
		}break;
		default:return;
	}
}

/*************************************************************************************************************************
* 函数			:	u32 T113_GetTimerCount(TIMER_CH ch)
* 功能			:	获取计数器当前值
* 参数			:	ch:定时器通道选择
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2023-10-02
* 最后修改时间 	: 	2023-10-02
* 说明			:	自减计数器
*************************************************************************************************************************/
u32 T113_GetTimerCount(TIMER_CH ch)
{
	switch (ch)
	{
		case TIMER_CH0: return r_TMR0_CUR_VALUE;
		case TIMER_CH1: return r_TMR1_CUR_VALUE;
		default:return 0;
	}
}

/*************************************************************************************************************************
* 函数			:	void T113_ClearTimerInt(TIMER_CH ch)
* 功能			:	清除定时器中断
* 参数			:	ch:定时器通道选择
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2024-07-19
* 最后修改时间 	: 	2024-07-19
* 说明			:	
*************************************************************************************************************************/
void T113_ClearTimerInt(TIMER_CH ch)
{
	switch (ch)
	{
		case TIMER_CH0: r_TMR_IRQ_STA |= BIT0; break;	//清除中断0状态
		case TIMER_CH1: r_TMR_IRQ_STA |= BIT1; break;	//清除中断1状态
		default:break;
	}
}



//中断处理函数 timer0
void TIMER0_IRQHandler(void)
{
	r_TMR_IRQ_STA |= BIT0;	//清除中断0状态
	if (sg_pTimer0_Callback != NULL) sg_pTimer0_Callback();
}

//中断处理函数 timer1
void TIMER1_IRQHandler(void)
{
	r_TMR_IRQ_STA |= BIT1;	//清除中断1状态
	if (sg_pTimer1_Callback != NULL) sg_pTimer1_Callback();
}
cpp 复制代码
/*************************************************************************************************************
 * 文件名:		t113_timer.h
 * 功能:		t113定时器支持
 * 作者:		cp1300@139.com
 * 邮箱:		cp1300@139.com
 * 创建时间:	2023-09-30
 * 最后修改时间:2023-09-30
 * 详细:		支持timer0 timer1 2个32bit定时器
*************************************************************************************************************/
#ifndef _T113_TIMER_H_  
#define _T113_TIMER_H_
#include "typedef.h"
#include "t113_map.h"
#include "t113_const.h"


//普通定时器通道选择
typedef enum
{
	TIMER_CH0 = 0,
	TIMER_CH1 = 1,
}TIMER_CH;

//分频选择
typedef enum
{
	TIMER_PRES_LOSC_1_1 = 0x0100,	//LOSC 1分频
	TIMER_PRES_LOSC_1_2 = 0x0101,	//LOSC 2分频
	TIMER_PRES_LOSC_1_4 = 0x0102,	//LOSC 4分频
	TIMER_PRES_LOSC_1_8 = 0x0103,	//LOSC 8分频
	TIMER_PRES_LOSC_1_16 = 0x0104,	//LOSC 16分频
	TIMER_PRES_LOSC_1_32 = 0x0105,	//LOSC 32分频
	TIMER_PRES_LOSC_1_64 = 0x0106,	//LOSC 64分频
	TIMER_PRES_LOSC_1_128 = 0x0107,	//LOSC 128分频

	TIMER_PRES_24M_1_1 = 0x0100,	//24MHz 1分频
	TIMER_PRES_24M_1_2 = 0x0101,	//24MHz 2分频
	TIMER_PRES_24M_1_4 = 0x0102,	//24MHz 4分频
	TIMER_PRES_24M_1_8 = 0x0103,	//24MHz 8分频
	TIMER_PRES_24M_1_16 = 0x0104,	//24MHz 16分频
	TIMER_PRES_24M_1_32 = 0x0105,	//24MHz 32分频
	TIMER_PRES_24M_1_64 = 0x0106,	//24MHz 64分频
	TIMER_PRES_24M_1_128 = 0x0107,	//24MHz 128分频
}TIMER_PRES_TYPE;


void T113_TimerSet(TIMER_CH ch, bool isPeriodicMode, TIMER_PRES_TYPE Pers, u32 Cycle, bool isEnableInt, void (*pCallback)());//定时器设置
void T113_TimerEnable(TIMER_CH ch, bool isEnable);	//使能定时器(开启或关闭定时器)
u32 T113_GetTimerCount(TIMER_CH ch);				//获取计数器当前值
void T113_ClearTimerInt(TIMER_CH ch);				//清除定时器中断

#endif //_T113_TIMER_H_

注意:定时器需要使用中断,中断需要依赖GIC。

测试代码:

cpp 复制代码
//中断回调0-闪烁LED
static void time0_callback(void)
{
	GPIOD->DATA ^= BIT16;
}

//中断回调1-打印数据
static void time1_callback(void)
{
	static u32 count = 0;

	uart_printf("tim1:%u\r\n", count++);
}


//定时器测试
void timer_test(void)
{
	//timer0 500毫秒中断
	T113_TimerSet(TIMER_CH0, TRUE, TIMER_PRES_24M_1_1, 24 * 1000000 * 0.5, TRUE, time0_callback);//定时器设置
	T113_TimerEnable(TIMER_CH0, TRUE);	//使能定时器(开启或关闭定时器)

	//timer1 1中断
	T113_TimerSet(TIMER_CH1, TRUE, TIMER_PRES_24M_1_1, 24 * 1000000 * 1, TRUE, time1_callback);	//定时器设置
	T113_TimerEnable(TIMER_CH1, TRUE);	//使能定时器(开启或关闭定时器)
}

例子:

给FreeOS作为滴答时钟

cpp 复制代码
//RTOS滴答时钟中断初始化
void vConfigureTickInterrupt( void )
{
	T113_TimerSet(FREE_RTOS_TIME_CH, TRUE, TIMER_PRES_24M_1_8, RTOS_TIME_CYCLE, TRUE, FreeRTOS_Tick_Handler);
	T113_TimerEnable(FREE_RTOS_TIME_CH, TRUE);				//启动定时器      
}
/*-----------------------------------------------------------*/

void vClearTickInterrupt( void )
{
	T113_ClearTimerInt(FREE_RTOS_TIME_CH);//清除定时器中断
}

void vApplicationIRQHandler(uint32_t ulICCIAR)
{
	if (ulICCIAR == GIC_IRQ_TIMER0)	//如果是定时器0中断,则直接调用 FreeRTOS_Tick_Handler() ,因为定时器0是滴答时钟中断
	{
		g_OS_RunTime ++;									//操作系统运行时间-单位ms
		FreeRTOS_Tick_Handler();		//由于直接调用了 FreeRTOS_Tick_Handler 导致定时器的中断没有被清除,所以必须实现 vClearTickInterrupt()
		
	}
	else
	{
		SystemIrqHandler(ulICCIAR);
	}
}