国产电影一区二区三区,,欧美大片免费观看,伊人久久大香线蕉av,国产日韩成人内射视频

ZYNQ-定時器中斷使用

學習內容

本文首先介紹了ZYNQ的定時器的相關內容,并學習使用ZYNQ芯片中的定時器進行操作測試。

開發環境

vivado 18.3&SDK,PYNQ-Z2開發板。

定時器簡介

介紹

ZYNQ有兩個Cortex-A9處理器,每個Cortex-A9處理器都有自己的專用32位計時器和32位看門狗計時器。兩個都處理器共享一個全局64位計時器。這些計時器始終以1/2的CPU頻率計時(CPU_3x2x)。在系統層級,有一個24位看門狗定時器和兩個16位三重定時器/計數器。系統看門狗定時器的時鐘頻率為CPU頻率(CPU_1x)的1/4或1/6,時鐘也可以由來自MIO引腳或PL的外部信號。兩個三重計時器/計數器時鐘頻率為在CPU頻率(CPU_1x)的1/4或1/6,可以用于計算來自MIO引腳或來自PL的脈沖寬度。

系統框圖

下圖為ZYNQ內部的定時器的系統框圖。

在圖中顯示,定時器部分包括系統看門狗、CPU內部的看門狗定時器,CPU私有的定時器,全局定時器,三重定時器。其中所有的定時器都可以觸發中斷控制器進行中斷控制的操作,看門狗定時器(無論是系統 的還是CPU內部的)都可以對系統進行一個復位操作。

CPU私有定時器和看門狗定時器

關于CPU私有定時器和看門狗定時器均具有以下功能:

  1. 32位計數器,在達到零時會產生中斷
  2. 八位預分頻器,可以更好地控制中斷周期
  3. 可配置的單次或自動重裝模式
  4. 計數器的可配置起始值
  5. 定時器和看門狗復位信號發送到PS復位子系統
  6. 所有私有計時器和看門狗計時器始終以CPU頻率(CPU_3x2x)的1/2計時。

下圖為CPU私有定時器和看門狗定時器寄存器表:

全局定時器(GT)

全局定時器是具有自動遞增功能的64位遞增計數器。全局計時器在與專用計時器相同的地址空間中映射到內存中。全局計時器僅在復位時以安全狀態訪問。 所有Cortex-A9處理器均可訪問全局計時器。每個Cortex-A9處理器都有一個64位比較器,用于在全局計時器達到比較器值時聲明一個私有中斷。全局定時器始終以CPU頻率(CPU_3x2x)的1/2計時。全局定時器(GT)寄存器功能表如下圖:

系統看門狗定時器(SWDT)

除了兩個CPU私有看門狗定時器之外,還有一個系統看門狗定時器(SWDT),可以在系統發生故障時,如PS PLL鎖相失敗,此時看門狗可以產生一個復位信號讓程序重啟,從而保證系統正常運行。與CPU私有看門狗定時器不同的是,SWDT的時鐘可以來自于外部設備或者PL端,用于提供一個復位信號輸出到PL端口或者外部設備。

特征

SWDT的主要功能如下:

  1. 內部24位計數器。
  2. 可選時鐘輸入,時鐘信號可以來自:1. 內部PS總線時鐘(CPU_1x);2. 內部時鐘(來自PL);3. 外部時鐘(來自MIO)。
  3. 計時超時時,可以進行系統中斷(PS)和系統重置(PS,PL,MIO)。
  4. 可編程超時時間:1. 超時范圍32,760至68,719,476,736個時鐘周期(在100 MHz時可配置范圍為330 µs至687.2s)。
  5. 超時時,可編程的輸出信號持續時間:系統中斷脈沖(4、8、16或32個時鐘周期(CPU_1x時鐘))。

系統看門狗定時器寄存器功能表如圖:

編程指南

系統看門狗定時器使能順序如下:

  1. 使用slcr.WDT_CLK_SEL [SEL]位選擇時鐘輸入源 :確保禁用SWDT(swdt.MODE [WDEN] = 0),并且將時鐘輸入源設置為選定的正在運行,然后繼續此步驟。更改時鐘輸入源時,啟用SWDT會導致無法預測的行為。時鐘輸入源更改為非運行時鐘導致APB訪問掛起。
  2. 設置超時時間(計數器控制寄存器) :swdt.CONTROL [CKEY]字段必須為0x248,才能寫入此寄存器。
  3. 啟用計數器;使能輸出脈沖 ;設置輸出脈沖長度(零模式寄存器):swdt.MODE [ZKEY]字段必須為0xABC,才能寫入此寄存器。確保IRQLN符合指定的最小值。
  4. 要使用其他設置運行SWDT,請首先禁用定時器(swdt.MODE [ZKEY]位)。然后重復上述步驟。

三重計時器(TTC)

TTC包含三個獨立的計時器/計數器。PS端中有兩個TTC模塊,總共六個計時器/計數器。可以使用 nic301_addr_region_ctrl_registers.security_apb [ttc1_apb]寄存器位將TTC 1控制器配置為安全或非安全模式。TTC控制器中的三個計時器具有相同的安全狀態。

特征

每個三重計時器/計數器都具有以下特征:

  1. 三個獨立的16位預分頻器和16位向上/向下計數器。
  2. 可選時鐘輸入,來自:1. 內部PS總線時鐘(CPU_1x);2. 內部時鐘(來自PL);3. 外部時鐘(來自MIO)。•每個計數器有一個中斷。•可以產生溢出中斷,定時中斷或計數中斷,可編程初始值。•可以生成通過MIO到PL的波形輸出(例如PWM)。

三重計時器/計數器寄存器功能表如圖:

計數器編程啟用順序

  1. 選擇時鐘輸入源,設置預分頻值。(slcr.MIO_MUX_SEL寄存器,TTC時鐘控制)在繼續執行此操作之前,請確保已禁用TTC(ttc.Counter_Control_x [DIS] = 1)。
  2. 設置間隔值(間隔寄存器)。 此步僅適用于間隔模式。(可選不配置)
  3. 設置匹配值(匹配寄存器)。 如果要啟用匹配,可以配置此操作。(可選不配置)
  4. **使能中斷(中斷使能寄存器)。**如果要啟用中斷,可以配置此操作。(可選不配置)
  5. 啟用/禁用波形輸出,啟用/禁用匹配,設置計數方向,設置模式,使能計數器(TTC計數器控制寄存器)。 此步驟完成后將啟動計數器。

計數器編程停止順序

  1. 讀回計數器控制寄存器的值。
  2. 將DIS位設置為1,同時保留其他位。
  3. 寫回計數器控制寄存器。

計數器編程重啟順序

  1. 讀回計數器控制寄存器的值。
  2. 將RST位設置為1,同時保留其他位。
  3. 寫回計數器控制寄存器。

事件計時器啟用序列

  1. 選擇外部脈沖源(slcr.MIO_MUX_SEL寄存器)。選定外部待測脈沖。
  2. 設置溢出處理,選擇外部脈沖電平,啟用事件計時器(事件控制計時器寄存器)。此步驟開始測量外部所選電平(高或低)的寬度脈沖。
  3. 使能中斷(中斷使能寄存器)。如果要啟用中斷,可以配置此操作。(可選不配置)
  4. 讀取測量的寬度(事件寄存器)。

中斷清除和應答序列

  1. 讀取中斷寄存器:讀取時清除中斷寄存器中的所有位。

系統框圖

本次工程系統框圖如下圖所示。

調用UART、TIMER、GPIO資源進行開發設計,UART串口引腳直接連接到MIO,GPIO引腳連接到PL端的EMIO引腳,由ARM核進行配置定時器中斷操作,實現定時中斷進行流水燈操作。

硬件平臺搭建

新建工程,創建 block design。添加ZYNQ7 ip,根據本次工程需要對IP進行配置。勾選本次工程使用的資源。

硬件系統構建完成如下:

然后我們進行generate output product 然后生成HDL封裝。這里用到了UART和GPIO,所以需要進行管腳分配。這里使用的是PYNQZ2開發板,該板卡可直接引用以下約束文件:

#LEDs
set_property -dict { PACKAGE_PIN R14   IOSTANDARD LVCMOS33 } [get_ports { EMIO_LED_tri_io[0] }]; #IO_L6N_T0_VREF_34 Sch=led[0]
set_property -dict { PACKAGE_PIN P14   IOSTANDARD LVCMOS33 } [get_ports { EMIO_LED_tri_io[1] }]; #IO_L6P_T0_34 Sch=led[1]
set_property -dict { PACKAGE_PIN N16   IOSTANDARD LVCMOS33 } [get_ports { EMIO_LED_tri_io[2] }]; #IO_L21N_T3_DQS_AD14N_35 Sch=led[2]
set_property -dict { PACKAGE_PIN M14   IOSTANDARD LVCMOS33 } [get_ports { EMIO_LED_tri_io[3] }]; #IO_L23P_T3_35 Sch=led[3]

完成約束后,進行綜合和布局布線,生成bit流,然后點擊導出硬件資源(包含bit流文件),接著launch SDK。

SDK軟件部分

打開SDK后,新建application project。在system.mss中可以打開相關參考文檔輔助設計。

可以選擇timer中斷的例程進行參考設計,導入uart_intr_example例程模板,

在main.c中輸入以下代碼:

#include 
#include "xparameters.h"
#include "xscutimer.h"
#include "xscugic.h"
#include "xgpiops.h"
#include "xil_exception.h"
#include "xil_printf.h"
//聲明定義
#define GPIO_ID             XPAR_PS7_GPIO_0_DEVICE_ID
#define TIMER_ID            XPAR_PS7_SCUTIMER_0_DEVICE_ID
#define INTR_DEVICE_ID      XPAR_SCUGIC_SINGLE_DEVICE_ID
#define TIMER_IRPT_INTR		XPAR_SCUTIMER_INTR

#define LOAD_VALUE 0X9AF8D9F//0.5s流水 系統時鐘650M  定時器時鐘325M 周期3ns

#define LED0 54
#define LED1 55
#define LED2 56
#define LED3 57

//聲明示例結構體
XGpioPs GpioPs;
XScuTimer Timer;
XScuGic ScuGic;

//函數定義
void Emio_init();
void Timer_init();
void Timer_intr_init(XScuGic *intr, XScuTimer *time);
void Timer_IntrHandler(void *CallBackRef);
int main(){
	//EMIO初始化
	Emio_init();
	//初始化定時器
	Timer_init();
	//初始化中斷
	Timer_intr_init(&ScuGic,&Timer);
	//啟動定時器
	XScuTimer_Start(&Timer);
	while(1);
	return0;
}

void Emio_init(){
	XGpioPs_Config *XGpioPs_Cfg;
	XGpioPs_Cfg = XGpioPs_LookupConfig(GPIO_ID);
	XGpioPs_CfgInitialize(&GpioPs,XGpioPs_Cfg,XGpioPs_Cfg->BaseAddr);

	XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);

	XGpioPs_SetDirectionPin(&GpioPs,LED1,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED1,0x01);

	XGpioPs_SetDirectionPin(&GpioPs,LED2,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED2,0x01);

	XGpioPs_SetDirectionPin(&GpioPs,LED3,0x01);
	XGpioPs_SetOutputEnablePin(&GpioPs,LED3,0x01);
}

void Timer_init(){
	int Status;
	XScuTimer_Config *ConfigPtr;
	//初始化定時器
	ConfigPtr = XScuTimer_LookupConfig(TIMER_ID);
	XScuTimer_CfgInitialize(&Timer, ConfigPtr,ConfigPtr->BaseAddr);
	//定時器自檢測
	Status = XScuTimer_SelfTest(&Timer);
	if (Status != XST_SUCCESS) {
		printf("timer selftest failed!\n");
	}
	printf("timer selftest success!\n");
	//裝載初值
	XScuTimer_LoadTimer(&Timer, LOAD_VALUE);
	//使能自動裝載模式
	XScuTimer_EnableAutoReload(&Timer);
}

void Timer_intr_init(XScuGic *intr, XScuTimer *time){
	XScuGic_Config *IntcConfig;
	//初始化定時器中斷
	IntcConfig = XScuGic_LookupConfig(INTR_DEVICE_ID);
	XScuGic_CfgInitialize(intr,IntcConfig,IntcConfig->CpuBaseAddress);
	//初始化中斷異常函數
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
			(Xil_ExceptionHandler)XScuGic_InterruptHandler,
			intr);
	Xil_ExceptionEnable();
	//設置中斷服務函數
	XScuGic_Connect(intr, TIMER_IRPT_INTR,
					(Xil_ExceptionHandler)Timer_IntrHandler,
					(void *)time);
	//使能中斷控制器
	XScuGic_Enable(intr, TIMER_IRPT_INTR);
	//使能定時器
	XScuTimer_EnableInterrupt(time);

}
//中斷處理函數
void Timer_IntrHandler(void *CallBackRef){
	staticchar led_status=0x01;
	XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
	if(XScuTimer_IsExpired(TimerInstancePtr)){
		led_status = led_status<<1;
		if(led_status == 0X10)
			led_status =0x01;
		XGpioPs_WritePin(&GpioPs,LED0,led_status);
		XGpioPs_WritePin(&GpioPs,LED1,led_status>>1);
		XGpioPs_WritePin(&GpioPs,LED2,led_status>>2);
		XGpioPs_WritePin(&GpioPs,LED3,led_status>>3);
		XScuTimer_ClearInterruptStatus(TimerInstancePtr);
	}
}

部分代碼講解

在主函數中引用了Emio_init();Timer_init();Timer_intr_init(&ScuGic,&Timer);分別完成初始化GPIO操作,初始化定時器,初始化中斷定時器等操作。最后用XScuTimer_Start(&Timer);啟動定時器。

對于定時器初始化設置主要要對計數模式進行設置,對初始值進行裝載配置 也就是調用下面的函數:

//裝載初值
	XScuTimer_LoadTimer(&Timer, LOAD_VALUE);
	//使能自動裝載模式
	XScuTimer_EnableAutoReload(&Timer);

這里LOAD_VALUE表示需要計時或者計數的次數,因為這里的代碼實現的是led的0.5s定時中斷,系統CPU時鐘為650M,所以定時器的時鐘頻率為325M,也就是周期為3.07ns,計算0.5s下的計數次數得到這里需要裝載的初值。(也即為0X9AF8D9F)

Reference

  1. UG585
  2. 正點原子ZYNQ開發視頻
聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯系:editor@netbroad.com
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 0
收藏 1
關注 17
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧