第十四章 ZYNQ TIMER定時器中斷


 

上篇文章實現了了PS接受來自PL的中斷,本片文章將在ZYNQ的純PS里實現私有定時器中斷。每隔一秒中斷一次,在中斷函數里計數加1,通過串口打印輸出。

本文所使用的開發板是Miz702 PC 開發環境版本:Vivado 2015.4 Xilinx SDK 2015.4

14.0本章難度系數★★☆☆☆☆☆

14.1中斷原理

中斷對於保證任務的實時性非常必要,在ZYNQ里集成了中斷控制器GIC(Generic Interrupt Controller).GIC可以接受I/O外設中斷IOP和PL中斷,將這些中斷發給CPU。 
中斷體系結構框圖圖下:
wps949F.tmp

14.1.1軟件中斷(SGI)

SGI通過寫ICDSGIR寄存器產生SGI.

14.1.2共享中斷SPI

通過PS和PL內各種I/O和存儲器控制器產生。

14.1.3私有中斷(PPI)

包含:全局定時器,私有看門狗定時器,私有定時器以及來自PL的FIQ/IRQ。本文主要介紹PPI,其它的請參考官方手冊ug585_Zynq_7000_TRM.pdf。 
ZYNQ每個CPU鏈接5個私有外設中斷,所有中斷的觸發類型都是固定不變的。並且來自PL的快速中斷信號FIQ和中斷信號IRQ反向,然后送到中斷控制器因此盡管在ICDICFR1寄存器內反應的他們是低電平觸發,但是PS-PL接口中為高電平觸發。如圖所示: 
wps94A0.tmp

14.1.4私有定時器

zynq中每個ARM core都有自己的私有定時器,私有定時器的工作頻率為CPU的一半,比如Miz702的ARM工作頻率為666MHZ,則私有定時器的頻率為333MHz. 
私有定時器的特性如下:
(1)32位計數器,達到零時產生一個中斷 
(2)8位預分頻計數器,可以更好的控制中斷周期 
(3)可配置一次性或者自動重加載模式 
(4)定時器時間可以通過下式計算: 
定時時間 = [(預分頻器的值 + 1) (加載值 + 1)]/定時器頻率

14.2 搭建硬件工程

Step1:新建一個名為為Miz702_sys的工程

wps94A1.tmp

Step2:選擇RTL Project 勾選Do not specify source at this time

wps94B2.tmp

Step3:由於Miz702兼容zedboard 因此選擇zedboard開發包

wps94B3.tmp

Step4:單擊Finish

wps94B4.tmp

14.3使用IP Integrator創建硬件系統

Step1:單擊Create Block Design

Step2:輸入system

wps94B5.tmp

Step3:單擊下圖中wps94C5.tmp添加IP按鈕

wps94C6.tmp

Step4:搜素單詞z選擇ZYNQ7 Processing System,然后雙擊

wps94C7.tmp

Step5:添加進來了ZYNQ CPU IP,然后單擊Run Block Automation

wps94C8.tmp

Step6:直接單擊OK

wps94D9.tmp

Step7:在你點擊了OK后,你會發現DDR以及FICED_IO自勱的延伸出來。

wps94DA.tmp

Step8:連線的作用就是把PS的時鍾可以接入PL部分,當然這里我們暫時用不到PL部分的資源。在Block文件中,我們進行連線,將鼠標放在引腳處,鼠標變成鉛筆后迚行拖拽,連線如下圖所示:

wps94DB.tmp

Step9: 右擊 system.bd, 單擊Generate Output Products

wps94DC.tmp

Step10:支部操作會產生執行、仿真、綜合的文件

wps94EC.tmp

Step11:右擊system.bd 選擇 Create HDL Wrapper 這步的作用是產生頂層的HDL文件

wps94ED.tmp

Step12:選擇Leave Let Vivado manager wrapper and auto-update 然后單擊OK

Step13:執行->產生bit文件wps94EE.tmp

14.4導出SOC硬件到SDK

Step1:File->Export->Export Hardware

wps94EF.tmp

Step2:勾選Include bitstream 直接單擊OK

wps9500.tmp

Step3:File->Launch SDK加載到SDK

wps9501.tmp

Step4:單擊OK

wps9502.tmp

14.5 建立軟件工程

建立一個TIMER_INTC空的工程,並且添加main.c 添加如下代碼

#include <stdio.h>

#include "xadcps.h"

#include "xil_types.h"

#include "Xscugic.h"

#include "Xil_exception.h"

#include "xscutimer.h"

//timer info

#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

//#define TIMER_LOAD_VALUE  0x0FFFFFFF

#define TIMER_LOAD_VALUE    0x13D92D3F

//static XAdcPs  XADCMonInst; //XADC

static XScuGic Intc; //GIC

static XScuTimer Timer;//timer

static void SetupInterruptSystem(XScuGic *GicInstancePtr,

        XScuTimer *TimerInstancePtr, u16 TimerIntrId);

static void TimerIntrHandler(void *CallBackRef);

int main()

{

     XScuTimer_Config *TMRConfigPtr;     //timer config

     printf("------------START-------------\n");

   //  init_platform();

     //

     //私有定時器初始化

     TMRConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);

     XScuTimer_CfgInitialize(&Timer, TMRConfigPtr,TMRConfigPtr->BaseAddr);

     XScuTimer_SelfTest(&Timer);

     //加載計數周期,私有定時器的時鍾為CPU的一般,為333MHZ,如果計數1S,加載值為1sx(333x1000x1000)(1/s)-1=0x13D92D3F

     XScuTimer_LoadTimer(&Timer, TIMER_LOAD_VALUE);

     //自動裝載

     XScuTimer_EnableAutoReload(&Timer);

     //啟動定時器

     XScuTimer_Start(&Timer);

     //set up the interrupts

     SetupInterruptSystem(&Intc,&Timer,TIMER_IRPT_INTR);

     while(1){

     }

     return 0;

}

void SetupInterruptSystem(XScuGic *GicInstancePtr,

        XScuTimer *TimerInstancePtr, u16 TimerIntrId)

{

        XScuGic_Config *IntcConfig; //GIC config

        Xil_ExceptionInit();

        //initialise the GIC

        IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);

        XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,

                        IntcConfig->CpuBaseAddress);

        //connect to the hardware

        Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,

                    (Xil_ExceptionHandler)XScuGic_InterruptHandler,

                    GicInstancePtr);

        //set up the timer interrupt

        XScuGic_Connect(GicInstancePtr, TimerIntrId,

                        (Xil_ExceptionHandler)TimerIntrHandler,

                        (void *)TimerInstancePtr);

        //enable the interrupt for the Timer at GIC

        XScuGic_Enable(GicInstancePtr, TimerIntrId);

        //enable interrupt on the timer

        XScuTimer_EnableInterrupt(TimerInstancePtr);

        // Enable interrupts in the Processor.

        Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);

    }

static void TimerIntrHandler(void *CallBackRef)

{

    static int sec = 0;   //計數

    XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;

    XScuTimer_ClearInterruptStatus(TimerInstancePtr);

    sec++;

    printf(" %d Second\n\r",sec);  //每秒打印輸出一次

}

14.6測試結果

可以看到串口終端每秒輸出一次,並且值加1遞增。

14.7本章小結

中斷對於實時系統是非常重要的,可以說是是實時性的保障吧。本章簡要介紹了ZYNQ的中斷原理和中斷類型,詳細介紹了私有定時器,建立了完整的工程進行測試。

淘寶店鋪:https://osrc.taobao.com

官網論壇:www.osrc.cn

視頻鏈接:http://www.osrc.cn/forum.php?mod=viewthread&tid=1104

源碼鏈接:http://pan.baidu.com/s/1bAstrC 密碼:wv3i


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM