Zynq ZC702平台 Linux + Baremetal AMP實現(二)【CPU1處理外設中斷】


預備知識:UG585 Interrupts

7.1.2 Generic Interrupt Controller (GIC)
The generic interrupt controller (GIC) is a centralized resource for managing interrupts sent to the 
CPUs from the PS and PL. The controller enables, disables, masks, and prioritizes the interrupt sources and sends them to the selected CPU (or CPUs) in a programmed manner as the CPU interface accepts the next interrupt. In addition, the controller supports security extension for implementing a 
security-aware system.

方法:通過  XScuGic_InterruptMaptoCpu ( XScuGic * InstancePtr, u8 Cpu_Id, u32 Int_Id )   配置中斷到對應的CPU,函數的說明如下:

XScuGic_InterruptMaptoCpu()

void XScuGic_InterruptMaptoCpu  ( XScuGic *  InstancePtr,  
  u8  Cpu_Id,  
  u32  Int_Id  
 )   

#include <xscugic.c>

Sets the target CPU for the interrupt of a peripheral. 
Parameters
  InstancePtr is a pointer to the instance to be worked on.  
  Cpu_Id is a CPU number for which the interrupt has to be targeted  
  Int_Id is the IRQ source number to modify 
Returns
  None.
Note
  None

Tips:Q. 如何/在哪快速查閱相關函數?

 A>通過system.mss 下對應外設的 Documentation 鏈接,查找所提供的API函數(API會隨着版本的升級而有變化)

 

背景:應用存在需要CPU1快速的響應某些外設的中斷,並要及時的操作其余外設,所以需要CPU1跑Baremetal。

比如如下應用:CAN  <---> CPU1 <---> GPIO, CPU1需要快速響應CAN總線發送的命令,及時解析是否需要操作GPIO控制外設來響應緊急需求,或者反向通信需求。

詳細步驟:

Step1:按照Zynq ZC702平台 Linux + Baremetal AMP實現(一),建立工程CPU1的app,比如import  Examples : xgpiops_intr_example,設置好lscript.ld

 

Step2: 設置GPIO中斷到CPU1

--<xgpiops_intr_example.c>, 中 static int SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio, u16 GpioIntrId)定義中添加 XScuGic_InterruptMaptoCpu(GicInstancePtr, 1, GpioIntrId); 設置GPIO的中斷至CPU1

static int SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,
                u16 GpioIntrId)
{
    int Status;
    u32 CPUID;
    CPUID = XScuGic_GetCpuID();
    xil_printf("\n\Current CPUID is %d\n", CPUID);

    XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */

    Xil_ExceptionInit();

    /*
     * Initialize the interrupt controller driver so that it is ready to
     * use.
     */
    IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
    if (NULL == IntcConfig) {
        return XST_FAILURE;
    }

    Status = XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,
                    IntcConfig->CpuBaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }


    /*
     * Connect the interrupt controller interrupt handler to the hardware
     * interrupt handling logic in the processor.
     */
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
                (Xil_ExceptionHandler)XScuGic_InterruptHandler,
                GicInstancePtr);

    /*
     * Connect the device driver handler that will be called when an
     * interrupt for the device occurs, the handler defined above performs
     * the specific interrupt processing for the device.
     */
    Status = XScuGic_Connect(GicInstancePtr, GpioIntrId,
                (Xil_ExceptionHandler)XGpioPs_IntrHandler,
                (void *)Gpio);
    if (Status != XST_SUCCESS) {
        return Status;
    }

    /* Enable falling edge interrupts for all the pins in bank 0. */
    XGpioPs_SetIntrType(Gpio, INPUT_BANK, 0x00, 0x00, 0x00);

    /* Set the handler for gpio interrupts. */
    XGpioPs_SetCallbackHandler(Gpio, (void *)Gpio, IntrHandler);


    /* Enable the GPIO interrupts of Bank 0. */
    XGpioPs_IntrEnable(Gpio, INPUT_BANK, (1 << Output_Pin));

    /* Sets the target CPU for the interrupt of a peripheral */ ///設置GPIO的中斷至CPU1 XScuGic_InterruptMaptoCpu(GicInstancePtr, 1, GpioIntrId); /* Enable the interrupt for the GPIO device. */
    XScuGic_Enable(GicInstancePtr, GpioIntrId);

    /* Enable interrupts in the Processor. */
    Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);


    return XST_SUCCESS;
}

Example程序中斷默認送給CPU0,

 

相同的方法可以添加can中斷example,並指定由CPU1來進行處理,大家需要根據外設example具體的情況讀code,可能需要在多處添加

--示例沒有去處理GPIO/CAN的相關性

static int SetupInterruptSystem(INTC *IntcInstancePtr,
                XCanPs *CanInstancePtr,
                u16 CanIntrId)
{
    int Status;
#ifdef XPAR_INTC_0_DEVICE_ID
#ifndef TESTAPP_GEN
    /* Initialize the interrupt controller and connect the ISRs */
    Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);
    if (Status != XST_SUCCESS)
    {

        xil_printf("Failed init intc\r\n");
        return XST_FAILURE;
    }
#endif
    /*
     * Connect the driver interrupt handler
     */
    Status = XIntc_Connect(IntcInstancePtr, CanIntrId,
                            (XInterruptHandler)XCanPs_IntrHandler, CanInstancePtr);
    if (Status != XST_SUCCESS)
    {

        xil_printf("Failed connect intc\r\n");
        return XST_FAILURE;
    }

 XScuGic_InterruptMaptoCpu(IntcInstancePtr, 1, CanIntrId);

#ifndef TESTAPP_GEN
    /*
     * Start the interrupt controller such that interrupts are enabled for
     * all devices that cause interrupts.
     */
    Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
    if (Status != XST_SUCCESS)
    {
        return XST_FAILURE;
    }
#endif XScuGic_InterruptMaptoCpu(IntcInstancePtr, 1, CanIntrId); /*
     * Enable the interrupt for the CAN device.
     */
    XIntc_Enable(IntcInstancePtr, CanIntrId);
#ifndef TESTAPP_GEN
    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
                (Xil_ExceptionHandler)XIntc_InterruptHandler,
                (void *)IntcInstancePtr);
#endif
#else
#ifndef TESTAPP_GEN
    XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */

    Xil_ExceptionInit();

    /*
     * Initialize the interrupt controller driver so that it is ready to
     * use.
     */
    IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
    if (NULL == IntcConfig) {
        return XST_FAILURE;
    }

    Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
                    IntcConfig->CpuBaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }


    /*
     * Connect the interrupt controller interrupt handler to the hardware
     * interrupt handling logic in the processor.
     */
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
                (Xil_ExceptionHandler)XScuGic_InterruptHandler,
                IntcInstancePtr);
#endif

    /*
     * Connect the device driver handler that will be called when an
     * interrupt for the device occurs, the handler defined above performs
     * the specific interrupt processing for the device.
     */
    Status = XScuGic_Connect(IntcInstancePtr, CanIntrId,
                (Xil_InterruptHandler)XCanPs_IntrHandler,
                (void *)CanInstancePtr);
    if (Status != XST_SUCCESS) {
        return Status;
    }

    XScuGic_InterruptMaptoCpu(IntcInstancePtr, 1, CanIntrId); /*
     * Enable the interrupt for the CAN device.
     */
    XScuGic_Enable(IntcInstancePtr, CanIntrId);
#endif
#ifndef TESTAPP_GEN
    /*
     * Enable interrupts in the Processor.
     */
    Xil_ExceptionEnable();
#endif
    return XST_SUCCESS;
}

 

Tips: 

Cpu1里面不能操作L2cache,需要在cpu1 BSP里的\intr_second_bsp\ps7_cortexa9_1\libsrc\standalone_v6_3\src\translation_table.S里面設置MMU arrtibute,使得DDR memory區域L2cache無效。 

.rept         DDR_REG                          /*  (DDR Cacheable) */

.word       SECT + 0x14de6               /* S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b1 */

.set  SECT, SECT+0x100000

.endr

 

Step5: CPU0的devicetree中注釋/刪除掉分給CPU1的外設 ,拷貝相應的文件到SD啟動

End

 


免責聲明!

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



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