ZYNQ筆記(5):軟中斷實現核間通信


  ZYNQ包括一個 FPGA 和兩個 ARM,多個 ARM 核心相對獨立的運行不同的任務,每個核心可能運行不同的操作系統或裸機程序,但是有一個主要核心,用來控制整個系統以及其他從核心的允許。因此我們可以在 CPU0 和 CPU1 中獨立跑不同的應用程序,發揮雙核的非對稱性架構的優勢和性能。

   從軟件的角度來看,多核處理器的運行模式主要有三種:

  ① AMP(非對稱多進程):多個核心相對獨立的運行不同的任務,每個核心可能運行不同的操作系統或裸機程序,但是有一個主要核心,用來控制整個系統以及其它從核心的運行。

  ② SMP(對稱多進程):一個操作系統同等的管理各個內核,例如 PC 機。

  ③ BMP(受約束多進程):與 SMP 類似,但開發者可以指定將某個任務僅在某個指定內核上執行默認情況下。

  裸機程序 ZYNQ 僅運行一個 CPU,這里主要講解 AMP 模式下,兩個 CPU 同時運行的裸機程序開發方法。

一、核間中斷原理(軟中斷SGI)

  軟中斷的 ID 都是從0到15,並且都是上升沿觸發,主要用於核間中斷或者 CPU 自己中斷自己。

  中斷函數如下:

XScuGic_SoftwareIntr(&InterruptController,   //指向GIC指針
                     INTC_CPU0,                //需要中斷的CPU ID
                     XSCUGIC_SPI_CPU0_MASK);   //使能該CPU會接受中斷
 

 

二、ARM啟動過程

1.ARM 里有個 ROM,存儲了一段程序,ROM起來后從 SD 卡讀取數據
2.啟動 FSBL(First Boot Loader)第一啟動項(有模板)
3.加載 bit(FPGA配置程序),同時加載 elf(ARM應用程序),如果是操作系統則 elf 替換成 uBoot

 

三、搭建軟件 CPU0 和 CPU1 非對稱環境

1.創建 amp_fsbl 用於生成燒寫鏡像的時候加載 core0 和 core1的代碼。

①啟動 Vivado,創建 ZYNQ,勾選  SD卡 和 UART 即可,並加載 SDK 開發環境

②進到 SDK ,點擊 File --- New --- Application Project,命名為 amp_fsbl 並選擇 CPU0

③選擇 FSBL,finish

④修改 main.c 函數來啟動 core1,需要兩個步驟,首先把 CPU1 應用程序地址寫入到 0xfffffff0地址中,這是啟動 CPU1 命令的地址,然后執行 sev 指令加載 CPU1 應用程序。具體參考 UG585 的啟動代碼章節。

在 main.c 函數的 main 函數上方插入這段代碼:

 1 #define sev() __asm__("sev")
 2 #define CPU1STARTADR 0xFFFFFFF0
 3 #define CPU1STARTMEM 0x2000000
 4 
 5 void StartCpu1(void)
 6 {
 7     #if 1
 8     fsbl_printf(DEBUG_GENERAL,"FSBL: Write the address of the application for CPU 1 to 0xFFFFFFF0\n\r");
 9     Xil_Out32(CPU1STARTADR, CPU1STARTMEM);
10     dmb(); //waits until write has finished
11     fsbl_printf(DEBUG_GENERAL,"FSBL: Execute the SEV instruction to cause CPU 1 to wake up and jump to the application\n\r");
12     sev();
13     #endif
14 }

在 main.c 函數的 load鏡像位置加入代碼: StartCpu1(); 

2.創建 app_cpu0 應用程序

①重新創建一個新的 File --- New --- Application Project,命名為 app_cpu0,這時選擇的是 CPU0

②選擇 helloworld 模板即可

③將 helloworld.c 改名為 mian.c,並且用如下代碼替換掉內容

 1 #include <stdio.h>
 2 #include "platform.h"
 3 #include "xil_printf.h"
 4 
 5 #define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000)) //無優化無符號長整形地址轉成指針
 6 
 7 int main()
 8 {
 9     COMM_VAL=0;
10 
11     //Disable cache on OCM
12     Xil_SetTlbAttributes(0xFFFF0000,0x14de2);
13     while(1)
14     {
15         print("Hello World cpu0 \n\r");
16         COMM_VAL =1;
17         while(COMM_VAL == 1)
18         {
19         }
20     }
21     return 0;
22 }

該指針指向的地址為片上存儲的共享內存(OCM)。可以指定這里面的任意一個地址。定義的指針變量如下所示: #define COMM_VAL (*(volatile unsigned long *)(0x00020000)) 該變量CPU0和CPU1都可以在里面讀寫數據,可以達到CPU0和CPU1的數據交互。OCM的地址如下圖所示。

④打開 Scr 目錄中的文件 lscript.ld,點擊下方的 Source 做如下修改:CPU0 的代碼空間改為 1E00000

CPU1運行程序的地址改為fsbl里面指定的起始地址。后面為長度,有一點需要注意:CPU0的起始地址加上CPU0的長度之后不能超過CPU1的起始地址。也就是兩個CPU占用的DDR的地址不能重疊。若程序很大,則CPU0需要的LENGTH就大,因此CPU1的起始地址數值就大。DDR地址范圍如下所示:

3.創建 app_cpu1 應用程序

①重新創建一個新的 File --- New --- Application Project,命名為 app_cpu1,這時選擇的是 CPU1

②選擇 helloworld 模板即可

③將 helloworld.c 改名為 mian.c,並且用如下代碼替換掉內容

 1 #include <stdio.h>
 2 #include "platform.h"
 3 #include "xil_printf.h"
 4 
 5 #define COMM_VAL (*(volatile unsigned long *)(0xFFFF0000))
 6 int main()
 7 {
 8     //Disable cache on OCM
 9     Xil_SetTlbAttributes(0xFFFF0000,0x14de2);
10     while(1)
11     {
12         while(COMM_VAL == 0)
13         {
14         }
15     print("Hello World cpu1 \n\r");
16     sleep(2);
17     COMM_VAL=0;
18     }
19     return 0;
20 }

④打開 Scr 目錄中的文件 lscript.ld 點擊下方的 Source 做如下修改起始地址改為 0x2000000 長度 0x1F00000

4.增加編譯選項(設置 CPU1 的BSP setting 為 AMP 模式)

app_cpu1_bps --- 右鍵 --- Board Suport Package Setting,點擊 driver --- ps7_cortexa9_0,添加指令

5.讓雙核跑起來

①點擊 app_cpu0 --- 右鍵 --- Debug As --- Debug Configurations...

② 點擊選項卡的 Application,勾選 0 和 1,然后點擊 Debug,yes

③默認停到第一行,連接好串口,選擇APU --- ARM --- #0,單步慢慢走可以看到有信息打印出,#2也是一樣的。如果讓 #0 和 #1 都一直執行,則串口會一直交替打印。

 

四、軟中斷的注冊和使用

 

參考資料:

    [1]V3學院FPGA教程

    [2]何賓, 張艷輝. Xilinx Zynq-7000嵌入式系統設計與實現[M]. 電子工業出版社, 2016.


免責聲明!

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



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