總結Zynq-7000 這款器件中的Timer定時器中斷,為FreeRTOS中斷做准備。在 ZYNQ 的純 PS 里實現私有定時器中斷。 每隔一秒中斷一次, 在中斷函數里計數加 1, 通過串口打印輸出。
私有中斷PPI包含: 全局定時器, 私有看門狗定時器, 私有定時器以及來自 PL 的 FIQ/IRQ。 ZYNQ 每個 CPU 鏈接 5 個私有外設中斷, 所有中斷的觸發類型都是固定不變的。 並且來自 PL 的快速中斷信號 FIQ 和中斷信號 IRQ 反向, 然后送到中斷控制器。因此盡管在ICDICFR1 寄存器內反應的他們是低電平觸發, 但是 PS-PL 接口中為高電平觸發。 UG585中P229如下表所示。
zynq 中每個 ARM core 都有自己的私有定時器, 私有定時器的工作頻率為 CPU 的一半, 比如 ARM 工作頻率為 666MHZ,則私有定時器的頻率為 333MHz。
私有定時器的特性如下:
(1) 32 位計數器, 達到零時產生一個中斷
(2) 8 位預分頻計數器, 可以更好的控制中斷周期
(3) 可配置一次性或者自動重加載模式
(4) 定時器時間可以通過下式計算:定時時間 = 1/定時器頻率*(預加載值+1) 。
<以下知識點來自米聯客公開教程!>
ARM體系的處理器中通常將低地址32字節作為中斷向量表,當中斷產生時會執行以下操作:
- 保存處理器當前狀態,設置中斷屏蔽位和各條件標志位
- 設置當前程序狀態寄存器CPSR中相應位
- 將lr_mode寄存器設置成返回地址
- 跳轉到中斷向量地址執行,從而跳轉到相應的中斷程序中執行
- 執行中斷處理函數內容
- 恢復被屏蔽的中斷屏蔽位
- 返回到被中斷指令的下一條指令處繼續執行
zynq中低32字節作為中斷向量表,每個中斷占據4字節,這4字節通常存儲一個跳轉指令,從而跳轉到中斷解析程序中。這低32字節中斷向量表如:
| 地址 |
中斷類型 |
異常中斷模式 |
優先級 |
說明 |
| 0x00 |
復位中斷 |
特權模式(SVC) |
1 |
系統上電和系統復位或軟復位時產生 |
| 0x04 |
未定義指令中斷 |
未定義指令中止模式(Undef) |
6 |
當執行的指令不是ARM處理器或協處理器的指令時產生 |
| 0x08 |
軟件中斷(SWI) |
特權模式(SVC) |
6 |
用戶定義中斷指令,可用於用戶模式下調用特權操作指令 |
| 0x0c |
指令預取中止 |
中止模式 |
5 |
當預取指令地址不存在或地址不允許當前指令訪問時產生 |
| 0x10 |
數據訪問中止 |
中止模式 |
2 |
當數據訪問指令的目的地址不存在或地址不允許當前指令訪問時產生 |
| 0x14 |
保留 |
無 |
無 |
無 |
| 0x18 |
外部中斷請求(IRQ) |
外部中斷模式 |
4 |
處理器外部中斷請求引腳有效而且CPSR的I位被清除時產生 |
| 0x1c |
快速中斷請求(FIQ) |
快速中斷模式 |
3 |
處理器外部快速中斷請求引腳有效而且CPSR的F位被清除時產生 |
code:
/* * 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 "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; }
