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