那曲檬骨新材料有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

ZYNQ開發雙核運行原理及過程

454398 ? 來源:FPGA技術聯盟 ? 作者:FPGA技術聯盟 ? 2020-12-05 10:48 ? 次閱讀

雙核運行原理

ZYNQ是一種主從關系的AMP架構,通過松散耦合共享資源,允許兩個處理器同時運行自己的操作系統或者裸機應用程序,在各自運行自己的程序或者系統的時候,可以通過共享內存進行雙核之間的交互。雙核啟動中,cpu0完成系統的初始化,與cpu1進行通信,讀寫共享內存。

共享資源防止沖突

1. DDR的內存使用,CPU0使用內存地址為0x00100000-0x001fffff,CPU1的使用地址應該避開這段地址,使用地址設為0x00200000-0x003fffff;

2. CPU1不使用L2內存,僅僅CPU0使用;

3. CPU1從核心在PL的中斷路由到PPI控制器,通過使用PPI將中斷路由到核心,而CPU0通過ICD路由到核心;

4. 當CPU0訪問共享內存的時候,CPU1不訪問,同理,CPU1訪問共享內存的時候,CPU0不訪問。

雙核運行的過程

ZYNQ是一個可擴展平臺,就是有FPGA作為外設的A9雙核處理器,它的啟動流程與FPGA完全不同,而與傳統的ARM處理器類似,ZYNQ的啟動配置需要多個處理步驟,通常情況,需要包含以下3個階段:

1. 階段1:在芯片上電運行后,處理器自動開始stage0-boot,就是片內的BOORROM中的代碼,上電復位或者熱復位后,處理器執行不可修改的代碼;

2. 階段2:BOORROM初始化CPU和一些外設后,讀取下一個階段所需的程序代碼FSBL(first stage boot loader),它是可以由用戶修改控制的代碼;

3. 階段3:這是用戶基于BSP(板級支持包),也可以是操作系統的啟動引導程序,這個階段完全是在用戶的控制下實現的。

系統上電啟動后,第0階段啟動代碼判斷啟動模式,將第一階段啟動代碼FSBL下載到DDR中并且執行。FSBL會配置硬件比特流文件,加載CPU0可執行文件和CPU1可執行文件到DDR對應的鏈接地址,在這一階段,所有代碼在CPU0中執行,在執行CPU0程序的時候,把CPU1上將要執行的應用程序執行地址寫入到OCM的0xFFFFFFF0地址,然后執行 SEV匯編指令,激活CPU1,CPU1激活后,將會到OCM的0xFFFFFFF0地址讀取其數值,其數值就是CPU1執行可執行程序的地址,CPU1將從該地址執行。

雙核運行的配置

建立工程的區別

核0建立工程和以前一樣,但是核1建立工程與以前不同,需要單獨建立一個板級支持包bsp。建立CPU1的板級支持包步驟:

1. 在SDK主界面主菜單下,選擇File->New->Board Support Package;

2. 出現“New Board Support Package Project”對話框,如圖1所示;

圖1 新建cpu1板級支持包

點擊finish建立好支持包后,出現“Board Support Package Settings”對話框,在界面左側窗口中,展開Overview,在展開項中,找到并展開drivers,找到ps_cortexa9_1,并選擇它;

在右側的Configuration for OS界面中,找到名字為extra_compiler_flags一行,將其對應的Value一列的值改為-g –DUSE_AMP_ = 1,如圖2所示;

圖2 板級開發包的屬性設置

建立好板級開發包后,建立cpu1的sdk工程,該工程的配置與和0也有不同,就是在新建工程對話框的參數配置要與核0不同,其核心選擇核心1,板級支持包選擇剛剛建立的cpu1的板級支持包(proccessor:ps7_cortexa9_1;Borad Support Package:app_cpu1_bsp),建立好雙核的應用工程和板級開發包后,進行軟件的設計。

軟件設計

1. cpu0的軟件,在fsbl啟動cpu0程序后,其程序需要增加啟動cpu1的流程代碼;

2. cpu0和cpu1的軟件需要有一片共享內存,該內存不能被cache化;

3. 通過共享內存的分時訪問,設計兩個cpu的程序流程。

增加啟動cpu1的代碼如下:

#define sev() __asm__("sev")

#define CPU1STARTADDR 0xFFFFFFF0

#define CPU1STARTMEM 0x10000000

void StartCpu1(void)

{

Xil_Out32(CPU1STARTADDR,CPU1STARTMEM);

dmb();

sev();

}

禁用共享內存的代碼:

#define COMM_VAL (*(volatile unsigned long *)(0xffff0000))

Xil_SetTlbAttributes(0xffff0000,0x14de2);

雙核源碼與測試

利用共享內存做通訊的例子

Cpu0代碼:

#include "stdio.h"

#include "xil_io.h"

#include "xil_mmu.h"

#include "xil_exception.h"

#include "xpseudo_asm.h"

#include "sleep.h"

#define COMM_VAL (*(volatile unsigned long *)(0xffff0000))

#define sev() __asm__("sev")

#define CPU1STARTADDR 0xFFFFFFF0

#define CPU1STARTMEM 0x10000000

void StartCpu1(void)

{

Xil_Out32(CPU1STARTADDR,CPU1STARTMEM);

dmb();

sev();

}

int main(void)

{

Xil_SetTlbAttributes(0xffff0000,0x14de2);

StartCpu1();

COMM_VAL = 0;

while(1)

{

print("CPU0:hello world CPU0/r/n");

sleep(2);

COMM_VAL = 1;

while(COMM_VAL == 1);

}

return 0;

}

Cpu1代碼:

#include "stdio.h"

#include "xil_io.h"

#include "xil_mmu.h"

#include "xil_exception.h"

#include "xpseudo_asm.h"

#include "xparameters.h"

#include "sleep.h"

#define COMM_VAL (*(volatile unsigned long *)(0xffff0000))

int main(void)

{

Xil_SetTlbAttributes(0xffff0000,0x14de2);

while(1)

{

while(COMM_VAL == 0);

print("CPU1:hello world CPU1/r/n");

sleep(2);

COMM_VAL = 0;

}

return 0;

}

測試結果:

將上述程序生成boot.bin文件,然后下載到flash,啟動后通過串口助手可以收到cpu0與cpu1的打印信息,每間隔兩秒打印一次,如圖3所示。

圖3 程序測試

利用軟件中斷做通訊的例子

該例子中,cpu0和cpu1都注冊兩個軟件中斷,將1號軟件中斷注冊給cpu1,表示cpu0發送中斷給cpu1,將2號軟件中斷注冊給cpu0,表示cpu1發送中斷給cpu0;然后在程序運行時,cpu0觸發1號軟件中斷,此時cpu1正在運行主程序被該中斷中斷,進入中斷服務函數,其處理完中斷后觸發2號軟件中斷,此時該中斷會中斷cpu0,進入中斷服務函數,cpu0處理完中斷后回到主函數,再觸發1號軟件中斷,往復運行。

Cpu0代碼:

/*

* app_cpu0.c

*

* Created on: 2019年3月27日

* Author: dz

*/

#include "xil_cache.h"

#include "xparameters.h"

#include "xil_mmu.h"

#include "xil_misc_psreset_api.h"

#include "xil_exception.h"

#include "xscugic.h"

#include "xuartps.h"

#include "stdio.h"

#include "sleep.h"

volatile u8 software_intr_received = 0;

#define CORE0_TO_CORE1_INTR_ID 0x01

#define CORE1_TO_CORE0_INTR_ID 0x02

void sys_intr_init(void);

void Setup_Intr_Exception(XScuGic * IntcInstancePtr);

void Scu_Intr_Init(XScuGic* IntancePtr,int Scu_Int_ID);

void Init_Software_Intr(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHanedler, u16 SoftwareIntrId, u8 CpuId);

void Gen_Software_Intr(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId);

void Cpu0_Intr_Hanedler(void *Callback);

void Cpu1_Intr_Hanedler(void *Callback);

XScuGic ScuGic;

void delay(unsigned int count)

{

int i = 0;

for(i = 0;i

}

int main(void)

{

sys_intr_init();

xil_printf("cpu0 start!/r/n");

while(1)

{

if(XPAR_CPU_ID == 0)

Gen_Software_Intr(&ScuGic, CORE0_TO_CORE1_INTR_ID, XSCUGIC_SPI_CPU1_MASK);

/*Gen_Software_Intr(&ScuGic, CORE0_TO_CORE1_INTR_ID, XSCUGIC_SPI_CPU0_MASK);*/

else

Gen_Software_Intr(&ScuGic, CORE1_TO_CORE0_INTR_ID, XSCUGIC_SPI_CPU0_MASK);

delay(200000000);

if(1 == software_intr_received)

{

xil_printf("cpu0_main/r/n");

software_intr_received = 0;

}

}

return 0;

}

void sys_intr_init(void)

{ Scu_Intr_Init(&ScuGic,XPAR_SCUGIC_SINGLE_DEVICE_ID);

// if(XPAR_CPU_ID == 0)

Init_Software_Intr(&ScuGic, Cpu0_Intr_Hanedler, CORE0_TO_CORE1_INTR_ID, 0);

// else

Init_Software_Intr(&ScuGic, Cpu1_Intr_Hanedler, CORE1_TO_CORE0_INTR_ID, 1);

Setup_Intr_Exception(&ScuGic);

}

void Setup_Intr_Exception(XScuGic * IntcInstancePtr)

{

//connect hardware interrupt

Xil_ExceptionInit();

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,(void *)IntcInstancePtr);

//enable hardware interrupt

Xil_ExceptionEnable();

}

void Scu_Intr_Init(XScuGic* IntancePtr,int Scu_Int_ID)

{

XScuGic_Config *ScuConfigPtr;

//find device

ScuConfigPtr = XScuGic_LookupConfig(Scu_Int_ID);

//config scuint

XScuGic_CfgInitialize(IntancePtr, ScuConfigPtr,ScuConfigPtr->CpuBaseAddress);

}

void Cpu0_Intr_Hanedler(void *Callback)

{

xil_printf("receive interrupt from core1!/r/n");

software_intr_received = 1;

}

void Cpu1_Intr_Hanedler(void *Callback)

{

xil_printf("receive interrupt from core0!/r/n");

software_intr_received = 1;

}

void Init_Software_Intr(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHanedler, u16 SoftwareIntrId, u8 CpuId)

{

int Status;

// XScuGic_SetPriorityTriggerType(GicInstancePtr, SoftwareIntrId, 0xB0, 0x2);

XScuGic_SetPriorityTriggerType(GicInstancePtr, SoftwareIntrId, 0xd0, 0x3);

Status = XScuGic_Connect(GicInstancePtr, SoftwareIntrId,

(Xil_InterruptHandler)IntrHanedler, NULL);

if (Status != XST_SUCCESS) {

xil_printf("core%d: interrupt %d set fail!/r/n", XPAR_CPU_ID, SoftwareIntrId);

return;

}

XScuGic_InterruptMaptoCpu(GicInstancePtr, CpuId, SoftwareIntrId); //map the the Software interrupt to target CPU

XScuGic_Enable(GicInstancePtr, SoftwareIntrId);//enable the interrupt for the Software interrupt at GIC

}

void Gen_Software_Intr(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId)

{

int Status;

Status = XScuGic_SoftwareIntr(GicInstancePtr, SoftwareIntrId, CpuId);

if (Status != XST_SUCCESS) {

xil_printf("core%d: interrupt %d gen fail!/r/n", XPAR_CPU_ID, SoftwareIntrId);

return;

}

}

Cpu1代碼:

/*

* app_cpu0.c

*

* Created on: 2019年3月27日

* Author: dz

*/

#include "xil_cache.h"

#include "xparameters.h"

#include "xil_mmu.h"

#include "xil_misc_psreset_api.h"

#include "xil_exception.h"

#include "xscugic.h"

#include "xuartps.h"

#include "stdio.h"

#include "sleep.h"

volatile u8 software_intr_received = 0;

#define CORE0_TO_CORE1_INTR_ID 0x01

#define CORE1_TO_CORE0_INTR_ID 0x02

void sys_intr_init(void);

void Setup_Intr_Exception(XScuGic * IntcInstancePtr);

void Scu_Intr_Init(XScuGic* IntancePtr,int Scu_Int_ID);

void Init_Software_Intr(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHanedler, u16 SoftwareIntrId, u8 CpuId);

void Gen_Software_Intr(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId);

void Cpu0_Intr_Hanedler(void *Callback);

void Cpu1_Intr_Hanedler(void *Callback);

XScuGic ScuGic;

void delay(unsigned int count)

{

int i = 0;

for(i = 0;i

;

}

int main(void)

{

sys_intr_init();

// Gen_Software_Intr(&ScuGic, CORE1_TO_CORE0_INTR_ID, XSCUGIC_SPI_CPU1_MASK);

xil_printf("cpu1 start!/r/n");

while(1)

{

if(1 == software_intr_received)

{

software_intr_received = 0;

if(XPAR_CPU_ID == 0)

Gen_Software_Intr(&ScuGic, CORE0_TO_CORE1_INTR_ID, XSCUGIC_SPI_CPU1_MASK);

/* Gen_Software_Intr(&ScuGic, CORE0_TO_CORE1_INTR_ID, XSCUGIC_SPI_CPU0_MASK);*/

else

Gen_Software_Intr(&ScuGic, CORE1_TO_CORE0_INTR_ID, XSCUGIC_SPI_CPU0_MASK);

delay(200000000);

xil_printf("cpu1_main/r/n");

}

}

return 0;

}

void sys_intr_init(void)

{ Scu_Intr_Init(&ScuGic,XPAR_SCUGIC_SINGLE_DEVICE_ID);

// if(XPAR_CPU_ID == 0)

Init_Software_Intr(&ScuGic, Cpu0_Intr_Hanedler, CORE0_TO_CORE1_INTR_ID, 0);

// else

Init_Software_Intr(&ScuGic, Cpu1_Intr_Hanedler, CORE1_TO_CORE0_INTR_ID, 1);

Setup_Intr_Exception(&ScuGic);

}

void Setup_Intr_Exception(XScuGic * IntcInstancePtr)

{

//connect hardware interrupt

Xil_ExceptionInit();

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,(void *)IntcInstancePtr);

//enable hardware interrupt

Xil_ExceptionEnable();

}

void Scu_Intr_Init(XScuGic* IntancePtr,int Scu_Int_ID)

{

XScuGic_Config *ScuConfigPtr;

//find device

ScuConfigPtr = XScuGic_LookupConfig(Scu_Int_ID);

//config scuint

XScuGic_CfgInitialize(IntancePtr, ScuConfigPtr,ScuConfigPtr->CpuBaseAddress);

}

void Cpu0_Intr_Hanedler(void *Callback)

{

xil_printf("receive interrupt from core1!/r/n");

software_intr_received = 1;

}

void Cpu1_Intr_Hanedler(void *Callback)

{

xil_printf("receive interrupt from core0!/r/n");

software_intr_received = 1;

}

void Init_Software_Intr(XScuGic *GicInstancePtr, Xil_InterruptHandler IntrHanedler, u16 SoftwareIntrId, u8 CpuId)

{

int Status;

XScuGic_SetPriorityTriggerType(GicInstancePtr, SoftwareIntrId, 0xB0, 0x2);

// XScuGic_SetPriorityTriggerType(GicInstancePtr, SoftwareIntrId, 0xd0, 0x3);

Status = XScuGic_Connect(GicInstancePtr, SoftwareIntrId,

(Xil_InterruptHandler)IntrHanedler, NULL);

if (Status != XST_SUCCESS) {

xil_printf("core%d: interrupt %d set fail!/r/n", XPAR_CPU_ID, SoftwareIntrId);

return;

}

XScuGic_InterruptMaptoCpu(GicInstancePtr, CpuId, SoftwareIntrId); //map the the Software interrupt to target CPU

XScuGic_Enable(GicInstancePtr, SoftwareIntrId);//enable the interrupt for the Software interrupt at GIC

}

void Gen_Software_Intr(XScuGic *GicInstancePtr, u16 SoftwareIntrId, u32 CpuId)

{

int Status;

Status = XScuGic_SoftwareIntr(GicInstancePtr, SoftwareIntrId, CpuId);

if (Status != XST_SUCCESS) {

xil_printf("core%d: interrupt %d gen fail!/r/n", XPAR_CPU_ID, SoftwareIntrId);

return;

}

}

將上述程序生成boot.bin文件,然后下載到flash,啟動后通過串口助手可以收到cpu0與cpu1的打印信息,每間隔兩秒打印一次,如圖4所示。

圖4 測試結果
編輯:hfy


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Zynq
    +關注

    關注

    10

    文章

    610

    瀏覽量

    47296
收藏 人收藏

    評論

    相關推薦

    如何實現的AMP啟動

    之前章節中涉及到PS端的裸機程序都是在CPU0上運行的,弄的差點就忘了ZYNQ是擁有兩個A9硬核的強勁芯片,所以我們必須要學會怎么讓兩個CPU核心同時運行,不然就和之前開發單片機有什么
    的頭像 發表于 09-14 09:07 ?2663次閱讀

    [XILINX] 正點原子ZYNQ7035/7045/7100開發板發布、ZYNQ 7000系列、ARM、PCIe2.0、SFPX2!

    正點原子FPGA新品ZYNQ7035/7045/7100開發板,ZYNQ 7000系列、ARM、PCIe2.0、SFPX2! 正點原子Z
    發表于 09-02 17:18

    正點原子ZYNQ7015開發板!ZYNQ 7000系列、ARM、PCIe2.0、SFPX2,性能強悍,資料豐富!

    本帖最后由 jf_85110202 于 2024-9-14 10:33 編輯 正點原子ZYNQ7015開發板!ZYNQ 7000系列、
    發表于 09-14 10:12

    基于Zynq的嵌入式開發流程

    A53都有,對于ZYNQ7020來說,它集成了一塊ARM Cortex-A9處理器,性能足夠運行Linux下圖為Zynq-7000系列S
    發表于 08-23 08:15

    小白求助如何對ARM進行分運行

    ARM如何分運行,一個運行操作系統 一個跑裸機程序?有何思路?
    發表于 01-13 07:27

    imx6dl是單核運行還是運行

    1.飛凌imx6dl的板子,請問是運行在單核模式還是模式。uboot的maxcpus參數的值是1,應該是單核,但是內核里看到了cpu0cpu1,有點疑惑。2.如果是
    發表于 12-05 06:39

    Linux驅動開發筆記:對zynq PL部分IP的驅動開發過程

    在對zynq進行Linux驅動開發時,除了需要針對zynq內ARM自帶的控制器適配驅動外,還需要對zynq PL部分的IP進行驅動
    發表于 06-30 15:10 ?9719次閱讀

    Zynq UltraScale+ MPSoC在仿真板上的運行展示

    Xilinx展示Zynq UltraScale + MPSoC在由6個FPGA組成的硬件仿真板上運行,以實現四ARM Cortex-A53,
    的頭像 發表于 11-26 06:44 ?3493次閱讀

    在OMAPL138的ARM與DSP上實現TL IPC通信開發

    TL_IPC是廣州創龍獨立開發的一種通訊協議,這種開發方式適用于通信邏輯相對簡單的程序的
    發表于 08-06 08:34 ?1460次閱讀
    在OMAPL138的ARM<b class='flag-5'>核</b>與DSP<b class='flag-5'>核</b>上實現TL IPC<b class='flag-5'>雙</b><b class='flag-5'>核</b>通信<b class='flag-5'>開發</b>

    ZYNQ學習要點:通信

    今天,我們聊聊通信。通信的基礎是已經建立好了核工程,且配置完成。兩個CPU之間傳遞數據,采用了共享內存,共享內存設置在OCM(On
    的頭像 發表于 11-26 13:47 ?3875次閱讀
    <b class='flag-5'>ZYNQ</b>學習要點:<b class='flag-5'>雙</b><b class='flag-5'>核</b>通信

    典型的ZYNQ開發流程

    Zynq UltraScale+ MPSoC系列是Xilinx第二代Zynq平臺。其亮點在于FPGA里包含了完整的ARM處理子系統(PS),包含了四Cortex-A53處理器或
    的頭像 發表于 02-08 14:39 ?7479次閱讀
    典型的<b class='flag-5'>ZYNQ</b><b class='flag-5'>開發</b>流程

    ZYNQ OpenAMPARM通信案例開發手冊

    ZYNQ OpenAMPARM通信案例開發手冊
    發表于 07-06 10:27 ?32次下載

    關于zynq 運行的流水燈工程

    zynq 7000 一般有2個cpu (arm A9),我們一般都用一個cpu0,本實驗讓2個cpu 都運行起來,cpu0 運行操作系統petalinux 2018.2, cpu1: 裸機流水燈。同時通過共享內存的方式,實現2個
    發表于 09-13 09:22 ?1124次閱讀

    ZYNQARM分別運行不同的操作系統(基于OpenAMP)

    ZYNQ系列是Xilinx最近幾年推出的多核異構SoC,集成了FPGA和ARM處理器,ARM部分是ARM Cortex-A9處理器,核可以同時對稱使用,還可以非對稱使用。
    的頭像 發表于 12-05 13:46 ?4904次閱讀

    Xilinx ZYNQARM通信開發實例

    前言:本文主要介紹基于OpenAMP框架的ARM通信案例的使用說明,CPU0(Master)運行Linux系統,CPU1(Remote)運行裸機或FreeRTOS程序。CPU0
    的頭像 發表于 12-27 13:48 ?2116次閱讀
    Xilinx <b class='flag-5'>ZYNQ</b><b class='flag-5'>雙</b><b class='flag-5'>核</b>ARM通信<b class='flag-5'>開發</b>實例
    百家乐官网终端下载| 卡卡湾网上娱乐| 同乐城备用网址| 澳门百家乐官网博牌| 怎么赌百家乐官网能赢| 玩百家乐新2娱乐城| 大发888ber| 百家乐官网高人玩法| 金字塔百家乐官网的玩法技巧和规则 | 百家乐知识技巧玩法| 钱柜娱乐城怎么样| 澳门百家乐官网娱乐网| 网上百家乐正规代理| 516棋牌游戏加速器| 太阳城百家乐官网网址-- | 立即博百家乐的玩法技巧和规则| 宜川县| 百家乐官网娱乐城博彩通博彩网| 威尼斯人娱乐城线上赌场| 百家乐官网算牌e世博| 百家乐庄河闲的赌法| 六合彩特码开奖结果| 百家乐官网网上真钱娱乐场开户注册| 网上百家乐有哪些玩法| 大庆市| 百家乐视频双扣游戏| 线上龙虎| 百家乐官网俄罗斯轮盘转盘套装| 全讯网址| 娱乐城百家乐官网可以代理吗 | 百家乐官网赌大小| 百家乐合| 百家乐官网最新投注方法| 百家乐游戏图片| 大发888创建账号翻译| 大发888怎么开户| 宁南县| 娱网百家乐官网补丁| 真人百家乐官网赌场娱乐网规则| 缅甸百家乐官网赌博现场下载| 明陞百家乐官网娱乐城|