版本:Vivado2020.2(Vitis)
任务:使用定时器 (私有定时器) 中断 实现 LED(PS端) 定时1s亮灭翻转
目录
一、介绍
Zynq系列是Xilinx(现为AMD)推出的集成了ARM Cortex-A9双核处理器和FPGA的可编程SoC器件。在Zynq中,定时器是重要的外设模块,用于时间测量、延时控制和周期性中断触发等。
Zynq主要有以下几种定时器:
-
私有定时器(Private Timer) - 每个ARM核都有一个私有定时器
-
全局定时器(Global Timer) - 双核共享的64位定时器
-
看门狗定时器(Watchdog Timer、WDT) - 用于系统监控和复位
-
三重定时器计数器(TTC) - FPGA侧提供的定时器
像 PS 端延时可以用定时器中断方式进行操作,以让cpu执行其他重要操作。
二、硬件设计
ZYNQ 的配置使用到了 MIO(LED灯)、UART(用于Debug)、DDR(存储器),跟之前的工程案例相比没有额外的特殊配置,下面这幅图是CPU的工作频率,保持默认666.666MHz,定时器驱动时钟是其二分之一,也就是333.333MHz(后面会用到)

最后整体 bd 设计部分如图所示:设计检查、Generate Output Products、 Create HDL Wrapper、(管脚约束、Gnerate Bitstream、(无PL端设计这两部忽略))、Export Hardware(不用包含比特流文件)、启动Vitis

三、软件设计
可以打开官方提供的私有定时器的示例工程,这里可以选定时器中断的示例工程,方便在设计时进行对照参考。

cs
#include "xparameters.h"
#include "xil_printf.h"
#include "xgpiops.h"
#include "xscutimer.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "sleep.h"
//===========================自定义宏=========================//
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID //宏定义GPIO器件ID
#define MIO_LED 7 //宏定义LED管脚(PS端LED,根据开发板设值,这里对应GPIO MIO 7)
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //宏定义中断控制器(GIC)ID
#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID //宏定义TIMER器件ID
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR //宏定义TIMER中断号(中断ID)
#define TIMER_LOAD_VALUE 0x13DE4354 //定时器计数值(定时器驱动时钟333.333MHz为CPU时钟(默认666.66MHz)一半,周期约3ns,定时1s计数333_333_333 -1 次)
//===========================实例化===========================//
XGpioPs Gpio; //GPIO示例
XScuGic Intc; //中断控制器实例
XScuTimer Timer; //定时器实例
//=======================函数、变量声明=======================//
static void Gpio_Init(); //GPIO初始化
static void Timer_Intr_Init(); //定时器中断初始化
static void LED_blink(); //LED闪烁测试
static void Timer_IntrHandler(void *CallBackRef); //定时器中断处理函数
static void Setup_Intr_System(XScuGic *intr, XScuTimer *timer, u16 timer_intr_id); //建立中断系统
//===========================主函数===========================//
int main()
{
xil_printf("SCU Timer Interrupt Test! \r\n");
Gpio_Init(); //GPIO初始化
LED_blink(); //LED闪烁测试
Timer_Intr_Init(); //定时器中断初始化
while(1)
return 0;
}
//=====================定时器中断处理函数=====================//
// @param CallBackRef 用户自定义回调参数(对应TIMER实例指针)
void Timer_IntrHandler(void *CallBackRef)
{
static int led_state = 0;
//将回调参数转为TIMER实例指针,用于操作硬件(例规范化设计)
XScuTimer *TimerInstPtr = (XScuTimer *) CallBackRef;
//打印Debug信息
xil_printf("Interrupt Detected! \r\n");
//清除定时器中断标志位
XScuTimer_ClearInterruptStatus(TimerInstPtr);
//翻转LED状态值
led_state = ~led_state;
//写数据到GPIO引脚(PS端LED)
XGpioPs_WritePin(&Gpio, MIO_LED, led_state);
}
//=========================GPIO初始化========================//
void Gpio_Init()
{
//定义器件ID(指针类型)
XGpioPs_Config * ConfigPtr;
//根据器件ID,查找器件配置信息
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//初始化GPIO的驱动
XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
//GPIO方向设置(0输入/1输出)
XGpioPs_SetDirectionPin(&Gpio, MIO_LED, 1);
//设置输出使能(1使能)
XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED, 1);
}
//======================定时器中断初始化======================//
void Timer_Intr_Init()
{
//定义器件ID(指针类型)
XScuTimer_Config *ConfigPtr;
//根据器件ID,查找器件配置信息
ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
//初始化定时器的驱动
XScuTimer_CfgInitialize(&Timer, ConfigPtr,ConfigPtr->BaseAddr);
//(可选)定时器自检
int Status = XScuTimer_SelfTest(&Timer);
if (Status != XST_SUCCESS) { xil_printf("Timer Self Test Error! \r\n"); }
//建立中断系统(调用函数)
Setup_Intr_System(&Intc, &Timer, TIMER_IRPT_INTR);
//加载计数值(计数上限)
XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);
//使能自动加载模式(计完自动加载计数值,不启用计完一次结束)
XScuTimer_EnableAutoReload(&Timer);
//启动定时器
XScuTimer_Start(&Timer);
}
//=======================建立中断系统=======================//
/* 建立中断系统,UART接收到数据时产生中断
* @param intr 是指向 XScuGic驱动实例的指针
* @param timer 是指向 XScuTimer驱动实例的指针
* @param timer_intr_id 是TIMER中断ID
*/
void Setup_Intr_System(XScuGic *intr, XScuTimer *timer, u16 timer_intr_id)
{
//定义中断控制器配置信息(指针)
XScuGic_Config * IntcConfig;
//根据中断控制器ID,查找GIC配置信息
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
//初始化中断控制器驱动
XScuGic_CfgInitialize(intr, IntcConfig, IntcConfig->CpuBaseAddress);
//设置中断异常处理功能
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler) XScuGic_InterruptHandler,
(void *) intr);
//使能处理器中断
Xil_ExceptionEnable();
//关联中断处理函数
XScuGic_Connect(intr, timer_intr_id,
(Xil_ExceptionHandler) Timer_IntrHandler,
(void *) timer);
//使能GIC中的定时器中断
XScuGic_Enable(intr, timer_intr_id);
//使能定时器中断
XScuTimer_EnableInterrupt(timer);
}
//========================LED闪烁测试========================//
void LED_blink()
{
for(int i=0; i<3; i++)//闪烁3次
{
//向GPIO写1 、延时200ms、写0、延时
XGpioPs_WritePin(&Gpio, MIO_LED, 1); usleep(200000);
XGpioPs_WritePin(&Gpio, MIO_LED, 0); usleep(200000);
}
}
四、效果
上板后会先打印测试信息,然后LED灯快速闪烁3次(说明MIO配置无误),此后每秒定时器会产生中断,并将LED的状态翻转,效果为每两秒闪烁一次
