zynq petalinux AMP双核运行linux+ucos(或者裸机)之间进行 IPI 软中断通讯的实现

前几天试验了xilinx官方remotporc AMP程序,运行是运行起来了,但是感觉太复杂了,我只想要一个能启动停止cpu1,能在两个cpu之间方便通讯的功能就行了,看着remotproc框架一堆的代码,编译出来的elf文件体积还超级大心里就非常不爽,想着干脆自己实现一个简单处理驱动程序算了,so...经过几天的痛苦研究,也算完整实现了想要的功能

由于linux应用程序不能处理硬件中断,因此这个IPI通讯只能在驱动层进行处理,所以第一步,要编写一个驱动程序,实现cpu1的bin(不是elf)文件加载,控制启动和停止cpu1,处理cpu0和cpu1之间的ipi中断,完整驱动代码如下

/*  ampipidevice.c - The simplest kernel module.

* Copyright (C) 2013 - 2016 Xilinx, Inc
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation; either version 2 of the License, or
*   (at your option) any later version.

*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License along
*   with this program. If not, see <http://www.gnu.org/licenses/>.

*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h> 
#include <linux/cdev.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/fs.h>
#include <linux/fcntl.h> 

#include <../../arch/arm/mach-zynq/common.h>
#include <linux/irqchip/arm-gic.h> 

extern int zynq_cpun_stop(int cpu);



/* Standard module information, edit as appropriate */
MODULE_LICENSE("GPL");
MODULE_AUTHOR
    ("Xilinx Inc.");
MODULE_DESCRIPTION
    ("ampipidevice - loadable module template generated by petalinux-create -t modules");

#define DRIVER_NAME "ampipi_Device"
#define DRIVER_NUM   1                      



#define StarCpu1			0x10000000
#define StopCpu1			0x20000000
#define KickCpu1			0x30000000

struct ampipidevice_local 
{
	int cpu0_to_cpu1_ipi;
	int cpu1_to_cpu0_ipi;
	unsigned long mem_start;
	unsigned long mem_end;
	void __iomem *base_addr;
};


struct ampipi_dev 
{ 
	dev_t devid;                   /*  设备号  */ 
	struct cdev chdev;            	/* cdev 结构体  */ 
	struct class *class;         	/*  类  */ 
	struct device *device;     		/*  设备  */ 
	struct ampipidevice_local *param;
	struct fasync_struct *async_queue; 
}; 

static struct ampipi_dev ampipi;  


/*********************************************************************
*
*
*
**********************************************************************/
static int ampipi_open(struct inode *inode, struct file *filp) 
{ 

	cpu_up(1);
	printk("ampipi Dev: open success  \r\n"); 
					
	return 0; 
} 

/*********************************************************************
*
*
*
**********************************************************************/
static ssize_t ampipi_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt) 
{
	int ret; 
	
	ret = copy_from_user((unsigned char*)(ampipi.param->base_addr + (*offt)), buf, cnt);  
	
	if(0 > ret)
	{
		printk(KERN_ERR "ampipi Dev: Failed to copy data from user space \r\n"); 
		return -EFAULT; 			
	}
	
	printk("ampipi Dev: write add: %08X  cnt: %d\r\n",(unsigned int)(ampipi.param->base_addr + (*offt)),cnt); 
	
	*offt = *offt + cnt;
	
	return cnt;
}

/*********************************************************************
*
*
*
**********************************************************************/
static ssize_t ampipi_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) 
{ 
	int ret = 0; 
	
	ret = copy_to_user(buf, (unsigned char*)(ampipi.param->base_addr + (*offt)) , cnt); 
	
	if(ret < 0)
	{ 
		printk(KERN_ERR "ampipi Dev: Failed to copy data to user space \r\n"); 
	} 
	
	*offt = *offt + cnt;
	
	return cnt;  

} 
/*********************************************************************
*
*
*
**********************************************************************/
static long ampipi_ioctl(struct file *filp,unsigned int cmd, unsigned long arg) 
{
	  int ret = 0; 
		printk("cmd %d \n" ,cmd);
		

		switch(cmd)
		{
			case StarCpu1:
				

					ret = cpu_down(1);
				
					if (ret && (ret != -EBUSY)) 
					{
						printk("Can't release cpu1 %d\n",ret);
						return ret;
					}
					
					zynq_cpun_stop(1);
					zynq_cpun_start((u32)ampipi.param->mem_start, 1);
					
					printk("StarCpu1\n");

				break;
				
			case StopCpu1:
				

				ret = cpu_up(1);
				if (ret)
				{
					printk("Can't power on cpu1 %d\n", ret);
				}
				
				printk("StopCpu1\n");
				break;
				
				case KickCpu1:
					
					gic_raise_softirq(cpumask_of(1), ampipi.param->cpu0_to_cpu1_ipi);
					
					printk("KickCpu %d  %d \n",1,ampipi.param->cpu0_to_cpu1_ipi);
					
					break;		
		}
		
		return 0;
}
/*********************************************************************
*
*
*
**********************************************************************/
loff_t ampipi_llseek(struct file *filp, loff_t off, int whence)
{
        loff_t newpos;

        switch(whence)
        {
        case 0: /* SEEK_SET */
        	
                newpos = off;
                
                break;

        case 1: /* SEEK_CUR */
        	
                newpos = filp->f_pos + off;
                
                break;

        case 2: /* SEEK_END */
        	
        				if(whence>0)
 									newpos = (ampipi.param->mem_end - ampipi.param->mem_start);
 								else
 									newpos = (ampipi.param->mem_end - ampipi.param->mem_start)+ whence;
 									
                break;

        default: /* can't happen */
                return -EINVAL;
        }
        
        if (newpos < 0)
                return -EINVAL;
                
        filp->f_pos = newpos;
        
        return newpos;
}


/*********************************************************************
*
*
*
**********************************************************************/
static int ampipi_fasync(int fd, struct file *filp, int on) 
{
	return fasync_helper(fd, filp, on, &ampipi.async_queue); 
}
/*********************************************************************
*
*
*
**********************************************************************/
static int ampipi_fasync_release(struct inode *inode, struct file *filp) 
{
	return ampipi_fasync(-1, filp, 0); 
}

/*********************************************************************
*
*
*
**********************************************************************/
static struct file_operations ampipi_fops = 
{ 
	.owner = THIS_MODULE, 
	.open = ampipi_open, 
	.write = ampipi_write, 
	.read = ampipi_read, 
	.unlocked_ioctl = ampipi_ioctl, 
	.llseek = ampipi_llseek, 
	.fasync = ampipi_fasync, 
	.release = ampipi_fasync_release, 
 }; 

/*********************************************************************
*
*
*
**********************************************************************/
static int ampipi_init(struct ampipidevice_local *nd) 
{ 
		ampipi.param = nd;
		
		cpu_down(1);
		
		return 0;
}



/*********************************************************************
*
*IPI 中断通知Linux CPU0 有信息要处理
*
**********************************************************************/
static void cpu1_to_cpu0_ipi_kick(void)
{
		
	if(ampipi.async_queue) 
		{
			
			printk("ipi %d  kick SIGIO \n",ampipi.param->cpu1_to_cpu0_ipi);
			kill_fasync(&ampipi.async_queue, SIGIO, POLL_IN); 
		}
		else
		{
			printk("ipi %d kick but async_queue is null \n",ampipi.param->cpu1_to_cpu0_ipi);
		}

}

/*********************************************************************
*
*驱动探测,初始化
*
**********************************************************************/
static int ampipidevice_probe(struct platform_device *pdev)
{
	struct resource *r_mem; /* IO mem resources */
	struct device *dev = &pdev->dev;
	struct ampipidevice_local *lp = NULL;

	int rc = 0;
	
	printk("ampipi Device Tree Probing\n");
	/* Get iospace for the device */
	r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!r_mem) 
	{
		dev_err(dev, "invalid address\n");
		return -ENODEV;
	}
	
	lp = (struct ampipidevice_local *) kmalloc(sizeof(struct ampipidevice_local), GFP_KERNEL);
	if (!lp) 
	{
		dev_err(dev, "Cound not allocate ampipidevice device\n");
		return -ENOMEM;
	}
	
	
	dev_set_drvdata(dev, lp);
	
	lp->mem_start = r_mem->start;
	lp->mem_end = r_mem->end;

	if (!request_mem_region(lp->mem_start,lp->mem_end - lp->mem_start + 1,DRIVER_NAME)) 
	{
		dev_err(dev, "Couldn't lock memory region at %p\n",
			(void *)lp->mem_start);
		rc = -EBUSY;
		goto error1;
	}

	lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
	if (!lp->base_addr) 
	{
		dev_err(dev, "ampipidevice: Could not allocate iomem\n");
		rc = -EIO;
		goto error2;
	}

	lp->cpu0_to_cpu1_ipi = 12;
	lp->cpu1_to_cpu0_ipi = 13;//默认值

	/* Read ipi12 ipi number 用于 ucos 通知 linux */
	rc = of_property_read_u32(pdev->dev.of_node, "ipi12",&lp->cpu1_to_cpu0_ipi);
	if (rc < 0) 
	{
		dev_err(&pdev->dev, "unable to read property ipi 12");
		goto error3;
	}

	rc = set_ipi_handler(lp->cpu1_to_cpu0_ipi, cpu1_to_cpu0_ipi_kick,"cpu 1 kick cpu0");
	if (rc) 
	{
		dev_err(&pdev->dev, "IPI 12 handler already registered\n");
		goto error3;
	}

	/* Read ipi13 ipi number 用于 linux 通知 ucos */
	rc = of_property_read_u32(pdev->dev.of_node, "ipi13",&lp->cpu0_to_cpu1_ipi);
	if (rc < 0) 
	{
		dev_err(&pdev->dev, "unable to read property ipi 13");
		goto error3;
	}

	printk("ampipidevice at 0x%08x mapped to 0x%08x len= %08X , ipi= %d\n",
		(unsigned int __force)lp->mem_start,
		(unsigned int __force)lp->base_addr,
		(unsigned int __force)(lp->mem_end - lp->mem_start+1),
		lp->cpu0_to_cpu1_ipi);
		
	
	ampipi_init(lp); 
	
	rc = alloc_chrdev_region(&ampipi.devid, 0, DRIVER_NUM, DRIVER_NAME); 
	if(rc)
	{
		dev_err(&pdev->dev, "unable to alloc_chrdev_region ");
	}
	
	ampipi.chdev.owner = THIS_MODULE; 
	cdev_init(&ampipi.chdev, &ampipi_fops); 
	
	rc = cdev_add(&ampipi.chdev, ampipi.devid, 1); 
	if(rc)
	{
		dev_err(&pdev->dev, "unable to cdev_add ");
	}	
	
	ampipi.class = class_create(THIS_MODULE, DRIVER_NAME); 
	if (IS_ERR(ampipi.class)) 
	{ 
		dev_err(&pdev->dev, "unable to class_create ");
	} 	
	
	ampipi.device = device_create(ampipi.class, &pdev->dev,ampipi.devid, NULL, DRIVER_NAME); 
	if (IS_ERR(ampipi.device)) 
	{ 
		dev_err(&pdev->dev, "unable to device_create ");
	} 	
	
	return 0;
	
error3:
	clear_ipi_handler(lp->cpu0_to_cpu1_ipi);	
error2:
	release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
error1:
	kfree(lp);
	dev_set_drvdata(dev, NULL);
	return rc;
}

static int ampipidevice_remove(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct ampipidevice_local *lp = dev_get_drvdata(dev);
	
	
	device_destroy(ampipi.class, ampipi.devid); 
	class_destroy(ampipi.class); 	
	cdev_del(&ampipi.chdev); 	
	unregister_chrdev_region(ampipi.devid, DRIVER_NUM); 	

	clear_ipi_handler(lp->cpu0_to_cpu1_ipi);
	
	iounmap(lp->base_addr);
	
	release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
	
	kfree(lp);
	
	dev_set_drvdata(dev, NULL);
	
	cpu_up(1);
	
	return 0;
}


static struct of_device_id ampipidevice_of_match[] = 
{
	{ .compatible = "my_qq_is,260869626", },
	{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, ampipidevice_of_match);


static struct platform_driver ampipidevice_driver = 
{
	.driver = 
	{
		.name = DRIVER_NAME,
		.owner = THIS_MODULE,
		.of_match_table	= ampipidevice_of_match,
	},
	.probe		= ampipidevice_probe,
	.remove		= ampipidevice_remove,
};

static int __init ampipidevice_init(void)
{
	printk("ampipidevice module init...! \n");

	return platform_driver_register(&ampipidevice_driver);
}


static void __exit ampipidevice_exit(void)
{
	platform_driver_unregister(&ampipidevice_driver);
	printk(KERN_ALERT "ampipidevice module exit\n");
}

module_init(ampipidevice_init);
module_exit(ampipidevice_exit);

然后在设备树里面添加下面一段

ampipi_instance: ampipimod@0 {
		compatible = "my_qq_is,260869626";
		reg = <0x38000000 0x8000000>;
		ipi12 = <12>;
		ipi13 = <13>;
		
	};

然后编译内核和驱动即可,这个驱动提供了一个接口,write会将要运行在cpu1上的bin文件加载到设备树的内存地址里, ioctl提供starCPU1,stopCPU1,KickCpu1  3个命令,分别启动,停止,ipi中断通知cpu1的操作,

实际linux端应用编写如下

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <fcntl.h>

unsigned char cpu1_bin_data[114704];

static void sigio_signal_func(int signum)
{
	static ii=0;
	printf("CPU0 Kick up %d \n",ii++);//cpu1 ipi中断触发linux,通知linux 有消息处理

}



int main()
{
	int fd, ret,i=0;

    fd = open("/dev/acdp_Device", O_RDWR);
    if(0 > fd)
    {
    	 printf("acdp dev open failed!\r\n");
    	 return -1;
    }

    signal(SIGIO, sigio_signal_func); 				//	设置信号 SIGIO 的处理函数
    fcntl(fd, F_SETOWN, getpid()); 					//  将当前进程的进程号告诉给内核
    i = fcntl(fd, F_GETFD);  						//  获取当前的进程状态
    fcntl(fd, F_SETFL, i | FASYNC);           	//  设置进程启用异步通知功能

    lseek(fd,0,SEEK_SET);
    ret = write(fd, cpu1_bin_data, 114704);//将cpu1的bin文件写入内存中
    if(0 > ret)
    {
    	 printf("write Failed!\r\n");
    }

    ioctl(fd,0x10000000,NULL);//启动cpu1

while(1)
{
    sleep(5);
    ioctl(fd,0x30000000,NULL);//linux触发 cpu1 的ipi中断,通知cpu1 有消息到达
}

    close(fd);


    return 0;
}

实际ucos端程序如下

#include  <stdio.h>
#include  <Source/os.h>
#include  <ucos_bsp.h>

#include "xgpiops.h"
#include "xil_io.h"
#include "xscugic.h"

#define  SGI0_INTR_ID  0
#define  SGI1_INTR_ID  1
#define  SGI2_INTR_ID  2
#define  SGI3_INTR_ID  3
#define  SGI4_INTR_ID  4
#define  SGI5_INTR_ID  5
#define  SGI6_INTR_ID  6
#define  SGI7_INTR_ID  7
#define  SGI8_INTR_ID  8
#define  SGI9_INTR_ID  9
#define  SGI10_INTR_ID  10
#define  SGI11_INTR_ID  11
#define  SGI12_INTR_ID  12
#define  SGI13_INTR_ID  13
#define  SGI14_INTR_ID  14
#define  SGI15_INTR_ID  15

#define  TRIGGER_SELECTED  0x00000000
#define  TRIGGER_SELF  0x02000000
#define  TRIGGER_OTHER  0x01000000

#define  CPU_NO0  0
#define  CPU_NO1  1
#define  CPU_ID_LIST  0x00010000

#define  ICDSGIR  0xF8F01F00
#define  ICDIPTR  0xF8F01800

#define  INTC_DEVICE_ID   XPAR_PS7_SCUGIC_0_DEVICE_ID

XScuGic InterruptController; /* Instance of the Interrupt Controller */

u32 SGI_INTR;

int SGI_trigered;

void  SGI0_INTR_ID_ISR (void);

#define  DELAY  50000000

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

#define  COMM_TX_FLAG (*(volatile unsigned long *)(0xFFFF9000))

#define  COMM_TX_DATA (*(volatile unsigned long *)(0xFFFF9004))

#define  COMM_RX_FLAG (*(volatile unsigned long *)(0xFFFF9008))

#define  COMM_RX_DATA (*(volatile unsigned long *)(0xFFFF900C))


u32 SetupSGIIntrSystem(XScuGic *IntcInstancePtr,Xil_InterruptHandler Handler, u32 DeveiceId, u32 SgiIntr, u32 CpuNo)
{
    int Status;

    XScuGic_Config *IntcConfig;

	IntcConfig =  XScuGic_LookupConfig(DeveiceId);

    if (NULL  == IntcConfig)
    {
        return XST_FAILURE;
    }

    Status =  XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);

    if (Status != XST_SUCCESS)
    {
        return XST_FAILURE;
    }

    XScuGic_SetPriorityTriggerType(IntcInstancePtr, SgiIntr,0xd0, 0x3);

    Status =  XScuGic_Connect(IntcInstancePtr, SgiIntr, (Xil_ExceptionHandler)Handler,0);

    if (Status != XST_SUCCESS)
    {
        return XST_FAILURE;
    }

    XScuGic_Enable(IntcInstancePtr, SgiIntr);

    XScuGic_InterruptMaptoCpu(IntcInstancePtr,CpuNo,SgiIntr);

    return XST_SUCCESS;

}

void  ExceptionSetup(XScuGic *IntcInstancePtr)
{
    Xil_ExceptionInit();

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

    Xil_ExceptionEnable();
}

void  SGI1_INTR_ID_ISR (void)
{
	printf("CPU0: The software interrupt0 has been triggered\n\r");

    SGI_trigered=1;
}

/*
*********************************************************************************************************
*                                      LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/

void  MainTask (void *p_arg);


/*
*********************************************************************************************************
*                                               main()
*
* Description : Entry point for C code.
*
*********************************************************************************************************
*/

int main()
{

    UCOSStartup(MainTask);

    return 0;
}


/*
*********************************************************************************************************
*                                             MainTask()
*
* Description : Startup task example code.
*
* Returns     : none.
*
* Created by  : main().
*********************************************************************************************************
*/

void  MainTask (void *p_arg)
{
	OS_ERR  os_err;
	int i=0;
	static XGpioPs psGpioInstancePtr;
	XGpioPs_Config *GpioConfigPtr;
	int xStatus;
	int Status;

    SGI_INTR=SGI13_INTR_ID;
    SGI_trigered=0;
    Status =  SetupSGIIntrSystem(&InterruptController,(Xil_ExceptionHandler)SGI1_INTR_ID_ISR,INTC_DEVICE_ID, SGI_INTR,CPU_NO1);
	if (Status != XST_SUCCESS)
	{
		UCOS_Print("FAILED Xil_ExceptionHandler \n\r");
	}
	ExceptionSetup(&InterruptController);

	GpioConfigPtr =XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
	if(GpioConfigPtr == NULL)
		UCOS_Print("PS GPIO INIT FAILED1 \n\r");

	xStatus =XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr,GpioConfigPtr->BaseAddr);
	if(XST_SUCCESS != xStatus)
		UCOS_Print("PS GPIO INIT FAILED2 \n\r");

	XGpioPs_SetDirectionPin(&psGpioInstancePtr,0,1);
	XGpioPs_SetOutputEnablePin(&psGpioInstancePtr,0,1);

	printf("Starting application...\n");

	while(1)
	{
		XGpioPs_WritePin(&psGpioInstancePtr,0,1);
		OSTimeDlyHMSM(0, 0, 0, 200, OS_OPT_TIME_HMSM_STRICT, &os_err);
		XGpioPs_WritePin(&psGpioInstancePtr,0,0);
		OSTimeDlyHMSM(0, 0, 0, 200, OS_OPT_TIME_HMSM_STRICT, &os_err);

		XScuGic_SoftwareIntr(&InterruptController,SGI12_INTR_ID,0x1<<CPU_NO0);

	}
}

 

实际运行时当cpu1的ucos运行起来后每400ms会触发一次ipi中断,linux收到中断后打印 printf("CPU0 Kick up %d \n",ii++);然后linux发一次ipi中断给ucos,ucos收到后打印printf("CPU0: The software interrupt0 has been triggered\n\r");

串口截图如下

显示是乱的,实际是正常的,因为linux和ucos使用的是同一个串口,两个系统竞争使用导致打印错乱了,这个并不影响试验结果!

 

 

 

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
文档共60页。主要向初学者提供了Zynq开发的技术方向,针对不同应用给出了基本的参考文档;同时对Zynq双核AMP加载方式做了详细描述,对Zynq的fsbl启动流程做了简单介绍。章节如下: Zynq User Guide 1 介绍 4 2 快速上手指南 4 3 多核开发教程 4 3.1 AMP开发说明 6 3.1.1 快速生成amp工程 6 3.1.2 Generating Boot File 8 3.1.3 烧写程序 9 3.1.4 启动 10 3.1.5 调试 10 3.1.6 总结 11 3.2 SMP开发说明 11 4 ZC706启动代码分析 11 4.1 启动代码 12 4.2 FSBL流程(FOR AMP) 13 4.3 CPU0启动CPU1流程 14 5 程序在线烧写方案及流程 14 5.1 程序烧写需求 14 5.2 提出该需求的原因 14 5.3 程序烧写方案 14 5.3.1 BOOT.BIN组成 14 5.3.2 BOOT.BIN生成方法 15 5.4 FSBL.BIN和APP.BIN等的生成 15 5.5 制作*BIN及烧写的具体步骤 15 5.5.1 制作*bin流程 15 5.5.2 BOOT.bin制作过程 15 5.5.3 FSBL.bin和APP.bin等的生成过程 22 5.6 烧写BOOT.BIN步骤 26 5.6.1 通过SDK工具烧写步骤 26 5.6.2 通过上位机烧写软件的烧写步骤 29 5.6.3 通过串口调试助手烧写步骤 29 6 Zynq Qspi控制器 30 6.1 基本特性 30 6.2 I/O接口 31 6.3 QSPI控制器模式 33 6.3.1 I/O模式 33 6.3.2 线性地址(linear address)模式 33 6.3.3 传统(legacy)SPI模式 34 6.4 QSPI 例程 34 6.5 QSPI控制器支持访问32MB方法 35 6.5.1 Bank地址寄存器(Bank address register) 35 6.5.2 扩展地址模式(Extended address mode) 35 6.5.3 使用新写命令(New commands) 35 6.6 QSPI FLASH选择 35 6.7 作为BOOT器件考虑 35 7 µC/OS系统启动指南 36 7.1 INTRODUCTION 36 7.1.1 Software Requirements 36 7.1.2 Hardware Requirements 36 7.2 HARDWARE DESIGN 37 7.2.1 Step 1. Invoke the Vivado IDE and Create a project 37 7.2.2 Step 2. Create an IP Integrator Design 39 7.2.3 Step 3. Add and setup the Zynq processor system IP block 39 7.2.4 Step 4. Customize the Zynq block for our design 41 7.2.5 Step 5. Add the soft peripherals 45 7.2.6 Step 6. Generate HDL Design Files 47 7.2.7 Step 7. Synthesis, Implement and Generate Bitstream 48 7.3 SOFTWARE DESIGN 49 7.3.1 Step 1. Installation of the µC/OS Repository 49 7.3.2 Step 2. Generate the µC/OS BSP 50 7.3.3 Step 3. Build and Debug the Demonstration Project 54 7.3.4 Step 4. Program the AXI Timer 0 with the ucos_axitimer Driver 55 7.3.5 Step 5. Program the AXI Timer 1 with the Xilinx tmrctr Driver 58 7.4 CONCLUSION 59 8 Linux系统启动指南 59
### 回答1: Zynq双核指的是Zynq系统中的两个处理器核心,一个是Arm Cortex-A9处理器核,另一个是可编程逻辑(FPGA)。Petalinux是一个基于Linux的操作系统,可用于Zynq系统的开发。裸机指的是没有操作系统的程序,只在硬件上运行。 在Zynq双核系统中,Petalinux裸机可以通过多种方式通信: 1. 通过寄存器:Petalinux可以读取和写入FPGA寄存器,从而与裸机进行通信。 2. 通过内存映射:Petalinux裸机可以共享相同的物理内存区域,从而进行通信。 3. 通过中断Petalinux可以通过发送中断请求给裸机,从而与裸机进行通信。 4. 通过串口:Petalinux裸机可以通过串口进行通信,Petalinux可以发送数据给裸机裸机可以通过串口返回数据给Petalinux。 总的来说,Petalinux裸机的通信方式取决于具体的应用场景和系统架构。 ### 回答2: Zynq是一款集成了ARM处理器和可编程逻辑的片上系统,使用Petalinux实现对该芯片的Linux操作系统进行定制和开发。在Zynq双核系统中,可以使用Petalinux裸机方式进行通信。 要在Petalinux裸机之间进行通信,有多种方法可以选择。以下是一种常用的方法: 1. 通过共享内存(Shared Memory)进行通信:在Petalinux中,可以使用mmap函数将一块物理内存映射到用户空间,然后将这块内存的地址传递给裸机程序。裸机程序可以通过访问该地址来读写共享内存。这种方式可以实现高速的数据传输,但需要保证共享内存的同步和互斥机制,以避免数据冲突和竞争条件。 2. 通过中断(Interrupt)进行通信:Petalinux可以通过中断控制器向裸机程序发送中断请求。裸机程序需要编写中断服务程序来处理中断,并进行相应的数据处理或响应。通过中断方式可以实现异步的通信,但需要在裸机Petalinux进行中断控制和数据传输的协议设计。 3. 通过设备驱动程序进行通信:在Petalinux中编写设备驱动程序,将裸机中需要访问的硬件资源封装成设备节点,然后通过设备文件进行读写操作。裸机程序可以通过访问设备文件来与Petalinux进行通信。这种方式需要在Petalinux中编写设备驱动程序,并实现对硬件资源的访问和控制。 无论使用哪种通信方式,都需要在Petalinux裸机程序中进行相应的配置和编程。同时,还需要考虑通信的同步、互斥和错误处理等方面,以保证通信的可靠性和稳定性。 ### 回答3: Zynq是一款由Xilinx开发的可编程SoC(系统级芯片),它集成了双核处理器和可编程逻辑电路,并支持多种外设接口和通信协议。Petalinux是一种基于Linux系统的嵌入式开发平台,可以在Zynq芯片上运行。 要实现Zynq双核裸机之间的通信,可以通过以下几种方式: 1. 共享内存:在Petalinux系统中,可以通过在内存中定义一块共享区域,使双核处理器和裸机都能够访问此共享内存。双核处理器可以通过操作系统提供的共享内存接口进行读写,而裸机则需要通过硬件访问控制器来操作共享内存。 2. 中断:通过设置中断控制器,在Petalinux中,双核处理器和裸机都可以注册相应的中断处理函数。当需要通信的一方发生事件时,通过触发中断来通知另一方。中断处理函数中可以进行数据的读写操作。 3. 外设寄存器:Zynq芯片上的可编程逻辑部分可以通过外设寄存器与双核处理器和裸机进行通信。Petalinux系统中,双核处理器可以通过内核驱动来访问外设寄存器,而裸机则可以直接通过寄存器操作指令来读写外设寄存器。 需要注意的是,双核处理器和裸机之间的通信需要进行同步和互斥操作,以避免数据冲突和竞争条件的发生。在设计通信协议时,需要考虑数据格式、通信速率、错误处理等方面的问题,并进行相应的数据校验和纠错处理。 总的来说,Zynq双核裸机之间的通信可以通过共享内存、中断和外设寄存器等方式实现。具体的实现方式要根据具体的应用场景和需求来选择和设计。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值