基於ZYNQ的中斷的使用(4)

項目簡述

前面的文章我們已經講解了ZYNQ的共享中斷、軟中斷,每種中斷的類型我們都進行了相應的講解。ZYNQ的三種中斷類型還差一個私有中斷我們沒有進行講解,接下來我們將以CPU的私有定時器爲例來進行相應私有中斷的講解。

工程描述:CPU利用私有定時器進行定時,每隔1s產生相應的中斷,並且通過串口進行相應的打印。

本次實驗所用到的軟硬件環境如下:
1、VIVADO 2019.1
2、米聯客MZ7015FA開發板

私用中斷簡述

包含:全局定時器,私有看門狗定時器,私有定時器以及來自 PL 的 FIQ/IRQ。ZYNQ 每個 CPU 連接 5 個私有外設中斷,所有中斷的觸發類型固定不變。並且來自 PL 的快速中斷信號 FIQ 和中斷信號 IRQ 反向。儘管在 ICDICFR1 寄存器內反應它們是低電平觸發,但是 PS-PL 接口中爲高電平觸發。如圖所示:
在這裏插入圖片描述
本篇博客主要利用上面的CPU 私有定時器爲例來講解私用中斷,ZYNQ 每個 ARM core 都有自己的私有定時器,私有定時器的工作頻率爲 CPU 的一半。 ARM 工作頻率爲 666MHZ,則私有定時器的頻率爲 333MHz.
私有定時器的特性如下:
(1) 32 位計數器,達到零時產生一箇中斷
(2) 8 位預分頻計數器,可以更好的控制中斷週期
(3)可配置一次性或者自動重加載模式
(4)定時器時間可以通過下式計算:
定時時間 = 1/定時器頻率*(預加載值+1)

PS端設計

這裏PL端只需要例化一個ZYNQ的IP,其他部分不需要進行任何處理,所以PL端我們沒有進行相應的設計。其中,Block Design設計如下:
在這裏插入圖片描述

PL端設計

這裏的GUI的初始化與前面的一樣,相當於增加了定時器的初始化,代碼如下:

#include <stdio.h>
#include "xscugic.h"
#include "xparameters.h"
#include "sleep.h"
#include "xscutimer.h"

#define GIC_ID 				XPAR_PS7_SCUGIC_0_DEVICE_ID
#define TIMER_IRPT_INTR     XPAR_SCUTIMER_INTR
#define TIMER_DEVICE_ID     XPAR_XSCUTIMER_0_DEVICE_ID
#define TIMER_LOAD_VALUE    0x13D92D3F //1S

static XScuGic ScuGic;
static XScuGic_Config * ScuGicCfgPtr;

XScuTimer Timer;
XScuTimer_Config  *Config;

volatile int usec;
//initial gic & software intr
int initSwIntr();
//callback func
void TimerIntrHandler(void *CallBackRef);
int initimer();


int main()
{
	int status;
	status = initSwIntr();
	status = initimer();
	if(status != XST_SUCCESS){
		return status;
	}
	while(1){
		usleep(100000);

	}
    return 0;
}


int initSwIntr(){
	int status;
	Xil_ExceptionInit();
	ScuGicCfgPtr = XScuGic_LookupConfig(GIC_ID);
	status = XScuGic_CfgInitialize(&ScuGic,ScuGicCfgPtr,ScuGicCfgPtr->CpuBaseAddress);
	if(status != XST_SUCCESS){
		return status;
	}
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
	status = XScuGic_Connect(&ScuGic,TIMER_IRPT_INTR,(Xil_ExceptionHandler)TimerIntrHandler,&Timer);
	if(status != XST_SUCCESS){
			return status;
	}
	XScuGic_Enable(&ScuGic,TIMER_IRPT_INTR);
	Xil_ExceptionEnable();

	return XST_SUCCESS;
}

int initimer(){
	int status;
	Config = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
	status = XScuTimer_CfgInitialize(&Timer, Config, Config->BaseAddr);
    XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);
    //自動裝載
    XScuTimer_EnableAutoReload(&Timer);
	XScuTimer_Start(&Timer);
	XScuTimer_EnableInterrupt(&Timer);//一定等定時器初始化好了之後再開始使能定時器中斷
	return status;
}

void TimerIntrHandler(void *CallBackRef){
    XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
    XScuTimer_ClearInterruptStatus(TimerInstancePtr);
    usec++;
    printf(" %d Second\n\r",usec);  //每秒打印輸出一次
}

這裏需要特別注意的一點是,一定等定時器初始化好了之後再開始使能定時器中斷,否則將無法成功運行。在這裏插入圖片描述
需要清除中斷狀態寄存器中的狀態:
在這裏插入圖片描述
裝載寄存器的初值:
在這裏插入圖片描述
設置自動填裝初值模式:
在這裏插入圖片描述
啓動定時器:
在這裏插入圖片描述

下板測試

將上面的代碼進行下班測試,結果如下:
在這裏插入圖片描述
可以看出每隔1s,PS端進行一次打印,從而證明了實驗的正確性。

總結

創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。爲行業貢獻及其微小的一部分。對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章