ZYNQ双核运行控制外设(CAN、GPIO)时需要注意的点

项目场景:

我在使用ZYNQ7010进行双核开发,目前双核可以成功启动,CPU0跑linux系统,CPU1跑Freertos系统,在CPU1下需要控制一些外设,比如CAN控制器,我发现双核对于外设是共享的,而不是互斥,因此如果要在CPU1下控制CAN控制器,就必须在两个核下都初始化,否则无法使用


问题描述

提示:这里描述项目中遇到的问题:

在ZYNQ双核下,如果我想在CPU1下控制CAN,刚开始我以为外设的控制对于双核来说是互斥的,网上也没找到相关资料描述双核间资源的控制,所以我在CPU1下控制CAN时,就把CPU0下关于CAN的配置都禁用掉,由于我CPU0下运行Linux系统,所以我把设备树和内核配置CAN相关都禁用,但是发现禁用后CPU1仍然无法控制CAN

原因分析:

后来通过尝试,我发现对于CAN或GPIO这种外设资源,双核中间是共享的,而且配置时必须都初始化,但是初始化也要注意顺序,必须CPU0先启动CAN控制器,再在CPU1下初始化,不能只在一个核下禁用


解决方案:

提示:这里填写该问题的具体解决方案:

1.首先对CPU0下的Linux系统配置与CAN相关的设备树和内核
对ZYNQ来说,进入到 Linux 内核源码目录,打开 arch/arm/boot/dts/zynq-7000.dtsi 设备树文件,在这个设备树文件当中有两个 CAN 节点,分别为 can0 和 can1,如下所示:

在这里插入图片描述
这是 xilinx 官方提供的 CAN 总线控制器节点配置信息,两个设备节点的 status 属性的值都是"disabled",也就是说默认情况下 CAN 外设是没有使能的,当我们在 vivado 软件中打开了相应的 CAN 控制器外设的时候,编译 hdf 文件得到pcw.dtsi 设备树文件中就会将 CAN 节点的 status 属性设置为"okay";我们打开arch/arm/boot/dts/pcw.dtsi 设备树文件,如下所示:
在这里插入图片描述
因为我们使用 vivado 工程只打开了 CAN0 控制器外设,所以 pcw.dtsi 设备树文件中就只
将 can0 节点的 status 设置为"okay",注意 pcw.dtsi 文件是自动生成的,我们不用对它进行
修改!
对于内核配置,我们使用的 Linux 内核源码默认已经使能了 ZYNQ CAN 驱动模块,所以这里不用再去配置了。
在这里插入图片描述
2.在CPU0的Linux系统配置完CAN后,此时在启动Linux系统后,输入ifconfig -a命令可以查看到CAN设备
在这里插入图片描述
此时如果要在CPU1下控制CNA设备,需要在CPU1下初始化,但是此初始化必须在CPU0启用CAN设备之后,否则控制失败,此处我的做法是,首先将Linux启动CAN的操作写为脚本放在Linux自启动程序下,启动CAN设备的操作为
在这里插入图片描述
然后在CPU1的程序中延迟10s左右,等Linux系统起来运行CAN控制器启动脚本之后,再在CPU1下初始化CAN
下面展示一些在ZYNQ下初始化CAN控制器的代码片。

// An highlighted block
 BOOLEAN Can0Ps_Init(uint8_t canid,XScuGic *IntcInstPtr, XCanPs *CanInstPtr)
 {
		int Status;
		XCanPs_Config *ConfigPtr;

		/*
		 * Initialize the Can device.
		 */
		ConfigPtr = XCanPs_LookupConfig(CAN0_DEVICE_ID);
		if (ConfigPtr == NULL) {
			return XST_FAILURE;
		}
		XCanPs_CfgInitialize(CanInstPtr,
					ConfigPtr,
					ConfigPtr->BaseAddr);


	/*
		 * Enter Configuration Mode if the device is not currently in
		 * Configuration Mode.
		 */
		XCanPs_EnterMode(CanInstPtr, XCANPS_MODE_CONFIG);
		while(XCanPs_GetMode(CanInstPtr) != XCANPS_MODE_CONFIG);

		/*
		 * Setup Baud Rate Prescaler Register (BRPR) and
		 * Bit Timing Register (BTR).
		 */
		XCanPs_SetBaudRatePrescaler(CanInstPtr, CAN_CFG[0].PreFreq);
		XCanPs_SetBitTiming(CanInstPtr, CAN_CFG[0].SyncSeg,
				CAN_CFG[0].TimeSeg2,
				CAN_CFG[0].TimeSeg1);


		/*
		 * Set interrupt handlers.
		 */
		// XCanPs_SetHandler(CanInstPtr, XCANPS_HANDLER_SEND,
		// 		(void *)CAN0_SendHandler, (void *)CanInstPtr);
		XCanPs_SetHandler(CanInstPtr, XCANPS_HANDLER_RECV,
				(void *)CAN0_RecvHandler, (void *)CanInstPtr);
		XCanPs_SetHandler(CanInstPtr, XCANPS_HANDLER_ERROR,
				(void *)CAN0_ErrorHandler, (void *)CanInstPtr);
		XCanPs_SetHandler(CanInstPtr, XCANPS_HANDLER_EVENT,
				(void *)CAN0_EventHandler, (void *)CanInstPtr);


		/*
		 * Connect to the interrupt controller.
		 */
		Status =  SetupInterruptSystem(IntcInstPtr,
						CanInstPtr,
						CAN0_INTR_VEC_ID);
		if (Status != XST_SUCCESS) {
			return XST_FAILURE;
		}

		/*
		 * Enable all interrupts in CAN device.
		 XCANPS_IXR_TXOK_MASK
		 */
		XCanPs_IntrEnable(CanInstPtr, (uint32_t)XCANPS_IXR_RXNEMP_MASK | XCANPS_IXR_ERROR_MASK |
				 XCANPS_IXR_BSOFF_MASK);

		/*
		 * Enter Loop Back Mode.
		 */
		XCanPs_EnterMode(CanInstPtr, XCANPS_MODE_NORMAL);
		while(XCanPs_GetMode(CanInstPtr) != XCANPS_MODE_NORMAL);

		return XST_SUCCESS;
 }

注意,CPU1下的初始化程序,必须在Linux启动CAN控制器之后执行,否则出错。
初始化完成后再去控制CAN发送数据,此时数据可正常发送
在这里插入图片描述

  • 18
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值