Linux中zynq定时器驱动,学会Zynq(9)定时器使用示例(PPI)

定时器资源

每个Cortex-A9处理器都有私有的32位定时器和32位看门狗定时器。这两种定时器都是32位的计数器,计数到0时产生中断;带有8位的预分频器,能够更好地控制中断周期;可配置为单次重载或自动重载模式;可配置初始值。它们的工作时钟固定为CPU频率的1/2(CPU_3x2x)。

两个CPU同时共享一个64位的全局定时器GT,这是一个递增的计数器,带有自动递增功能。全局定时器与私有定时器在内存中映射的地址空间相同。两个Cortex-A9有各自的64位的比较器,可以共同访问全局定时器,达到比较器值时产生一个私有中断。它的时钟也固定为CPU频率的1/2(CPU_3x2x)。

除了两个CPU的私有看门狗定时器,还有一个24位的系统看门狗SWDT,在发生灾难性的系统故障时发出信号(比如PS中的PLL工作失常)。SWDT可以工作在CPU频率的1/4或1/6(CPU_1x),也可以工作在设备外部或PL提供的时钟下,并向它们输出一个复位信号。

此外PS中还有两个TTC(Triple Timer Counters),每个TTC都有三个独立的定时器/计数器。TTC只能工作在CPU频率的1/4或1/6(CPU_1x),Zynq使用该定时器计算来自MIO管脚或PL的信号脉冲宽度。

私有定时器和看门狗定时器、全局定时器属于PPI;SWDT和TTC属于SPI。各种定时器资源之间的关系如下:aa1af056c1b6e23484c0393ae949fe65.png

私有定时器的使用

几种定时器中,私有定时器是最常用的,使用双核时可能会用到全局定时器。私有定时器是CPU五种PPI中断源的一种,固定为上升沿敏感。

做一个简单的设计体会私有定时器的使用,每隔1s串口输出一次。Vivado中搭建硬件环境,使用最小系统即可,导出硬件到SDK中。

timer.h文件的代码如下:

#include #include "xadcps.h"

#include "xil_types.h"

#include "Xscugic.h"

#include "Xil_exception.h"

#include "xscutimer.h"

//---------------------------------------------------------

// 参数定义

//---------------------------------------------------------

#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID

#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID

#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR //定时器中断ID号

#define TIMER_LOAD_VALUE 0x13D92D3F //定时器装载值

//---------------------------------------------------------

// 函数申明

//---------------------------------------------------------

void SetupInterruptSystem(XScuGic *GicInstancePtr,

XScuTimer *TimerInstancePtr, u16 TimerIntrId);

void TimreInit(XScuTimer Timer, XScuGic Intc);

timer.c文件的代码如下:

#include "timer.h"

//---------------------------------------------------------

// 定时器中断处理程序

//---------------------------------------------------------

static void TimerIntrHandler(void *CallBackRef)

{

static int sec = 0; //计数

XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;

XScuTimer_ClearInterruptStatus(TimerInstancePtr);

sec++;

printf(" %d Second\n\r",sec); //每秒打印输出一次

}

//---------------------------------------------------------

// 定时器中断配置

//---------------------------------------------------------

void SetupInterruptSystem(XScuGic *GicInstancePtr,

XScuTimer *TimerInstancePtr, u16 TimerIntrId)

{

/* 初始化中断控制器 */

XScuGic_Config *IntcConfig;

IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);

XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);

/* 设置中断异常 */

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,

(Xil_ExceptionHandler)XScuGic_InterruptHandler, GicInstancePtr);

Xil_ExceptionEnable();

/* 设置定时器中断 */

XScuGic_Connect(GicInstancePtr, TimerIntrId,

(Xil_ExceptionHandler)TimerIntrHandler, (void *)TimerInstancePtr);

XScuGic_Enable(GicInstancePtr, TimerIntrId); //使能中断

XScuTimer_EnableInterrupt(TimerInstancePtr); //使能定时器中断

}

//---------------------------------------------------------

// 定时器初始化程序

//---------------------------------------------------------

void TimreInit(XScuTimer Timer, XScuGic Intc)

{

/* 私有定时器初始化 */

XScuTimer_Config *TMRConfigPtr;

TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);

XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr->BaseAddr);

XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE); // 加载计数周期

XScuTimer_EnableAutoReload(&Timer); // 设置自动装载模式

SetupInterruptSystem(&Intc,&Timer,TIMER_IRPT_INTR); // 设置定时器中断

XScuTimer_Start(&Timer); // 启动定时器

}

mian.c文件的代码如下:

#include "timer.h"

static XScuTimer Timer; //定时器

static XScuGic Intc; //中断控制器

int main()

{

TimreInit(Timer, Intc);

while(1);

return 0;

}

相关API函数

查阅PPI列表,可以看到私有定时器的中断号为29。6f4299c65b1dd2666064af295fbedeef.png

1.私有定时器初始化

初始化部分中,我们看到了似曾相识的XScuTimer、XscuTimer_Config两个结构体、XScuTimer_LookupConfig()和XScuTimer_CfgInitialize()两个函数,只是从“GPIO设备”、“中断设备”换成了“定时器设备”。这算是Zynq中各种设备(device)初始化的套路,甚至传入的参数类型都是十分相近的,这里不再赘述。

/* 私有定时器初始化 */

XScuTimer_Config *TMRConfigPtr;

TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);

XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr->BaseAddr);

2.加载计数周期

使用XScuTimer_LoadTimer()函数加载定时器的计数器中的值,其本质上只是操作Timer Load寄存器。函数原型采用宏定义,但也可以看作一个C语言风格的函数接口:

#define XScuTimer_LoadTimer(InstancePtr, Value)\

XScuTimer_WriteReg((InstancePtr)->Config.BaseAddr,\

XSCUTIMER_LOAD_OFFSET, (Value))

//可视作如下C语言函数

void XScuTimer_LoadTimer(XScuTimer *InstancePtr, u32 Value)

私有定时器是从装载值递减到0时发出中断。我们这里默认使用666MHz的CPU时钟,则私有定时器的工作时钟为333MHz,每1/333M秒减1。因此若想定时1s,则装载值为1/(1/333M)-1,将该值在timer.h中宏定义。

3.设置装载模式

本例程需要定时器一直工作,因此使用XScuTimer_EnableAutoReload()函数启用自动装载模式。不需要时使用XScuTimer_DisableAutoReload()函数禁用自动装载。这两个函数本质上也是宏定义,操作相关寄存器中的相应bit位。下面只给出等效的C语言模型:

void XScuTimer_EnableAutoReload(XScuTimer *InstancePtr)

void XScuTimer_DisableAutoReload(XScuTimer *InstancePtr)

4.设置定时器中断

这部分通过自定义函数来设置定时器的中断,过程和第8篇中PL中断的初始化过程基本相同。实际上用到中断时基本都要有这个过程:初始化中断控制器、设置中断异常、连接中断、使能中断。

我们这里使用的是定时器中断,连接函数如下。在定时器中断处理程序中,我们必须清除中断标志,因此XscuGic_Connect的第三个参数设置为定时器的控制设备,在调用中断状态清除函数时会用到该参数。

XScuGic_Connect(GicInstancePtr, TimerIntrId,

(Xil_ExceptionHandler)TimerIntrHandler, (void *)TimerInstancePtr);

5.清除定时器中断

中断处理程序中,除了计时和串口打印输出,还要调用XScuTimer_ClearInterruptStatus()函数清除中断状态。相关代码如下:

XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;

XScuTimer_ClearInterruptStatus(TimerInstancePtr);

该函数本质上也是宏定义,等效的C语言接口如下:

void XScuTimer_ClearInterruptStatus(XScuTimer *InstancePtr)

传入的XscuTimer*类型的参数在连接定时器中断时设置。使用时首先要将其从void*类型转换为XscuTimer*类型。

---------------------

文章来源:FPGADesigner的博客

*本文由作者授权转发,如需转载请联系作者本人

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值