上一章实现了PS端接收PL端的中断,本章主要在ZYNQ的PS端实现定时器中断:
(1)软件中断(SGI)
SGI通过写ICDSGIR寄存器产生SGI中断
(2)共享中断(SPI)
通过PS和PL内各种I/O和存储器控制器产生
(3)私有中断(PPI)
包含:全局定时器,私有看门狗定时器,私有定时器以及来自PL端的FIQ/IRQ
ZYNQ的每一个ARM core都有自己的私有定时器,私有定时器的工作频率是CPU的一半
私有定时器的特性如下:
(1)32位计数器,到达0产生一个中断
(2)8位预分频计数器,更好控制中断周期
(3)可配置一次性或自动重加载模式
所以,定时器记录时间=T*(预加载值+1)
前面的步骤与之前PL端中断是相同的,同样配置两个按键
/*
* main.c
*
*
* Author: Administrator
*/
#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 INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR
#define TIMER_LOAD_VALUE 0x13D92D3F
static XScuGic Intc; //GIC
static XScuTimer Timer;//timer
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; //GIC config
Xil_ExceptionInit();
//initialise the GIC
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,//connect to the hardware
GicInstancePtr);
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
XScuTimer_EnableInterrupt(TimerInstancePtr);//enable interrupt on the timer
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); //Enable interrupts in the Processor.
}
int main()
{
XScuTimer_Config *TMRConfigPtr; //timer config
printf("------------START-------------\n");
//私有定时器初始化
TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);//通过查找配置这个程序可以获取参数
XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr->BaseAddr);
//XScuTimer_SelfTest(&Timer);
//加载计数周期,私有定时器的时钟为CPU的一般,为333MHZ,如果计数1S,加载值为1sx(333x1000x1000)(1/s)-1=0x13D92D3F
//程序的指针与测试程序(装载预加载值的寄存器)
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;
}
对于初始化程序XScuTimer_CfgInitialize,在这个定时器被其他函数调用之前,这个函数必须先被调用(用了一个特定的函数来检测传递进来的参数是否是空的,如果是,则不能正常跳转到下一个语句)
(二)URAT中断
前面步骤同样相同,主要分析main.c程序
/*
* main.c
*
* Created on: 2016年6月26日
* Author: Administrator
*/
#include <stdio.h>
#include "xadcps.h"
#include "xil_types.h"
#include "Xscugic.h"
#include "Xil_exception.h"
#include "xuartps.h"
//timer info
#define UART_DEVICE_ID XPAR_PS7_UART_1_DEVICE_ID //URAT的设备ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //中断的设备ID
#define UART_IRPT_INTR XPAR_XUARTPS_1_INTR //URAT的中断号(URAT1为82)
static XScuGic Intc; //GIC 结构体指针
static XUartPs Uart;// uart 结构体指针
static void UartIntrHandler(void *CallBackRef)
{
XUartPs *InstancePtr = (XUartPs *) CallBackRef;
u32 IsrStatus;
u32 ReceivedCount=0;
u32 CsrRegister;
/*
* Read the interrupt ID register to determine which
* interrupt is active
*/
IsrStatus = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,
XUARTPS_IMR_OFFSET);//e0001000+10=regaddr=e0001010
IsrStatus &= XUartPs_ReadReg(InstancePtr->Config.BaseAddress,
XUARTPS_ISR_OFFSET);//e0001000+14=regaddr=e0001014
/* Dispatch an appropriate handler. */
if((IsrStatus & ((u32)XUARTPS_IXR_RXOVR | (u32)XUARTPS_IXR_RXEMPTY |
(u32)XUARTPS_IXR_RXFULL)) != (u32)0) {
CsrRegister = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,//判断FIFO触发标准位
XUARTPS_SR_OFFSET);//e0001000+2c=regaddr=e000102c
while((CsrRegister & XUARTPS_SR_RXEMPTY)== (u32)0){//读取FIFO中所有数据
//InstancePtr->ReceiveBuffer.NextBytePtr[ReceivedCount] =//每次循环读取1byte
;
XUartPs_WriteReg(InstancePtr->Config.BaseAddress,//每次循环发送读取到的数据
XUARTPS_FIFO_OFFSET,
XUartPs_ReadReg(InstancePtr->Config.
BaseAddress,
XUARTPS_FIFO_OFFSET));
ReceivedCount++;//计数
CsrRegister = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,
XUARTPS_SR_OFFSET);
}
}
printf("this time ReceivedCount=%d\r\n",ReceivedCount);
XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_ISR_OFFSET,
IsrStatus);
}
void SetupInterruptSystem(XScuGic *GicInstancePtr,
XUartPs *UartInstancePtr, u16 UartIntrId)
{
XScuGic_Config *IntcConfig; //GIC config
Xil_ExceptionInit();
//initialise the GIC
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,//connect to the hardware
GicInstancePtr);
Xil_ExceptionEnable();
XScuGic_Connect(GicInstancePtr, UartIntrId,
(Xil_InterruptHandler)UartIntrHandler,//set up the timer interrupt
(void *)UartInstancePtr);
XScuGic_Enable(GicInstancePtr, UartIntrId);//enable the interrupt for the Timer at GIC
XUartPs_SetInterruptMask(UartInstancePtr, XUARTPS_IXR_RXOVR/* | XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_TNFUL*/ );
// XUartPs_EnableUart(UartInstancePtr);//enable interrupt on the timer
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); //Enable interrupts in the Processor.
}
int main()
{
XUartPs_Config *UartConfigPtr; //timer config
// printf("------------START-------------\n");
UartConfigPtr = XUartPs_LookupConfig(UART_DEVICE_ID);
XUartPs_CfgInitialize(&Uart,UartConfigPtr,UartConfigPtr->BaseAddress);
//set up the interrupts
SetupInterruptSystem(&Intc,&Uart,UART_IRPT_INTR);
while(1);
return 0;
}
在XUartPs_Config中存放的是URAT的设备ID,基地址(在硬件工程中添加了中断后,系统自动生成的)