所用板:zedbroad
针对于定时器,Cortex-A9 processor 有一个32位私有定时器和一个32位的看门狗,并且与其他处理器公用一个64位的定时器;
对于我对看门狗的理解就是,对于系统看门狗,当过一定时刻要喂狗,不然就默认系统没有正常运行,会对系统进行复位。
对于系统级来说的话,有一个24位看门狗和二个16位的triple定时器;这个看门狗的时钟频率是CPU时钟的四分之一或者六分之一,也可以由外部时钟来提供(从MIO或者PL端)。对于两个triple timer的时钟频率通常是CPU时钟的四分之一或者六分之一,一般用来计算来自MIO或者PL端的脉冲宽度。
下图是系统定时器之间的关系:

对于CPU私有定时器和看门狗
1.32位计数器自减到0时,产生一个中断。
2.8位预分频可以更好的控制中断周期。(预分频置x,就代表着要分频2^x)
3.可以设置自动装载模式和单次(这里的自动装载可以这样理解,当计数结束时,产生中断后,我为了多次进行,我将计数器值再次装载,这样就可以继续中断)
4.可以设定计数器开始的数值
5.对于所有的私有定时器和看门狗时钟频率一般都设定CPU频率的二分之一

CPU私有中断ID是29
这两个图是定时器和看门狗中寄存器功能


对于triple 定时器、全局定时器和系统定时器不一一赘述,后面我再补充
此次学习针对实现ScuTimer(也就是基于 ARM Cortex-A9 的私有系统控制器(SCU)定时器)
对于此次定时器的实践操作
打开vivado,建立BD文件

之后生成输出文件,产生HDL wrapper文件,导入硬件打开SDK
建新工程新建c文件和H文件

这里我分别用两个c文件来初始化系统中断和定时器中断。h文件用来声明
一般调用资源,例如GPIO,定时器,中断这些,都需要先初始化,根据设备ID查找配置,用来初始化端口。
对于系统中断初始化如下
#ifndef SYS_INTR_H_
#define SYS_INTR_H_
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xscugic.h"
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
int Init_Intr_System(XScuGic * IntrInstancePtr);
#endif
//h文件
int Init_Intr_System(XScuGic * IntcInstancePtr)
{
int status;
XScuGic_Config *IntcConfig;
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
/* Enable interrupts from the hardware */
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
(void *)IntcInstancePtr);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
定时器中断初始化如下,此处的中断响应函数功能打印出秒数,当定时器递减到0,进入中断,sec++,并清除中断
#include "timer_intr.h"
volatile int sec = 0 ;
static void TimerIntrHandler(void *CallBackRef)
{
XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
XScuTimer_ClearInterruptStatus(TimerInstancePtr);
printf("seconds is %d \n",sec++);
}
int Timer_init(XScuTimer *TimerPtr, u8 PrescalerValue , u32 Load_Value,u32 DeviceId)
{
XScuTimer_Config *TMRConfigPtr; //timer config
TMRConfigPtr = XScuTimer_LookupConfig(DeviceId);
XScuTimer_CfgInitialize(TimerPtr, TMRConfigPtr,TMRConfigPtr->BaseAddr);
XScuTimer_SetPrescaler(TimerPtr, PrescalerValue) ;
XScuTimer_LoadTimer(TimerPtr, Load_Value);
XScuTimer_EnableAutoReload(TimerPtr);
return 1;
}
void Timer_Setup_Intr_System(XScuGic *GicInstancePtr,XScuTimer *TimerInstancePtr, u16 TimerIntrId)
{
XScuGic_Connect(GicInstancePtr, TimerIntrId,
(Xil_ExceptionHandler)TimerIntrHandler,//set up the timer interrupt
(void *)TimerInstancePtr);
XScuGic_Enable(GicInstancePtr, TimerIntrId);//enable the interrupt for the Timer at GIC
XScuGic_SetPriorityTriggerType(GicInstancePtr, TimerIntrId, 0XA0 , 3 ) ;
XScuTimer_EnableInterrupt(TimerInstancePtr);//enable interrupt on the timer
}
void Timer_start(XScuTimer *TimerPtr)
{
XScuTimer_Start(TimerPtr);
}
void Timer_stop(XScuTimer *TimerPtr)
{
XScuTimer_Stop(TimerPtr);
}
#ifndef TIMER_INTR_H_
#define TIMER_INTR_H_
#include <stdio.h>
#include "xadcps.h"
#include "xil_types.h"
#include "Xscugic.h"
#include "Xil_exception.h"
#include "xscutimer.h"
//timer info
#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR
void Timer_start(XScuTimer *TimerPtr);
void Timer_stop(XScuTimer *TimerPtr) ;
void Timer_Setup_Intr_System(XScuGic *GicInstancePtr,XScuTimer *TimerInstancePtr, u16 TimerIntrId);
int Timer_init(XScuTimer *TimerPtr, u8 PrescalerValue , u32 Load_Value,u32 DeviceId) ;
#endif /* TIMER_INTR_H_ */
//h文件
主函数文件
定义一个装载值,定时器设定的自动装载模式,当定时器溢出时,装载值会写入寄存器,重新进行新的计数周期,这样可以用来多次中断。还有一个比较重要的预分频器(PSC),比方说我们要一秒产生一个中断,有两种方式,一个是通过计算装载值与定时器时钟频率的倍数之比来算,还有一种就是通过预分频,将定时器的时钟频率降低,例如:zynq cpu的系统频率为666.66MHz,定时器的频率是CPU的一半,即333.33MHz,原定667*1000*1000 / 2-1装载值,运行产生中断是一秒一次,当设置预分频,为二分频时,装载值不变的话,2秒才能产生一个中断。
#include "timer_intr.h"
#include "timer_intr.h"
#include "sys_intr.h"
static XScuGic GIC; //GIC
static XScuTimer Timer;//timer
int main(void)
{
unsigned int TIMER_LOAD_VALUE ;
TIMER_LOAD_VALUE = 667*1000*1000 / 2 ;
TIMER_LOAD_VALUE -= 1 ;
Init_Intr_System(&GIC);
Timer_init(&Timer,0 ,TIMER_LOAD_VALUE,0);
Timer_Setup_Intr_System(&GIC,&Timer,TIMER_IRPT_INTR);
Timer_start(&Timer);
while(1) ;
}
运行结果我们下载到板子上之后,会在串口显示:

秒数会不断增加。至此实验结束。
24.10.22
1144

被折叠的 条评论
为什么被折叠?



