UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

栏目: 编程工具 · 发布时间: 6年前

内容简介:在在這篇文章,我們要講的則是如何透過(本文以

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-A53 中我們題到了如何透過 Vivado 去建立我們的專案,讓 UltraZed-EG PCIe Carrier Card 上的處理器系統 (Processing Syste, PS) 裡面的 Cortex-A53 可以透過 AXI_GPIO 去對可程式邏輯區 (Programmable Logic, PL) 端的 LEDs D12 ~ D19 進行輸出的控制。

在這篇文章,我們要講的則是如何透過 AXI_GPIO 來處理 輸入 的控制,並讓 Cortex-R5 根據不同的輸入,在 ps_uart1 輸出不同的訊息,以及控制不同的 LED 亮暗。

(本文以 Vivado 2018.2 進行開發)

開發目標

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-A53 一文很像,只是這次我們把目標轉向 Cortex-R5 ,以及將 GPIO 輸出的功能,改成 GPIO 輸入。

這次我們將透過 ps_uart1 輸出 Cortex-R5 上的訊息,並透過 AXI_GPIO 搭配 interrupt 的使用,去偵測使用者按下可程式邏輯(Programmable Logic, PL) 端的 SW2 ~ SW4 這三個無段按鈕。

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

建立專案

首先讓我們打開 Vivado 吧~ 不過在進行這一步之前,請先確定你有依照 讓 Vivado 有 UltraZed-EG PCIe Carrier Card 的設定檔 一文的說明,讓我們在建立專案的時候可以找到 UltraZed-EG PCIe Carrier Card 這塊板子。

啟動了 Vivado 後,點選 Create New Project

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

接下來指定好專案路徑和名稱

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

選擇 RTL Project ,並將 Do not specify sources at this time 打勾,我們暫時不會匯入已經有的 verilog 程式碼

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

點選 Boards ,選擇 UltraZed-EG PCIe Carrier Card

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

完成專案的建立

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

建立 Block Design

和之前的文章一樣,我們的專案需要用到 Xilinx 一些預先定義好的 IP, 因此使用 Block Design 來建立我們的設計。

首先點選 IP Integrator -> Create Block Design

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

接著點選 OK 建立我們的 Block Design

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

點選 Add IP 按鈕去增加我們需要的 IP 核

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

我們首先尋找 Zynq UltraScale+ MPSoC 並將它加入到我們的 Block Design,並點選 Run BLock Automation 對該 IP 做一些設定

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

由於預設的 Zynq UltraScale+ MPSoC 並不會打開可程式邏輯 (Programmable Logic, PL) 對應到處理器系統 (Processing System, PS) 的中斷控制 (PL-PS interrupt),因此我們要自己打開。

點擊 Zynq UltraScale+ MPSoC 兩下來對其進行設定,你會看到這樣的頁面,選擇 PS-PL Configuration

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

接下來,點選 General -> Interrupts -> PL to PS -> IRQ0[0-7] 將其變成 1 ,完成後點選 OK

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

你會看到我們的 Zynq UltraScale+ MPSoC 增加了 pl_ps_irq0[0:0] 這個輸入界面,如果有需要的話則再 Run Block Automation 一次。

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

接下來,將 Board 裡面的 Push buttons 拉到我們的 Diagram

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

目前電路變成這樣

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

接下來,再把 Board 上的 LED 拉到 axi_gpio_0 上面,讓整個電路變成這樣 UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

axi_gpio_0 點擊兩下,進入到以下設定頁面

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

在這邊,我們將 Enable Interrupt 打開,點選 OK 完成設定

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

我們拉條線將 ip2intc_irpt 接到 pl_ps_irq0[0:0] 上,讓 interrupt 可以運作

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

完成後,點選 Run Connection Automation 進行線路連接,現在電路會變成這樣

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

(注意到 ip2intc_irpt 一定要連接到 pl_ps_irq0[0:0] 上呦,也就是橘色線的這一條)

完成後可以點選 Validate Design 按鈕來確認設計沒問題

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

好了,讓我們來產生 HDL Wrapper 吧 ~

產生 HDL Wrapper

接下來我們要將剛剛用 Block Design 建立的電路變成 verilog 程式碼,因此會需要進行產生 HDL Wrapper 這個步驟。

對你的 Block Design 檔案點選右鍵,選擇 Create HDL Wrapper ,它會根據你專案設定的語言 (VHDL 或是 Verilog) 來產生相對的 HDL 程式碼。

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

由於這次我們不需要對產出來的東西進行修改,因此選 Let Vivado manage wrapper and auto-update 即可

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

好了後,假設你的 Block Design 檔案叫做 design_1.bd ,那就會產生 design_1_wrapper.v 或是 design_1_wrapper.vhdl 這樣的檔案。

產生位元流 (bitstream)

前面的處理都好了後,接下來點選 Program and Debug -> Generate Bitstream 去讓 Viavado 將這個專案產生出 位元流 (bitstream) ,Zynq UltraScale+ 會在開機的時候根據 bitstream 的資訊對 FPGA 進行設定。

這個產生的過程視你的電腦強度如何而決定花多少時間,總之先來泡杯茶吧~

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

當 bitstream 完成後,我們準備執行 Xilinx SDK 來透過寫 C 語言專案來讓 Cortex-R 可以透過 AXI_GPIO 偵測 SW2 ~ SW4 的中斷(interrupt) ,並根據不同按鈕的觸發來對 LED 進行控制。

點選 File -> Export -> Export Hardware 將剛剛產生的硬體資訊輸出給 Xilinx SDK 去。

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

確定你有勾選 Include bitstream 後,點選 OK UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

完成後,執行 Xilinx SDK

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

建立 Xilinx SDK 專案

啟動 Xilinx SDK 後,點選 File -> New -> Application Project 去建立新的專案

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

這邊我命名此一專案為 helloR5 ,並指定為 standalone 的程式,注意到 Processor 要選擇 psu_cortex45_0

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

接下來,我們一樣選擇 Hello World 來作為我們的專案樣板,點選 Finish 完成專案建立。

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

打開 helloworld.c

點選左邊欄位的 helloR5 -> src -> helloworld.c 來編輯我們的主程式,你會看到以下的內容

/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"


int main()
{
    init_platform();

    print("Hello World\n\r");

    cleanup_platform();
    return 0;
}

這個程式預設會直接透過 Xilinx 定義好的 print() 函式透過當前開發板的 ps7_uart 進行輸出,以這塊板子而言,就是透過 ps_uart0 也就是 Linux 端的 /dev/ttyUSB1 會得到訊息,讓我們修改一下預設的輸出吧。

設定輸出的 UART

在本文一開始,我們題到了我們這次希望透過 ps_uart1 輸出,也就是希望 Linux 端的 /dev/ttyUSB0 可以收到訊息,那這樣要怎樣做呢?

首先點選 Xilinx -> Board Support Packages Settings

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

選擇 helloR5_bsp

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

點選 Overview -> standalone 設定 stdinstdoutps_uart1 ,變成如下圖這樣

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

點選 OK ,完成設定,這樣這個專案透過 print() 或是 xil_printf() 輸出的訊息就都是從 ps_uart1 也就是 Linux 端的 /dev/ttyUSB0 進行輸出囉~

透過 SW 控制 LED (輪詢)

由於如果連如何抓 SW2 ~ SW4 的輸入都不會的話,中斷控制大概也不用提了 (笑)。 因此讓我們先用最傳統的方式,透過輪詢 (polling) 的方式取得當前 SW2 ~ SW4 的狀態,並分別控制 LED D12 ~ D14

簡單的 SW2 ~ SW4 資訊取得

讓我們編輯 helloworld.c 將其變成以下

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"
#include "sleep.h"

XGpio sw;

int main()
{
    init_platform();

    // Initialize SW2 ~ SW4
    int ret = XGpio_Initialize(&sw, XPAR_GPIO_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
            return XST_FAILURE;

    // Setup gpio direction to IN, SW is at axi_gpio0 channel 1
    XGpio_SetDataDirection(&sw, 1, 0xFF);

    print("Hello Cortex-R5\n\r");

    // Polling the SW2 ~ SW4 input result
    while (1) {
            int val = XGpio_DiscreteRead(&sw, 1);
            switch (val) {
            case 0x4:
                    xil_printf("SW 4 pressed!\n\r");
                    break;
            case 0x1:
                    xil_printf("SW 3 pressed!\n\r");
                    break;
            case 0x2:
                    xil_printf("SW 2 pressed!\n\r");
                    break;
            }
            // delay a bit here for 10ms
            usleep(100 * 1000);
    }

    cleanup_platform();
    return 0;
}

這個程式,基本上和 UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-A53 時對 LED 進行輸出控制差不多,只是將原本的輸出變成了輸入。

特別要注意的事情是,由於輪詢 (polling) 的速度很快,因此我們在迴圈裡面加入了 usleep() 來做點延遲。

你可以依照下載到開發板 (一次性)上面的下載方式,並得到以下結果 (按一下 SW2 ~ SW4 看看)

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

確認至少 SW2 ~ SW4 的設定沒錯後,再來看看如何透過中斷 (Interrupt) 來取得這些按鈕的狀態並控制 LED 的亮暗吧 ~

加入 LED 的控制

在上面,我們做到了偵測 SW2 ~ SW4 不同按鍵按下的狀態,這次就根據我們的結果來控制對應的 LED D12 ~ D14 吧,我們在 print("Hello Cortex-R5\n\r"); 後面加入我們對 LED 的初始化~

#define LED_CHANNEL 2
XGpio led;

int main()
{
    // skip ....
    print("Hello Cortex-R5\n\r");

    // Initialize LEDs
    ret = XGpio_Initialize(&led, XPAR_GPIO_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
            return XST_FAILURE;

    // Set direction on GPIO_0 channel 2 to output (LED)
    XGpio_SetDataDirection(&led, LED_CHANNEL, 0xff);

    // polling the SW2 ~ SW4 input result
    while (1) {
            int val = XGpio_DiscreteRead(&sw, 0x1);
            switch(val) {
            case 0x4:
                    xil_printf("SW 4 pressed!\n\r");
                    XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x4); // D14: ON
                    break;
            case 0x1:
                    xil_printf("SW 3 pressed!\n\r");
                    XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x2); // D13: ON
                    break;
            case 0x2:
                    xil_printf("SW 2 pressed!\n\r");
                    XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x1); // D12: ON
                    break;
            }
            // delay a bit here for 10ms
            usleep(100 * 1000);
    }
    // skip ...
}

在這邊,要特別提到我們定義的 LED_CHANNEL 這個巨集,它到底是幹啥麼用的呢? 如果將 LED 相關控制的程式,和我們的電路對照在一起就明顯啦 ~

Code

#define LED_CHANNEL 2

XGpio led;

// Initalize GPIO_0
XGpio_Initialize(&led, XPAR_GPIO_0_DEVICE_ID);

// Set direction on GPIO_0 channel 2 to output (LED)
XGpio_SetDataDirection(&led, LED_CHANNEL, 0xff);

// Make D14 ON (GPIO_0 channel 2)
XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x4); // D14: ON

AXI_GPIO_0

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

是的,由於我們在建立 axi_gpio_0 的時候,將 LED 用的輸出腳放入到了 GPIO_0Channel 2 上,因此就是需要這樣設定才能點亮它~

完整程式碼

到目前為止,透過輪詢(polling)來取得 SW2 ~ SW4 並分別控制 D12 ~ D14 的 LED 完整程式碼如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"
#include "sleep.h"

#define LED_CHANNEL 2

XGpio sw;
XGpio led;

int main()
{
    init_platform();

    // Initialize SW2 ~ SW4
    int ret = XGpio_Initialize(&sw, XPAR_GPIO_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
            return XST_FAILURE;

    // Setup gpio direction to IN, SW is at axi_gpio0 channel 1
    XGpio_SetDataDirection(&sw, 1, 0xff);

    print("Hello Cortex-R5\n\r");

    // Initialize LEDs
    ret = XGpio_Initialize(&led, XPAR_GPIO_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
            return XST_FAILURE;

    // Set direction on GPIO_0 channel 2 to output (LED)
    XGpio_SetDataDirection(&led, LED_CHANNEL, 0xff);

    // Polling the SW2 ~ SW4 input result
    while (1) {
            int val = XGpio_DiscreteRead(&sw, 0x1);
            switch(val) {
            case 0x4:
                    xil_printf("SW 4 pressed!\n\r");
                    XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x4); // D14: ON
                    break;
            case 0x1:
                    xil_printf("SW 3 pressed!\n\r");
                    XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x2); // D13: ON
                    break;
            case 0x2:
                    xil_printf("SW 2 pressed!\n\r");
                    XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x1); // D12: ON
                    break;
            }
            // Delay a bit here for 10ms
            usleep(100 * 1000);
    }

    cleanup_platform();
    return 0;
}

我們將來看如何透過中斷來達到一樣的事情~

透過 SW 控制 LED (中斷)

了解了如何透過輪詢(polling) 的方式來使用 GPIO 相關的函式庫後,這次來將剛剛的程式改寫成中斷 (interrupt) 的版本吧 !

清理目前的程式

我們先將剛剛的輪詢的程式清理成這樣,好方便後面程式的撰寫

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"
#include "sleep.h"

#define LED_CHANNEL 2

XGpio sw;
XGpio led;

int main()
{
    init_platform();

    // Initialize SW2 ~ SW4
    int ret = XGpio_Initialize(&sw, XPAR_GPIO_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
            return XST_FAILURE;

    // Setup gpio direction to IN, SW is at axi_gpio0 channel 1
    XGpio_SetDataDirection(&sw, 1, 0xff);

    print("Hello Cortex-R5\n\r");

    // Initialize LEDs
    ret = XGpio_Initialize(&led, XPAR_GPIO_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
            return XST_FAILURE;

    // Set direction on GPIO_0 channel 2 to output (LED)
    XGpio_SetDataDirection(&led, LED_CHANNEL, 0xff);

    /// <--- NOTE: Other Codes will be inserted here !!

    // wait here
    while (1) ;
    cleanup_platform();
    return 0;
}

加入中斷控制

我們先在 while (1); 前面加入我們對中斷控制器初始化用的函式 My_InterruptInitializer()

// skip ...

int main()
{
    /// <--- NOTE: Other Codes will be inserted here !!
    ret = My_InterruptInitialize(XPAR_SCUGIC_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
        return XST_FAILURE;

    // wait here
    while (1) ;
    cleanup_platform();
    return 0;
}

並在程式最前面,加入中斷相關的標頭檔 xscugic.h ,還有一些方便我們撰寫程式用的巨集

#include "xscugic.h"

#define SW_INT XGPIO_IR_CH1_MASK
#define GPIO_0_INTERRUPT_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR

XScuGic gic;

在這邊, SW_INT 主要是幫助我們知道 axi_gpio_0 的通道 (channel) 遮罩 (mask) ,好讓我們知道當前是 axi_gpio_0 的哪個通道 (channel) 發出了中斷 (interrupt)

GPIO_0_INTERRUPT_ID 則是對應到 Xilinx SDK 自動幫我們定義好的中斷編號,你可以到 helloR5_bsp 裡面去找對應的數值。

我們先定義一旦進入到中斷時,相對應處理的函式 SW_Irq_Handler() ,在這邊,我們做的事情和輪詢(polling) 的版本很像,都是抓到 SW 的輸入後,讓相對應的 LED 進行輸出。

不同的地方是,這個函式會在中斷被觸發的時候執行。

當進入到中斷的時候,我們要先關掉該設備的中斷,避免受到干擾,而當中斷結束後,則是要回復這些設定。

有一點要注意的事情是,在中斷處理的函式中,要 盡可能的快速處理 這樣才可以避免影響到整體系統的其他程式。

void SW_Irq_Handler(void *gpio)
{
    // Disable GPIO Interrupts
    XGpio_InterruptDisable(gpio, SW_INT);

    // Ignore addition button press
    if ((XGpio_InterruptGetStatus(gpio) & SW_INT) != SW_INT)
        return;

    int val = XGpio_DiscreteRead(gpio, 1);
    switch(val) {
        case 0x4:
            xil_printf("SW 4 pressed!\n\r");
            XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x4); // D14: ON
            break;
        case 0x1:
            xil_printf("SW 3 pressed!\n\r");
            XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x2); // D13: ON
            break;
        case 0x2:
            xil_printf("SW 2 pressed!\n\r");
            XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x1); // D12: ON
            break;
    }

    // Clear the interrupt bit
    XGpio_InterruptClear(gpio, SW_INT);
    // Enabl GPIO interrupts
    XGpio_InterruptEnable(gpio, SW_INT);
}

完成中斷的處理函式後,我們需要將它餵給中斷控制器,讓它知道哪些設備要處理中斷,因此讓我們來弄我們的 My_InterruptInitialize()

這邊的初始化很單存,首先先初始化中斷控制器,並將剛剛的 SW_Irq_Handler() 註冊給這個控制器後,啟用 GPIO 的中斷後,就完成了。

int My_InterruptInitialize(u16 DeviceID)
{
    // Interrpt controller initizlization
    XScuGic_Config *IntcConfig = XScuGic_LookupConfig(DeviceID);
    int ret = XScuGic_CfgInitialize(&gic, IntcConfig, IntcConfig->CpuBaseAddress);
    if (ret != XST_SUCCESS)
        return XST_FAILURE;

    // Register Interrupt handler
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
                                 (Xil_ExceptionHandler) XScuGic_InterruptHandler,
                                 &gic);
    Xil_ExceptionEnable();

    // Connect GPIO interrupt to handler
    ret = XScuGic_Connect(&gic, GPIO_0_INTERRUPT_ID,
                          (Xil_ExceptionHandler) SW_Irq_Handler,
                          (void *) &sw);

    if (ret !=  XST_SUCCESS)
        return XST_FAILURE;

    // Enable GPIO Interrupts
    XGpio_InterruptEnable(&sw, SW_INT);
    XGpio_InterruptGlobalEnable(&sw);

    // Enable GPIO interrupts in the controller
    XScuGic_Enable(&gic, GPIO_0_INTERRUPT_ID);

    return XST_SUCCESS;
}

好啦~ 程式完成啦,可以準備下載了。 如果覺的哪些地方很模糊的話,完整的程式碼如下

完整程式碼

完整的程式碼如下:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"
#include "sleep.h"
#include "xscugic.h"

XGpio sw;
XGpio led;
XScuGic gic;

#define LED_CHANNEL 2
#define SW_INT XGPIO_IR_CH1_MASK
#define GPIO_0_INTERRUPT_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR

void SW_Irq_Handler(void *gpio)
{
    // Disable GPIO Interrupts
    XGpio_InterruptDisable(gpio, SW_INT);

    // Ignore addition button press
    if ((XGpio_InterruptGetStatus(gpio) & SW_INT) != SW_INT)
        return;

    int val = XGpio_DiscreteRead(gpio, 1);
    switch(val) {
        case 0x4:
            xil_printf("SW 4 pressed!\n\r");
            XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x4); // D14: ON
            break;
        case 0x1:
            xil_printf("SW 3 pressed!\n\r");
            XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x2); // D13: ON
            break;
        case 0x2:
            xil_printf("SW 2 pressed!\n\r");
            XGpio_DiscreteWrite(&led, LED_CHANNEL, 0x1); // D12: ON
            break;
    }

    // Clear the interrupt bit
    XGpio_InterruptClear(gpio, SW_INT);
    // Enabl GPIO interrupts
    XGpio_InterruptEnable(gpio, SW_INT);
}

int My_InterruptInitialize(u16 DeviceID)
{
    // interrpt controller initizlization
    XScuGic_Config *IntcConfig = XScuGic_LookupConfig(DeviceID);
    int ret = XScuGic_CfgInitialize(&gic, IntcConfig, IntcConfig->CpuBaseAddress);
    if (ret != XST_SUCCESS)
        return XST_FAILURE;

    // Register Interrupt handler
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
                                 (Xil_ExceptionHandler) XScuGic_InterruptHandler,
                                 &gic);
    Xil_ExceptionEnable();


    // Connect GPIO interrupt to handler
    ret = XScuGic_Connect(&gic, GPIO_0_INTERRUPT_ID,
                          (Xil_ExceptionHandler) SW_Irq_Handler,
                          (void *) &sw);

    if (ret !=  XST_SUCCESS)
        return XST_FAILURE;

    // Enable GPIO Interrupts
    XGpio_InterruptEnable(&sw, SW_INT);
    XGpio_InterruptGlobalEnable(&sw);

    // Enable GPIO interrupts in the controller
    XScuGic_Enable(&gic, GPIO_0_INTERRUPT_ID);

    return XST_SUCCESS;
}

int main()
{
    init_platform();

    // Initialize SW2 ~ SW4
    int ret = XGpio_Initialize(&sw, XPAR_GPIO_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
        return XST_FAILURE;

    // setup gpio direction to IN
    XGpio_SetDataDirection(&sw, 1, 0xff);

    print("Hello Cortex-R5\n\r");

    // Initialize LEDs
    ret = XGpio_Initialize(&led, XPAR_GPIO_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
        return XST_FAILURE;

    // setup gpio direction to OUT
    XGpio_SetDataDirection(&led, 2, 0xff);

    // Initialize Interrupt
    ret = My_InterruptInitialize(XPAR_SCUGIC_0_DEVICE_ID);
    if (ret != XST_SUCCESS)
        return XST_FAILURE;

    // wait for interrupt triggered
    while (1) ;
    cleanup_platform();
    return 0;
}

設定 JTAG 下載

為了透過 Micro USB 連接到 UltraZed-EG PCIe Carrier Card 上的 JTAG 來進行下載,我們需要對 UltraZed-EG 上的 SW2 要進行一些調整,變成下圖這樣。

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

這樣子就可以透過 Micro USB 走 JTAG 下載的路線,將程式下載下去

下載到開發板 (一次性)

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-A53 一文不同的是,這次我們不再分別下載 FPGA 和我們的程式,這次採用一次性下載的方案

點選 Run -> Run Configurations

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

Xilinx C/C++ Application (GDB) 建立新的設定,並設定如下:

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

點入 Application 確定我們的程式會下載到 psu_cortexr5_0

UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5

這樣就完成囉,點選 Run 就會看到 Xilinx SDK 先燒錄 FPGA 再下載這次的程式了~

結果

按照本篇文章的設定,你的 UltraZed-EG PCIe Carrier Card 顯示應該如以下影片:

另外,我們也可以透過 minicom , emacs , tio , gtkterm 等終端機軟體,連接上 /dev/ttyUSB0 來查看透過 printf() 輸出的訊息。

取得程式碼

本文的範例已經上傳到 coldnew/ultrazed_pciecc_helloR5 ,你可以透過以下命令獲得

git clone https://github.com/coldnew-examples/ultrazed_pciecc_helloR5.git

以上所述就是小编给大家介绍的《UltraZed-EG PCIe Carrier Card 開發紀錄: Hello Cortex-R5》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法竞赛入门经典

算法竞赛入门经典

刘汝佳、陈锋 / 2012-10 / 52.80元

《算法竞赛入门经典:训练指南》是《算法竞赛入门经典》的重要补充,旨在补充原书中没有涉及或者讲解得不够详细的内容,从而构建一个较完整的知识体系,并且用大量有针对性的题目,让抽象复杂的算法和数学具体化、实用化。《算法竞赛入门经典:训练指南》共6章,分别为算法设计基础、数学基础、实用数据结构、几何问题、图论算法与模型和更多算法专题,全书通过近200道例题深入浅出地介绍了上述领域的各个知识点、经典思维方式......一起来看看 《算法竞赛入门经典》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具