54_ZYNQ7020开发板SDK_逻辑双核AMP的使用

前面的例程都是采用单核CPU,有些情况比如多任务处理,并行处理,需要用到双核CPU,本章将开始介绍双核CPU

1.CPU0实现PS端按键中断,控制PS端的LED的亮灭,并向CPU1发出软件中断,让CPU1打印CPU0内存空间的一串字符。
2.CPU1实现PL端按键中断,控制PL端的LED的亮灭,并向CPU0发出软件中断,让CPU0打印CPU1内存空间的一串字符。
3.内存空间的划分,共享内存空间的使用
4.FSBL启动Flash
一、硬件环境搭建
本实验以“ps_hello”例程为基础,添加PL端GPIO,添加axi_gpio_0设置为输出,位宽为1位,连接PL端LED。
在这里插入图片描述
在这里插入图片描述
添加axi_gpio_0设置为输出,位宽为1位,连接PL端LED
在这里插入图片描述
添加axi_gpio_1,连接pl端按键,设置为输入,位宽为1位,并使能中断
在这里插入图片描述
自动连接布线
在这里插入图片描述
全选
在这里插入图片描述
将axi_gpio_1的中断输出连接到CPU的IRQ_F2P端口
在这里插入图片描述
修改axi_gpio_1输出为key,修改axi_gpio_0的输出为led
在这里插入图片描述
点击,整理布线
在这里插入图片描述
Generate Outputs
在这里插入图片描述
绑定按键和LED灯的引脚,生成bitstream

在这里插入图片描述
led.xdc

set_property IOSTANDARD LVCMOS33 [get_ports {led_tri_o[0]}]
set_property PACKAGE_PIN M14 [get_ports {led_tri_o[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports {key_tri_i[0]}]
set_property PACKAGE_PIN N15 [get_ports {key_tri_i[0]}]

二、新建工程,在Processor选择ps7_cortexa9_0,也就是CPU0,选择Empty,工程名字为cpu0_app

在这里插入图片描述
选择Empty,点击Finish
在这里插入图片描述
三、分别在cpu0_app与cpu1_app中分别添加cpu0_app.c与share.h,cpu1_app.c与share.c
cpu0_app.c

/*
 * cpu0_app.c
 *
 *  Created on: 2018Äê9ÔÂ17ÈÕ
 *      Author: myj
 */

#include "xparameters.h"
#include "xscugic.h"
#include "xgpiops.h"
#include "xil_printf.h"
#include "xil_exception.h"
#include "xil_mmu.h"
#include "xpseudo_asm.h"
#include "stdio.h"
#include "share.h"
#include "xil_cache.h"
#include "xtime_l.h"

/* GPIO paramter */
#define MIO_0_ID        XPAR_PS7_GPIO_0_DEVICE_ID
#define INTC_DEVICE_ID	XPAR_SCUGIC_SINGLE_DEVICE_ID
#define KEY_INTR_ID     XPAR_XGPIOPS_0_INTR

#define GPIO_INPUT      0
#define GPIO_OUTPUT     1

int key_flag = 0 ;
int soft_flag = 0 ;
XGpioPs GPIO_PTR ;

XScuGic InterrruptInst;


u16 SoftIntrIdToCpu0 = 1 ;
u16 SoftIntrIdToCpu1 = 2 ;

ShareMem *SharePtr ;

u32 CPU1 = 0x2 ;

unsigned char Cpu0_Data[12] = "Hello Cpu1!" ;
unsigned char *Cpu1Data ;

XTime TimerCurr, TimerLast;

#define SHARE_BASE  0x3FFFFF00

int InterruptInit(XScuGic *InstancePtr, u16 DeviceId) ;
int InterruptConnnect(XScuGic *InstancePtr, u16 IntId, void * Handler,void *CallBackRef) ;

int PsGpioSetup(XScuGic *InstancePtr) ;
int GpioHandler(void *CallbackRef);

void SoftHandler(void *CallbackRef) ;

#define sev() __asm__("sev")
#define CPU1STARTADR 0xFFFFFFF0
#define CPU1STARTMEM 0x20000000

void StartCpu1(void)
{
	printf("Write the address of the application for CPU1 to 0xFFFFFFF0\r\n");
	Xil_Out32(CPU1STARTADR, CPU1STARTMEM);
	dmb();
	printf("Execute the SEV instruction to cause CPU1 to wake up and jump to the application\r\n");
	sev();
}


int main()
{
	int Status ;
	int LedVal  = 0 ;
	/*
	 * Disable cache on OCM  S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0
	 */
	Xil_SetTlbAttributes(0xFFFF0000,0x14de2);
	/*
	 * Wake up CPU1
	 */
	StartCpu1();

	SharePtr = (ShareMem *)SHARE_BASE ;
	/*
	 * Initial interrupt
	 */
	Status = InterruptInit(&InterrruptInst, INTC_DEVICE_ID) ;
	if (Status != XST_SUCCESS)
		return XST_FAILURE ;
	/*
	 * Setup Ps Gpio and Enable Gpio interrupt
	 */
	PsGpioSetup(&InterrruptInst) ;
	/*
	 * Connect interrupt
	 */
	InterruptConnnect(&InterrruptInst, SoftIntrIdToCpu0, (void *)SoftHandler, (void *)&InterrruptInst) ;


	while(1)
	{
		if (key_flag)
		{
			/*
			 * initial shared Struct
			 */
			SharePtr->addr = (unsigned int *)&Cpu0_Data ;
			SharePtr->length = sizeof(Cpu0_Data) ;
			/*
			 * Write led value
			 */
			XGpioPs_WritePin(&GPIO_PTR, 0, LedVal) ;
			LedVal = ~LedVal ;
			/*
			 * Software interrupt to CPU1
			 */
			XScuGic_SoftwareIntr(&InterrruptInst, SoftIntrIdToCpu1, CPU1) ;
			key_flag = 0 ;
		}
		else if (soft_flag)
		{
			/*
			 * When Software interrupt, print data in CPU1
			 */
			Cpu1Data = (unsigned char *)SharePtr->addr ;
			xil_printf("This is CPU0, Now Start to Print:\r\n") ;
			xil_printf("%s\r\n", Cpu1Data) ;
			soft_flag = 0 ;
		}

	}

	return 0 ;
}


int PsGpioSetup(XScuGic *InstancePtr)
{
	XGpioPs_Config *GPIO_CONFIG ;
	int Status ;

	GPIO_CONFIG = XGpioPs_LookupConfig(MIO_0_ID) ;

	Status = XGpioPs_CfgInitialize(&GPIO_PTR, GPIO_CONFIG, GPIO_CONFIG->BaseAddr) ;
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE ;
	}
	/* set MIO 50 as input */
	XGpioPs_SetDirectionPin(&GPIO_PTR, 50, GPIO_INPUT) ;
	/* set MIO 0 as output */
	XGpioPs_SetDirectionPin(&GPIO_PTR, 0, GPIO_OUTPUT) ;
	/* enable MIO 0 output */
	XGpioPs_SetOutputEnablePin(&GPIO_PTR, 0, GPIO_OUTPUT) ;
	/* set interrupt type */
	XGpioPs_SetIntrTypePin(&GPIO_PTR, 50, XGPIOPS_IRQ_TYPE_EDGE_RISING) ;

	/* enable GPIO interrupt */
	XGpioPs_IntrEnablePin(&GPIO_PTR, 50) ;

	InterruptConnnect(InstancePtr, KEY_INTR_ID, (void *)GpioHandler, (void *)&GPIO_PTR) ;

	return XST_SUCCESS ;
}


int InterruptInit(XScuGic *InstancePtr, u16 DeviceId)
{
	XScuGic_Config *IntcConfig;
	int Status ;

	IntcConfig = XScuGic_LookupConfig(DeviceId);

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

	/*
	 * Initialize the  exception table
	 */
	Xil_ExceptionInit();

	/*
	 * Register the interrupt controller handler with the exception table
	 */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler)XScuGic_InterruptHandler,
			InstancePtr);

	/*
	 * Enable non-critical exceptions
	 */
	Xil_ExceptionEnable();


	return XST_SUCCESS ;

}

int InterruptConnnect(XScuGic *InstancePtr, u16 IntId, void * Handler,void *CallBackRef)
{
	XScuGic_Connect(InstancePtr, IntId,
			(Xil_InterruptHandler)Handler,
			CallBackRef) ;

	XScuGic_Enable(InstancePtr, IntId) ;
	return XST_SUCCESS ;
}



int GpioHandler(void *CallbackRef)
{
	XGpioPs *GpioInstancePtr = (XGpioPs *)CallbackRef ;
	int Int_val ;
	float Interval_time ;

	Int_val = XGpioPs_IntrGetStatusPin(GpioInstancePtr, 50) ;
	/* clear key interrupt */
	XGpioPs_IntrClearPin(GpioInstancePtr, 50) ;
	if (Int_val)
	{
		TimerLast = TimerCurr ;
		XTime_GetTime(&TimerCurr) ;
		Interval_time = ((float)(TimerCurr-TimerLast))/((float)COUNTS_PER_SECOND) ;
		/* Key debounce, set decounce time to 50ms*/
		if (Interval_time < 0.05)
		{
			key_flag = 0 ;
			return 0 ;
		}
		else
		{
			key_flag = 1 ;
		}
	}


	return 1 ;
}

void SoftHandler(void *CallbackRef)
{
	xil_printf("Soft Interrupt from CPU1\r\n") ;
	soft_flag = 1 ;
}


share.h


typedef struct
{
	unsigned int length;
	unsigned int *addr;
}ShareMem;

cpu1_app.c

/*
 * cpu1_app.c
 *
 *  Created on: 2018Äê9ÔÂ17ÈÕ
 *      Author: myj
 */

#include "xparameters.h"
#include "xscugic.h"
#include "xgpio.h"

#include "xil_printf.h"
#include "xil_exception.h"
#include "xil_mmu.h"
#include "sleep.h"
#include "share.h"
#include "xtime_l.h"


#define KEY_DEVICE_ID XPAR_AXI_GPIO_1_DEVICE_ID
#define LED_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID

#define KEY_INTR_ID XPAR_FABRIC_AXI_GPIO_1_IP2INTC_IRPT_INTR
#define INTC_DEVICE_ID	XPAR_SCUGIC_SINGLE_DEVICE_ID

#define LED_DIR 0x0f
#define LED_CHANNEL 1
#define KEY_DIR 0x0f
#define KEY_CHANNEL 1

#define BTN_INT             XGPIO_IR_CH1_MASK


ShareMem *SharePtr ;

unsigned char Cpu0_Data[12] = "Hello Cpu0!" ;

#define SHARE_BASE  0x3FFFFF00

XGpio Gpio_key ;
XGpio Gpio_led ;

XScuGic InterrruptInst;

int key_flag = 0 ;
int soft_flag = 0 ;

u32 CPU0 = 0x1 ;

u16 SoftIntrIdToCpu0 = 1 ;
u16 SoftIntrIdToCpu1 = 2 ;

unsigned char Cpu1_Data[12] = "Hello Cpu0!" ;
unsigned char *Cpu0Data ;

XTime TimerCurr, TimerLast;


int InterruptInit(XScuGic *InstancePtr, u16 DeviceId);
int InterruptConnnect(XScuGic *InstancePtr, u16 IntId, void * Handler,void *CallBackRef) ;

int PLGpioSetup(XScuGic *InstancePtr) ;
int GpioHandler(void *InstancePtr);

void SoftHandler(void *CallbackRef) ;



int main()
{
	int Status ;
	int LedVal = 0x1;

	/*
	 * Disable cache on OCM  S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0
	 */
	Xil_SetTlbAttributes(0xFFFF0000,0x14de2);

	SharePtr = (ShareMem *)SHARE_BASE ;
	/*
	 * Initial interrupt
	 */
	Status = InterruptInit(&InterrruptInst, INTC_DEVICE_ID) ;
	if (Status != XST_SUCCESS)
		return XST_FAILURE ;
	/*
	 * Setup Gpio and Enable Gpio interrupt
	 */
	PLGpioSetup(&InterrruptInst);
	/*
	 * Connect interrupt
	 */
	InterruptConnnect(&InterrruptInst, SoftIntrIdToCpu1, (void *)SoftHandler, (void *)&InterrruptInst) ;


	while(1)
	{
		if (key_flag)
		{
			/*
			 * initial shared Struct
			 */
			SharePtr->addr = (unsigned int *)&Cpu1_Data ;
			SharePtr->length = sizeof(Cpu1_Data) ;
			/*
			 * Write led value
			 */
			XGpio_DiscreteWrite(&Gpio_led, LED_CHANNEL, LedVal);
			LedVal = ~LedVal ;
			/*
			 * Software interrupt to CPU0
			 */
			XScuGic_SoftwareIntr(&InterrruptInst, SoftIntrIdToCpu0, CPU0) ;
			key_flag = 0 ;
		}
		else if (soft_flag)
		{
			/*
			 * When Software interrupt, print data in CPU0
			 */
			Cpu0Data = (unsigned char *)SharePtr->addr ;
			xil_printf("This is CPU1, Now Start to Print:\r\n") ;
			xil_printf("%s\r\n", Cpu0Data) ;
			soft_flag = 0 ;
		}

	}


	return 0 ;
}

int PLGpioSetup(XScuGic *InstancePtr)
{
	int Status ;

	/* initial gpio key */
	Status = XGpio_Initialize(&Gpio_key, KEY_DEVICE_ID) ;
	if (Status != XST_SUCCESS)
		return XST_FAILURE ;

	/* initial gpio led */
	Status = XGpio_Initialize(&Gpio_led, LED_DEVICE_ID) ;
	if (Status != XST_SUCCESS)
		return XST_FAILURE ;

	/* set key as input */
	XGpio_SetDataDirection(&Gpio_key, KEY_CHANNEL, 0x1);
	/* set led as output */
	XGpio_SetDataDirection(&Gpio_led, LED_CHANNEL, 0x0);

	/* Enable key interrupt */
	XGpio_InterruptGlobalEnable(&Gpio_key) ;
	XGpio_InterruptEnable(&Gpio_key, BTN_INT) ;
	/* Connect key interrupt to CPU1 */
	XScuGic_InterruptMaptoCpu(InstancePtr, XPAR_CPU_ID, KEY_INTR_ID) ;

	InterruptConnnect(InstancePtr, KEY_INTR_ID, (void *)GpioHandler, (void *)&Gpio_key) ;

	return XST_SUCCESS ;
}


int InterruptInit(XScuGic *InstancePtr, u16 DeviceId)
{
	XScuGic_Config *IntcConfig;
	int Status ;

	IntcConfig = XScuGic_LookupConfig(DeviceId);

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

	/*
	 * Initialize the  exception table
	 */
	Xil_ExceptionInit();

	/*
	 * Register the interrupt controller handler with the exception table
	 */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler)XScuGic_InterruptHandler,
			InstancePtr);

	/*
	 * Enable non-critical exceptions
	 */
	Xil_ExceptionEnable();


	return XST_SUCCESS ;

}


int InterruptConnnect(XScuGic *InstancePtr, u16 IntId, void * Handler,void *CallBackRef)
{
	XScuGic_Connect(InstancePtr, IntId,
			(Xil_InterruptHandler)Handler,
			CallBackRef) ;

	XScuGic_Enable(InstancePtr, IntId) ;
	return XST_SUCCESS ;
}

int GpioHandler(void *CallbackRef)
{
	XGpio *GpioInstancePtr = (XGpio *)CallbackRef ;
	int Int_val ;
	int key_val ;
	float Interval_time ;

	Int_val = XGpio_InterruptGetStatus(GpioInstancePtr);
	key_val = XGpio_DiscreteRead(GpioInstancePtr, KEY_CHANNEL) ;
	/* Clear Interrupt */
	XGpio_InterruptClear(GpioInstancePtr, XGPIO_IR_CH1_MASK) ;

	if (Int_val == 1 && key_val == 0)
	{
		TimerLast = TimerCurr ;
		XTime_GetTime(&TimerCurr) ;
		Interval_time = ((float)(TimerCurr-TimerLast))/((float)COUNTS_PER_SECOND) ;
		/* Key debounce, set decounce time to 200ms*/
		if (Interval_time < 0.2)
		{
			key_flag = 0 ;
			return 0 ;
		}
		else
		{
			key_flag = 1 ;
		}
	}

	return 1 ;
}


void SoftHandler(void *CallbackRef)
{
	xil_printf("Soft Interrupt from CPU0\r\n") ;
	soft_flag = 1 ;
}


share.h



typedef struct
{
	unsigned int length;
	unsigned int *addr;
}ShareMem;

在cpu0_app工程中的lscript.ld设置CPU0的访问空间,例如DDR3为1GByte,将CPU0空间设置为一半,当然也可以根据需要修改
在这里插入图片描述
修改CPU1内存空间,注意不要与CPU0重合,最后保留256字节空间,用于共享内存
在这里插入图片描述
四、CPU0程序介绍
1.在cpu0_app.c文件中,设置一个字符数组Cpu0_Data,存放在CPU0访问空间,指针Cpu1Data用于指向CPU1内的字符数组。

在这里插入图片描述
2.在程序中,需要CPU0唤醒CPU1,可以在UG585文档看到相关解释,第一步是向0xffffffff0地址写入CPU1的访问内存基地址,在本实验中也就是0x20000000,第二步通过SEV指令唤醒CPU1并且跳转到相应的程序。
CPU1STARTMEM即在lscript.ld里设置的CPU1 base address
在这里插入图片描述
在这里插入图片描述
在while循环语句中,将字符数组的地址与长度赋给共享结构体,这里要提一下共享内存结构体,在share.h中定义结构体ShareMem,用于共享内存中传递信息。
在这里插入图片描述
在这里插入图片描述
共享的地址
在这里插入图片描述
在while循环中判断来自CPU1的软件中断,打印出来CPU1内存空间中的字符串
在这里插入图片描述

五、CPU1程序介绍
1.在CPU1程序中同样有一个字符数组,Cpu0Data指向CPU0内存空间的字符串地址。
在这里插入图片描述
2.在main函数中首先也是关闭OCM的Cache

在这里插入图片描述
3.在PLGpioSetup函数中需要将按键中断号绑定到CPU1,其他部分都与CPU0类似
在这里插入图片描述
六、板上验证
1.Run Configurations配置如下
在这里插入图片描述
2.在Application窗口将两个核都勾选上,下载程序
在这里插入图片描述

3.打开串口助手,测试CPU0,按下按键,控制LED灯亮,表明CPU0在运行,同时CPU1接收到CPU0设置的软件中断,并打印信息。
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值