从SOD到OOD(timer模块)

D:\Xilinx\SDK\2019.1\data\embeddedsw\XilinxProcessorIPLib\drivers\tmrctr_v4_5\examples
中的
xtmrctr_intr_example.c文件,作为移植参考。
这个例子中,核心数据结构是XTmrCtr。这也是我们要封装的对象。
如果需要cascase模式的参考,则查找xtmrctr_intr_64bit_example.c文件即可。

INTC InterruptController;  /* The instance of the Interrupt Controller */

XTmrCtr TimerCounterInst;   /* The instance of the Timer Counter */

volatile int TimerExpired;

在C++环境下,既可以封装为class,也可以封装为struct,为了尽量多的保持SOD风格,这里封装成struct。

// stamp_timer_dev.h

struct StampTimerDev
{
	XTmrCtr tmr;
};

来看main,它里面只调用了TmrCtrIntrExample,这是功能主体。
来看TmrCtrIntrExample。
这个函数里,
首先,初始化timer,XTmrCtr_Initialize完成这个任务,利用传入的DeviceID,来lookup,并cfg_init。
然后,设置中断,TmrCtrSetupIntrSystem完成这个任务。来看看这个函数。
这个函数中,初始化INTC,XINC_connect,XINC_start,XINC_Enable,然后,初始化exception,
exception_register,exception_enable,这些操作都是整板级别的处理,这里需要重点关注的是,
xinc_connect。它将timer的handler挂载到INTC中去。
即XTmrCtr_InterruptHandler。这个函数,是ISR,在这个函数里,遍历所有的timer number,查询是哪个timer到期,然后调用timer的callback函数。这个函数,是BSP包里提供的函数。
回到TmrCtrIntrExample中,来看看下一个,
XTmrCtr_SetHandler,这个函数,在XTMRCTR中,注册callback。当中断发生后,INTC会调用ISR,而ISR又会调用callback,所以,必须要在XTMRCTR结构体中注册callback。这个函数,是BSP包中提供的函数。
回到TmrCtrIntrExample中,来看看下一个,
XTmrCtr_SetOptions,这个函数,设置选项参数,是BSP包中提供的函数。
回到TmrCtrIntrExample中,来看看下一个,
XTmrCtr_SetResetValue,这个函数,设置复位值,是BSP包中提供的函数,
回到TmrCtrIntrExample中,来看看下一个,
XTmrCtr_Start,这个函数,设置启动哪个number的timer,是BSP包中提供的函数。
之后,ISR运行在前台,等待被触发,main的主线程运行在后台,前后台之间,通过共享变量进行通信,前台修改共享变量的值,后台轮询共享变量的值。
回到TmrCtrIntrExample中,来看看下一个,
XTmrCtr_Stop,这个函数,设置停止哪个number的timer,是BSP包中提供的函数。

来看看这个例子中,为XTMRCTR设计的callback,即
TimerCounterHandler,
这个函数中,检查是否是当前number的timer到期,用XTmrCtr_IsExpired函数检查,
如果不是则跳过,如果是,则进行后续处理。
例如,修改共享变量的值,配置当前number的timer的参数。

if (XTmrCtr_IsExpired(InstancePtr, TmrCtrNumber)) {
		TimerExpired++;
		if (TimerExpired == 3) {
			XTmrCtr_SetOptions(InstancePtr, TmrCtrNumber, 0);
		}
	}

所以,这个函数,是需要我们移植的函数。
首先是封装stamp_timer_init函数。

int stamp_timer_init(struct StampTimerDev* dev, int dev_id)
{
	int ret;
	/*
	 * Initialize the timer counter so that it's ready to use,
	 * specify the device ID that is generated in xparameters.h
	 */
	ret = XTmrCtr_Initialize(&dev->tmr, dev_id);
	if (ret != XST_SUCCESS) {
		return -1;
	}

	/*
	 * Perform a self-test to ensure that the hardware was built
	 * correctly, use the 1st timer in the device (0)
	 */
	ret = XTmrCtr_SelfTest(&dev->tmr, 0);
	if (ret != XST_SUCCESS) {
		return -1;
	}

	/*
	 * Perform a self-test to ensure that the hardware was built
	 * correctly, use the 2nd timer in the device (0)
	 */
	ret = XTmrCtr_SelfTest(&dev->tmr, 1);
	if (ret != XST_SUCCESS) {
		return -1;
	}


	/*
	 * Set a reset value for the timer counter such that it will expire
	 * eariler than letting it roll over from 0, the reset value is loaded
	 * into the timer counter when it is started
	 */
	XTmrCtr_SetResetValue(&dev->tmr, 0, 0);
	XTmrCtr_SetResetValue(&dev->tmr, 1, 0);


	/*
	 * Enable the interrupt of the timer counter so interrupts will occur
	 * and use auto reload mode such that the timer counter will reload
	 * itself automatically and continue repeatedly, without this option
	 * it would expire once only and set the Cascade mode.
	 */
	XTmrCtr_SetOptions(&dev->tmr, 0,
				XTC_AUTO_RELOAD_OPTION |
				XTC_CASCADE_MODE_OPTION);

	/*
	 * Reset the timer counters such that it's incrementing by default
	 */
	 XTmrCtr_Reset(&dev->tmr, 0);
	 XTmrCtr_Reset(&dev->tmr, 1);

	 return 0;
}

可以看出,区别在于,main中操作的对象是static的变量,而在封装函数中,替换成参数传入的对象。

然后是stamp_timer_start函数,

int stamp_timer_start(struct StampTimerDev* dev)
{
	XTmrCtr_Start(&dev->tmr, 0);
	return 0;
}

可以看出,这是对XTmrCtr_Start进行了简单的封装,区别只是在于变量引用上的不同。

我们只是需要时间戳,所以没有使用INT_MODE,而是使用了cascade模式,所以需要设计读取时间戳的函数。
get_timestamp。

u64 get_timestamp(struct StampTimerDev* dev)
{
	u32 val0 = XTmrCtr_GetValue(&dev->tmr, 0);
	u32 val1 = XTmrCtr_GetValue(&dev->tmr, 1);

	u64 ret = (((u64)val1) << 32) + val0;
	return ret;
}

为了更方便的读取时间,需要进一步处理读取的时间戳,所以需要设计时间转换函数。

u32 get_timestamp_ms(struct StampTimerDev* dev)
{
	u64 val = get_timestamp(dev);
	u64 ms = val / 100000;
	return (u32)ms;
}

对于使用100MHZ时钟的axi_aclk而言,timer每个周期计数加1,所以1秒钟,计数值是100M,所以计数值与秒的换算关系,是除以100M,如果是毫秒,则先除以100M,再乘以1000。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值