zcu102_6_AXI_TIMER精確計時
阿新 • • 發佈:2019-01-14
部落格配套原碼工程已上傳https://download.csdn.net/download/botao_li/10915619
AXI Timer
axi_timer模組即為PS可以訪問的PL計數器,通過計數值以及接入axi_timer的計數時鐘週期,可以在PS內取得比較精確的計時
axi_timer有2種使用方式,一種是作為計數器使用,另一種是作為定時器使用
Block Design
建立Vivado工程,新建Block Design,並且新增zynq模組,AXI Timer模組,以及ILA模組
保持zynq模組的預設配置
使能UART0,連線至MIO 18 19,用於串列埠顯示除錯資訊
新增PL至PS的中斷輸入介面
雙擊axi_timer模組,按下圖設定
在Block Design中自動連線和手動連線之後,完成設計
在Vivado中生成bitstream,並且Export to Hardware,之後開啟SDK
SDK
建立helloworld模板工程,雙擊helloworld.c新增功能程式碼
注意,無論axi_timer模組作為計數器還是定時器,都是每個時鐘週期計數增1或者減1,由於在Block Design中時鐘輸入介面來源於PS模組的時鐘輸出,注意需要開啟PS模組設定介面確認Actual Frequency
在SDK建立的BSP工程中,xparameters.h也儲存該頻率值XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ
具體程式設計參考自BSP中system.mss中匯入的示例程式
計數器程式碼
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xtmrctr.h"
#include "sleep.h"
int main()
{
print("axi_timer test\r\n");
int sta = -1;
//timer初始化
XTmrCtr tmr;
sta = XTmrCtr_Initialize(&tmr, XPAR_AXI_TIMER_0_DEVICE_ID) ;//ID來自於xparameters.h定義
if (sta != XST_SUCCESS)
{
return XST_FAILURE;
}
//如果timer沒有自動載入模式
//向上計數溢位時置為0值停止計數
//向下計數溢位時置為0xFFFFFFFF時停止計數
//設定timer1的option為自動載入模式
//在不設定reset value的情況下,計數暫存器迴圈計數
//在設定reset value的情況下
//計數暫存器向上計數至0xFFFFFFFF後變為reset value
//計數暫存器向下計數至0後變為reset value
//option為mask形式,定義見xtmrctr.h
XTmrCtr_SetOptions(&tmr, 0, XTC_AUTO_RELOAD_OPTION);//axi_timer模組中timer1的num為0,timer2的num為1
// XTmrCtr_SetOptions(&tmr, 0, XTC_DOWN_COUNT_OPTION);
//timer1計數值
u32 v = 0;
//取得timer1的當前計數值,start之前值為0
v = XTmrCtr_GetValue(&tmr, 0);
printf("timer1 before start = %08x\r\n", v);
//啟動timer1
XTmrCtr_Start(&tmr, 0);
for (int i = 0; i < 8; ++i)
// for (;;)
{
sleep(1);
//取得timer1的當前計數值
v = XTmrCtr_GetValue(&tmr, 0);
//串列埠顯示
printf("timer1 value = %08x\r\n", v);
}
//關閉自動載入模式,清空全部option
XTmrCtr_SetOptions(&tmr, 0, 0);
//停止timer1
XTmrCtr_Stop(&tmr, 0);
//取得timer1的當前計數值,停止計數後,數值保持,不會復位
v = XTmrCtr_GetValue(&tmr, 0);
printf("timer1 after stop = %08x\r\n", v);
return 0;
}
定時器程式碼:
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xtmrctr.h"
#include "sleep.h"
#include "xscugic.h"
//axi_timer自定義中斷響應函式
void tmr_intr(void *CallBackRef, u8 TmrCtrNumber)
{
XTmrCtr *ptr = (XTmrCtr *)CallBackRef;
//取得產生中斷的timer的當前計數值,復位reset value之後,接近該value的值
u32 v = XTmrCtr_GetValue(ptr, TmrCtrNumber);
//串列埠顯示
printf("timer value = %08x\r\n", v);
}
int main()
{
print("axi_timer test\r\n");
int sta = -1;
//timer初始化
XTmrCtr tmr;
sta = XTmrCtr_Initialize(&tmr, XPAR_AXI_TIMER_0_DEVICE_ID);//ID來自於xparameters.h定義
if (sta != XST_SUCCESS)
{
return XST_FAILURE;
}
//查詢中斷配置
XScuGic_Config* intc_conf;
intc_conf = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
if (intc_conf == NULL)
{
return XST_FAILURE;
}
//中斷初始化
XScuGic intc;
sta = XScuGic_CfgInitialize(&intc, intc_conf, intc_conf->CpuBaseAddress);
if (sta != XST_SUCCESS)
{
return XST_FAILURE;
}
//設定timer中斷優先順序及上升沿觸發
XScuGic_SetPriorityTriggerType(&intc, XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR, 0xA0, 0x3);
//設定中斷響應函式為axi_timer的中斷響應函式XTmrCtr_InterruptHandler(非自定義)
//由此中斷響應函式將中斷分發至自定義的中斷響應函式
sta = XScuGic_Connect(&intc, XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR, (Xil_ExceptionHandler)XTmrCtr_InterruptHandler, &tmr);
if (sta != XST_SUCCESS)
{
return XST_FAILURE;
}
//使能中斷
XScuGic_Enable(&intc, XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR);
//使能硬體中斷
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &intc);
Xil_ExceptionEnable();
//將axi_timer連線自定義中斷響應函式
XTmrCtr_SetHandler(&tmr, tmr_intr, &tmr);
//如果timer沒有自動載入模式
//向上計數溢位時置為0值停止計數
//向下計數溢位時置為0xFFFFFFFF時停止計數
//如果timer有自動載入模式
//無論向上還是向下計數,計數溢位時自動wrap
//設定timer1為中斷模式,中斷後由硬體中斷函式XScuGic_InterruptHandler,呼叫軟體中斷函式XTmrCtr_InterruptHandler,再呼叫自定義中斷函式
//設定timer1的option為自動載入模式,計數暫存器迴圈計數
//option為mask形式,定義見xtmrctr.h
XTmrCtr_SetOptions(&tmr, 0, XTC_DOWN_COUNT_OPTION | XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION);//axi_timer模組中timer1的num為0,timer2的num為1
//設定timer1計數暫存器的復位值,即向上計數至0xFFFFFFFF或者向下計數至0時,reload至該值
XTmrCtr_SetResetValue(&tmr, 0, XPAR_AXI_TIMER_0_CLOCK_FREQ_HZ);//復位值為頻率值,並且向下計數則計時1秒
//timer1計數值
u32 v = 0;
//取得timer1的當前計數值,start之前值為?
v = XTmrCtr_GetValue(&tmr, 0);
printf("timer1 before start = %08x\r\n", v);
//啟動timer1
XTmrCtr_Start(&tmr, 0);
while (1)
{
sleep(1);
}
//關閉自動載入模式,清空全部option
XTmrCtr_SetOptions(&tmr, 0, 0);
//停止timer1
XTmrCtr_Stop(&tmr, 0);
//取得timer1的當前計數值,停止計數後,數值保持,不會復位
v = XTmrCtr_GetValue(&tmr, 0);
printf("timer1 after stop = %08x\r\n", v);
return 0;
}