Xilinx-ZYNQ7000系列-学习笔记(9):定时器中断实验

Xilinx-ZYNQ7000系列-学习笔记(9):定时器中断实验

1、定时器

首先,zynq 7000 soc芯片具有2个ARM核。每个Cortex-a9处理器都有自己的专用32位定时器和32位看门狗定时器.两个处理器共享一个全局64位定时。这些定时器的时钟频率固定为CPU时钟频率(Cpu_6x2x)的1/2,例如AX7021的ARM工作频率为767MHZ,则私有定时器的频率为383.5MHZ。

同时,在系统级别上,有一个24位的看门狗定时器和两个16位的三重定时器/计数器(TTC)。
系统看门狗计时器的时钟频率为CPU频率的1/4或1/6(即Cpu_1x时钟),或是来自MIO引脚或PL的外部时钟。两个三重定时器/计数器(TTC)的时钟为CPU频率的1/4或1/6(即Cpu_1x时钟),或是来自MIO引脚或PL的外部时钟。在这里插入图片描述

定时器的寄存器
  • 专用定时器加载寄存器 – 可将该寄存器用于自动重新加载模式,包含在使能自动重新加载时被重新加载到专用定时器计数器寄存器中的数值。

  • 专用定时计数寄存器 (Private TImer Counter Register) –
    这是真实计数器本身。使能后,一旦寄存器达到零,则会设置中断事件标志。

  • 专用定时器控制寄存器 – 控制寄存器可使能或禁用定时器、自动重新加载模式以及中断生成,还包含定时器的预分频器。

  • 专用定时器中断状态寄存器 – 该寄存器包含专用定时器中断状态事件标志。

2、中断

首先介绍几个概念:
Exception:(中断异常处理),为保证在ARM处理器发生异常时不至于处于未知状态,在应用程序的设计中,首先要进行异常处理、
SCU:(Snoop Control Unit) ,维护多CPU核之间的数据缓存的一致性,主要作用是CPU控制缓存的操作。
GIC:(中断控制器),接收I/O外设中断IOP和PL中断,将它们发送给CPU。
PPI(private peripheral interrupts),专用外围设备中断,PPI包括全局定时器,专用看门狗定时器,专用定时器和PL端的FIQ/IRQ。

2.1、中断来源
  • 硬件 - 直接连接处理器的电子信号
  • 软件 - 处理器加载的软件说明
  • 异常情况 - 发生错误或异常时处理器出现的异常情况
2.2、中断结构

Zynq SoC可使用通用中断控制器(GIC)来处理中断。GIC可处理源自以下方面的中断:

  • 软件生成的中断 – 每个处理器有16个此类中断,能够中断一个或两个Zynq SoC的ARM®CortexTM-A9处理器内核;
  • 共享外设中断 – 共计60个,这些中断来自I/O外围设备,或往返于设备的可编程逻辑(PL)侧。Zynq SoC的两个CPU共享这些中断;
  • 专用外设中断 – 这种类型中包含的5个中断对每个CPU都属于专用中断,比如CPU定时器、CPU看门狗监视器定时器以及专属PL至CPU中断。
2.3、中断过程
  1. 将中断显示为挂起;
  2. 处理器停止执行当前线程;
  3. 处理器在协议栈中保存线程状态,以便在中断处理后继续进行处理;
  4. 处理器执行中断服务例程,其中定义了如何处理中断;
  5. 在处理器从协议栈恢复之前,被中断的线程继续运行;

中断属于异步事件,因此可能同时发生多个中断。为了解决这一问题,处理器会对中断进行优先级排序,从而首先服务于优先级别最高的中断挂起。
为了正确实现这一中断结构,需要编写两个函数:一是中断服务例程,用于定义中断发生时的应对措施;二是用于配置中断的中断设置。中断设置例程可重复使用,允许构建不同的中断。该例程适用于系统中的所有中断,将针对通用I/O(GPIO)设置和使能中断。

在这里插入图片描述

代码解析

整个代码要实现的目的是设置一个计时器,1s递减,当定时器计数到0时会产生定时器中断,这时CPU会跳转到在定时器中断处理程序中,在处理程序中改变sec的值。相当于定时器发生一次中断,sec的数值就加1,再从串口信息中打印出来。
首先是整体代码:

#include <stdio.h>
#include "xadcps.h"
#include "xil_types.h"
#include "Xscugic.h" //该文件包含配置驱动程序以及GIC的使用范围
#include "Xil_exception.h"  //该文件包含Cortex-A9的异常函数
#include "xscutimer.h"

#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID//定义timer设备号
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID//定义中断控制器设备号(GIC中断控制器)
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR//私有时钟中断
#define TIMER_LOAD_VALUE (767/2*1000*1000-1)//欲装载值

static XScuGic Intc; //中断
static XScuTimer Timer; //定时器
static void SetupInterruptSystem(XScuGic *GicInstancePtr, XScuTimer *TimerInstancePtr, u16 TimerIntrId);
static void TimerIntrHandler(void *CallBackRef);

int main() {
	XScuTimer_Config *TMRConfigPtr; //timer config
	printf("------------Timer Test-------------\n");
	//私有定时器初始化
	TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
	XScuTimer_CfgInitialize(&Timer, TMRConfigPtr, TMRConfigPtr->BaseAddr);
	XScuTimer_SelfTest(&Timer);
	//加载计数周期,私有定时器的时钟为CPU的一半
	XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);
	//自动装载
	XScuTimer_EnableAutoReload(&Timer);
	//启动定时器
	XScuTimer_Start(&Timer);
	//set up the interrupts
	SetupInterruptSystem(&Intc, &Timer, TIMER_IRPT_INTR);
	while (1) {
	}
	return 0;
}

void SetupInterruptSystem(XScuGic *GicInstancePtr,XScuTimer *TimerInstancePtr, u16 TimerIntrId)
{
	XScuGic_Config *IntcConfig; //GIC config
	//初始化SOC异常
	Xil_ExceptionInit();
	//initialise the GIC
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);
	//connect to the hardware
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler) XScuGic_InterruptHandler,GicInstancePtr);
	//连接到中断处理硬件
	XScuGic_Connect(GicInstancePtr, TimerIntrId,(Xil_ExceptionHandler) TimerIntrHandler,(void *) TimerInstancePtr);
	//enable the interrupt for the Timer at GIC
	XScuGic_Enable(GicInstancePtr, TimerIntrId);
	//enable interrupt on the timer
	XScuTimer_EnableInterrupt(TimerInstancePtr);
	// Enable interrupts in the Processor.
	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
}

static void TimerIntrHandler(void *CallBackRef)
{
	static int sec = 0; //计数
	XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
	XScuTimer_ClearInterruptStatus(TimerInstancePtr);  //清除挂起的中断
	sec++;
	printf(" %d Second\n\r", sec); //每秒打印输出一次
}

代码解析:

#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID:定义一个timer计时器设备号。
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID:定义中断控制器设备号。
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR:定义私有时钟中断。
#define TIMER_LOAD_VALUE (767/210001000-1):定义预装载值。(AX7021的ARM工作频率为767MHZ,则私有定时器的频率为383.5MHZ)

TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID)
查找timer的设备号,并将其返回到一个含有设备号和基地址的结构体中。
XScuTimer_CfgInitialize
初始化timer。
XScuTimer_SelfTest(&Timer)
在计时器上运行自我测试。此测试清除控制寄存器中的计时器使能位,向计时器加载寄存器写入和验证读回的值与写入的值匹配,并恢复控制寄存器和计时器加载寄存器。
XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE)
向计时器写入装载值。
XScuTimer_EnableAutoReload(&Timer):使能自动装载值模式。
XScuTimer_Start(&Timer):开始计时。
SetupInterruptSystem(&Intc, &Timer, TIMER_IRPT_INTR)
设置中断系统函数。
Xil_ExceptionInit()
初始化ARM处理器异常处理(属于中断其中的一类,也是必须要执行的一步操作,防止出现异常情况无法判断)。
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT(Xil_ExceptionHandler)XScuGic_InterruptHandler, &my_Gic)
这一步基本是固定的,中断触发后统一由XScuGic_InterruptHandler先处理,然后在Handler Table中查找相应的处理函数。
XScuGic_InterruptHandler
所有产生的中断都要经过GIC,GIC负责使能中断,废弃中断,赋予优先级,发送到CPU,中断发生时ARM处理器会先询问中断控制器哪一个外设产生的中断。
XScuGic_Connect
将我们定义的中断服务函数地址映射到将Handler Table中。或者可以理解为GIC连接到中断处理硬件以实现对某硬件的中断控制作用。
XScuGic_Enable
在GIC上使能定时器使能中断。(INPUT)
XScuTimer_EnableInterrupt
使能定时器中断。(OUTPUT)
Xil_ExceptionEnableMask
在处理器上使能中断。
XScuTimer_ClearInterruptStatus
清除中断状态(类似于执行完返回原状态的一个函数)。

  • 17
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Zynq-7000系列之linux开发学习笔记是一系列关于在Zynq7030数据采集板上进行Linux开发的文章。在这些文章中,作者提供了关于编译Linux内核、制作设备树、安装NFS等方面的指导和经验。在其中一篇文章中,作者遇到了在挂载NFS时出现的问题,提示"wrong fs type, bad option, bad superblock"等错误信息。作者还提供了Linux内核源码的下载链接以及开发环境的相关信息。整个学习笔记的目标是让开发板能够连接外网,并通过NFS挂载到虚拟机上运行一个helloworld程序。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *3* [Zynq-7000系列之linux开发学习笔记:NFS配置与开发板联网(七)](https://blog.csdn.net/Claudedy/article/details/94591622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Zynq-7000系列之linux开发学习笔记:编译Linux内核和制作设备树(六)](https://blog.csdn.net/Claudedy/article/details/90760085)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值