1. 程式人生 > >zcu102_6_AXI_TIMER精確計時

zcu102_6_AXI_TIMER精確計時

部落格配套原碼工程已上傳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;
}