碎碎思 · 2022年04月14日

ZYNQ从放弃到入门(五)- 专用定时器

ZYNQ从放弃到入门(五)- 专用定时器

7249bb5397ae8f9fb15083dc75fd3a1b.jpg

与大多数 Zynq 外设一样,专用定时器(Private Timer,这里翻译成专用定时器,也可翻译成私有定时器)具有许多预定义的函数和宏,可帮助工程师有效地使用资源。这些包含在#include "xscutimer.h"

参考:


UG585 CH8 Timer

每个A9处理器都有私有的32位定时器和32位看门狗定时器。两个处理器共享一个64位定时器。这些定时器的时钟始终是的CPU频率的1/2(CPU_3x2x)。

4b6a6f9aa09ab214820de2bf96d733d6.png

xscutimer.h 中包含以下函数(宏):

  • 初始化定时器
  • 运行计时器自检
  • 启动和停止计时器
  • 管理定时器(重启、检查是否过期、加载定时器、启用/禁用自动加载)
  • 设置预分频器
  • 获取预分频器值
  • 设置、启用、禁用、清除和管理定时器中断

定时器本身通过 Zynq All Programmable SoC 中的四个寄存器进行控制:

  • Private Timer Load Register——用于自动重载模式。该寄存器包含启用自动重载时要重载到专用定时器计数器寄存器中的值。
  • Private Timer Counter Register——这个寄存器是实际的计数器本身。当该寄存器中的值达到零时,设置中断事件标志(启用时)。
  • Private Timer Control Register ——该控制寄存器启用或禁用定时器、自动重载模式和中断生成。它还包含定时器预分频器。
  • Private Timer Interrupt Status Register——该寄存器包含专用定时器中断状态事件标志

设置定时器所需的定时器设备 ID 和定时器中断 ID 包含在 XParameters.h 中。这篇博文中的示例使用了我们之前开发的按钮中断。在此示例中,将加载计时器并在按下按钮时开始运行。(注意:定时器不会在自动重载模式下运行)。当预设的定时器倒计时值达到零时,定时器将产生中断。产生的中断通过 STDOUT 触发消息输出,然后将清除中断以等待下一次按下按钮。

此示例将相同的值加载到计数器中。因此,在文件顶部声明了定时器计数值的声明

#define TIMER_LOAD_VALUE 0xFFFFFFFF

下一步是配置和初始化私有定时器,执行自检,并将定时器计数值加载到定时器中:

//定时器初始化     
TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);      
XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr-> BaseAddr );      
XScuTimer_SelfTest(&Timer); 
//加载定时器    
XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);

我们还需要更新中断设置子程序,将定时器中断连接到 GIC(通用中断控制器)并启用定时器中断:

//设置定时器中断      
XScuGic_Connect(GicInstancePtr, TimerIntrId,                                   
              ( Xil_ExceptionHandler )TimerIntrHandler,                                     
              ( void *) TimerInstancePtr); 
//为 GIC 处的定时器启用中断      
XScuGic_Enable(GicInstancePtr, TimerIntrId);   
//启用定时器中断      
XScuTimer_EnableInterrupt(TimerInstancePtr); 

其中 TimerIntrHandler 是中断发生时要调用的函数的名称。

接下来,必须在 GIC 上和定时器本身内启用定时器中断。定时器中断服务程序非常简单。它只是清除挂起的中断并通过 STDOUT 写出一条消息:

static void TimerIntrHandler ( void *CallBackRef) 
{       
XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;       
XScuTimer_ClearInterruptStatus(TimerInstancePtr); 
printf ("****Timer Event!!!!!!!!!!!!!****\n\r"); 

最后一步是修改GPIO中断服务程序,在每次按下按钮时启动定时器:

//加载定时器
XScuTimer_LoadTimer       (&Timer, TIMER_LOAD_VALUE);
//启动定时器
XScuTimer_Start(&Timer); 

为此,我们首先将定时器值加载到定时器中,然后调用定时器启动函数,然后再次清除按钮中断并恢复处理.下面是这个程序的输出现在的样子:

664078133e686a9aa899ccca10a5d4b0.png

源文件:


https://gitee.com/openfpga/zy...
原文:OpenFPGA
作者:碎碎思

相关文章推荐

更多FPGA技术干货请关注FPGA 的逻辑技术专栏。
推荐阅读
关注数
10677
内容数
633
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息