學會Zynq(9)定時器使用示例(PPI)
定時器資源
每個Cortex-A9處理器都有私有的32位定時器和32位看門狗定時器。這兩種定時器都是32位的計數器,計數到0時產生中斷;帶有8位的預分頻器,能夠更好地控制中斷週期;可配置為單次過載或自動過載模式;可配置初始值。它們的工作時鐘固定為CPU頻率的1/2(CPU_3x2x)。
兩個CPU同時共享一個64位的全域性定時器GT,這是一個遞增的計數器,帶有自動遞增功能。全域性定時器與私有定時器在記憶體中對映的地址空間相同。兩個Cortex-A9有各自的64位的比較器,可以共同訪問全域性定時器,達到比較器值時產生一個私有中斷。它的時鐘也固定為CPU頻率的1/2(CPU_3x2x)。
除了兩個CPU的私有看門狗定時器,還有一個24位的系統看門狗SWDT,在發生災難性的系統故障時發出訊號(比如PS中的PLL工作失常)。SWDT可以工作在CPU頻率的1/4或1/6(CPU_1x),也可以工作在裝置外部或PL提供的時鐘下,並向它們輸出一個復位訊號。
此外PS中還有兩個TTC(Triple Timer Counters),每個TTC都有三個獨立的定時器/計數器。TTC只能工作在CPU頻率的1/4或1/6(CPU_1x),Zynq使用該定時器計算來自MIO管腳或PL的訊號脈衝寬度。
私有定時器和看門狗定時器、全域性定時器屬於PPI;SWDT和TTC屬於SPI。各種定時器資源之間的關係如下:
私有定時器的使用
幾種定時器中,私有定時器是最常用的,使用雙核時可能會用到全域性定時器。私有定時器是CPU五種PPI中斷源的一種,固定為上升沿敏感。
做一個簡單的設計體會私有定時器的使用,每隔1s串列埠輸出一次。Vivado中搭建硬體環境,使用最小系統即可,匯出硬體到SDK中。
timer.h檔案的程式碼如下:
#include <stdio.h>
#include "xadcps.h"
#include "xil_types.h"
#include "Xscugic.h"
#include "Xil_exception.h"
#include "xscutimer.h"
//---------------------------------------------------------
// 引數定義
//---------------------------------------------------------
#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 //定時器中斷ID號
#define TIMER_LOAD_VALUE 0x13D92D3F //定時器裝載值
//---------------------------------------------------------
// 函式申明
//---------------------------------------------------------
void SetupInterruptSystem(XScuGic *GicInstancePtr,
XScuTimer *TimerInstancePtr, u16 TimerIntrId);
void TimreInit(XScuTimer Timer, XScuGic Intc);
timer.c檔案的程式碼如下:
#include "timer.h"
//---------------------------------------------------------
// 定時器中斷處理程式
//---------------------------------------------------------
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;
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);
/* 設定中斷異常 */
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler, GicInstancePtr);
Xil_ExceptionEnable();
/* 設定定時器中斷 */
XScuGic_Connect(GicInstancePtr, TimerIntrId,
(Xil_ExceptionHandler)TimerIntrHandler, (void *)TimerInstancePtr);
XScuGic_Enable(GicInstancePtr, TimerIntrId); //使能中斷
XScuTimer_EnableInterrupt(TimerInstancePtr); //使能定時器中斷
}
//---------------------------------------------------------
// 定時器初始化程式
//---------------------------------------------------------
void TimreInit(XScuTimer Timer, XScuGic Intc)
{
/* 私有定時器初始化 */
XScuTimer_Config *TMRConfigPtr;
TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr->BaseAddr);
XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE); // 載入計數週期
XScuTimer_EnableAutoReload(&Timer); // 設定自動裝載模式
SetupInterruptSystem(&Intc,&Timer,TIMER_IRPT_INTR); // 設定定時器中斷
XScuTimer_Start(&Timer); // 啟動定時器
}
mian.c檔案的程式碼如下:
#include "timer.h"
static XScuTimer Timer; //定時器
static XScuGic Intc; //中斷控制器
int main()
{
TimreInit(Timer, Intc);
while(1);
return 0;
}
相關API函式
查閱PPI列表,可以看到私有定時器的中斷號為29。
1.私有定時器初始化
初始化部分中,我們看到了似曾相識的XScuTimer、XscuTimer_Config兩個結構體、XScuTimer_LookupConfig()和XScuTimer_CfgInitialize()兩個函式,只是從“GPIO裝置”、“中斷裝置”換成了“定時器裝置”。這算是Zynq中各種裝置(device)初始化的套路,甚至傳入的引數型別都是十分相近的,這裡不再贅述。
/* 私有定時器初始化 */
XScuTimer_Config *TMRConfigPtr;
TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr->BaseAddr);
2.載入計數週期
使用XScuTimer_LoadTimer()函式載入定時器的計數器中的值,其本質上只是操作Timer Load暫存器。函式原型採用巨集定義,但也可以看作一個C語言風格的函式介面:
#define XScuTimer_LoadTimer(InstancePtr, Value) \
XScuTimer_WriteReg((InstancePtr)->Config.BaseAddr, \
XSCUTIMER_LOAD_OFFSET, (Value))
//可視作如下C語言函式
void XScuTimer_LoadTimer(XScuTimer *InstancePtr, u32 Value)
私有定時器是從裝載值遞減到0時發出中斷。我們這裡預設使用666MHz的CPU時鐘,則私有定時器的工作時鐘為333MHz,每1/333M秒減1。因此若想定時1s,則裝載值為1/(1/333M)-1,將該值在timer.h中巨集定義。
3.設定裝載模式
本例程需要定時器一直工作,因此使用XScuTimer_EnableAutoReload()函式啟用自動裝載模式。不需要時使用XScuTimer_DisableAutoReload()函式禁用自動裝載。這兩個函式本質上也是巨集定義,操作相關暫存器中的相應bit位。下面只給出等效的C語言模型:
void XScuTimer_EnableAutoReload(XScuTimer *InstancePtr)
void XScuTimer_DisableAutoReload(XScuTimer *InstancePtr)
4.設定定時器中斷
這部分通過自定義函式來設定定時器的中斷,過程和第8篇中PL中斷的初始化過程基本相同。實際上用到中斷時基本都要有這個過程:初始化中斷控制器、設定中斷異常、連線中斷、使能中斷。
我們這裡使用的是定時器中斷,連線函式如下。在定時器中斷處理程式中,我們必須清除中斷標誌,因此XscuGic_Connect的第三個引數設定為定時器的控制裝置,在呼叫中斷狀態清除函式時會用到該引數。
XScuGic_Connect(GicInstancePtr, TimerIntrId,
(Xil_ExceptionHandler)TimerIntrHandler, (void *)TimerInstancePtr);
5.清除定時器中斷
中斷處理程式中,除了計時和串列埠列印輸出,還要呼叫XScuTimer_ClearInterruptStatus()函式清除中斷狀態。相關程式碼如下:
XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
XScuTimer_ClearInterruptStatus(TimerInstancePtr);
該函式本質上也是巨集定義,等效的C語言介面如下:
void XScuTimer_ClearInterruptStatus(XScuTimer *InstancePtr)
傳入的XscuTimer*型別的引數在連線定時器中斷時設定。使用時首先要將其從void*型別轉換為XscuTimer*型別。
相關文章
- 學會Zynq(8)PL中斷示例(SPI)
- 學會Zynq(1)搭建Zynq-7000 AP SoC處理器
- 學會Zynq(2)Zynq-7000處理器的配置詳解
- 學會Zynq(5)GPIO中EMIO的使用方法
- 學會Zynq(4)GPIO中MIO的使用方法
- 學會Zynq(12)lwIP 1.4.1庫的配置與使用
- 學會Zynq(10)lwIP簡介
- 學會Zynq(3)Zynq的軟體開發基礎知識
- Camunda定時器事件示例Demo(Timer Events)定時器事件
- SMP PPI中斷使用
- 微控制器學習(六)定時器的使用定時器
- 學會Zynq(7)中斷系統簡介
- FPGADesigner《學會Zynq》系列目錄與傳送門FPGA
- 學會Zynq(6)固化程式到SD卡或QSPI FlashSD卡
- 學會Zynq(11)RAW API的TCP和UDP程式設計APITCPUDP程式設計
- Java定時器之Timer學習二Java定時器
- MySQL定時器EVENT學習筆記MySql定時器筆記
- 小米9 SE定時開關機怎麼設定?小米9 SE定時開機關機設定方法教程
- ZYNQ 中PS端GPIO EMIO使用
- 定時器以及定時器的幾個案例定時器
- JS學習之Bom(window和定時器)JS定時器
- 從零開始再學 JavaScript 定時器JavaScript定時器
- Spring 定時器的使用—Xml、Annotation、自定義Spring定時器XML
- Spring 定時器的使用---Xml、Annotation、自定義Spring定時器XML
- Xilinx-ZYNQ7000系列-學習筆記(7):解決ZYNQ IP核自動佈線後會更改原有配置的問題筆記
- ZYNQ核心板使用者手冊
- ZYNQ PS端IIC介面使用-筆記筆記
- JavaScript定時器JavaScript定時器
- iOS定時器iOS定時器
- Timer(定時器)定時器
- JavaScript 定時器JavaScript定時器
- js定時器JS定時器
- python定時器Python定時器
- javascript定時器(setTimeout和setInterval)的使用詳解JavaScript定時器
- 使用 PubSubHubbub 製作 RSS 定時器 —— Laravel RSS (三)定時器Laravel
- 直播軟體開發,ScheduledExecutorService定時器的使用定時器
- 驅動開發:核心使用IO/DPC定時器定時器
- 純生JS輪播,定時器新增和清除定時器JS定時器