基于ZYNQ 的多轴运动控制平台关键技术研发-Linux+xenomai开源实时系统设计(二)

4. SoC 双核系统与核间多任务通信设计
本章详细介绍 AMP 架构下 SoC 核系统的设计和核间任务通信的实现方法。首
先,进行双核系统的搭建并完成设备驱动的移植;然后,进行基于共享内存的通信模
块设计;最后,针对系统不同通信任务的要求,提出多任务通信的实现方案。
4.1 双核系统设计与实现
4.1.1 Linux 实时系统搭建
1 Xenomai 实时补丁安装
机器人控制系统需要具有强实时性能力,在运行时必须保证运动控制相关的任
务调度和数据通信的实时处理和响应。 Linux 系统因支持内核抢占、中断屏蔽和优先
级抢占调度等机制,无法提供严格的强实时性能。 Linux 系统的实时性优化有两种方
法,分别为 Linux 内核源码改进和 Linux 双内核扩展。其中,内核改进法方便用户进
行指定方向的性能优化,但存在工作量大,改造难度高等问题。
因此,本文通过 Xenomai Linux 系统进行拓展,实现双内核实时系统,即满足
系统使用要求,同时提高了开发效率。 Xenomai 采用 Adeos(Adaptive Domain
Environment for Operating System) 技术保证硬实时的拓展,双内核架构如图 4.1 所示。
在采用 Adeos 的双核架构中, Adeos 主要完成域的调度、中断和域的管理等工
作。在 Adeos 架构中设置了域的优先级, Xenomai 域要高于普通的 Linux 域。因此,
当系统接收到中断信号时,
Adeos 将中断分配给 Xenomai 进行处理;只有当 Xenomai
域的任务执行完成后,
Linux 域中的任务才会继续执行。通过上述调度方法, Adeos
保证了 Xenomai 域的优先级,从而保证了任务的实时处理。如图 4.2 所示,本文使用
Linux 4.9.0 版本内核和 Xenoma 3.0.7 实现实时系统的搭建。

为了保证 Xenomai 正确使用,表 4.1 中列出内核配置中重要的 Xenomai 部分功
能项。其中,内核需要开启 Xenomai 相关的服务项,同时关掉与实时性功能相冲突
的内核选型,保证系统的正常运行。
Linux+Xenomai 系统搭建完成后,验证 Xenoma 是否安装成功。在 Linux 启动
完成后,通过 dmesg |grep I-pipe dmesg |grep Xenomai 命令查看安装状态。如图 4.3
所示,系统完成 Xenomai 实时补丁的安装。
(2) Linux 设备驱动移植
基于 SoC 关键通信接口设计,在 Linux 系统下完成对外设驱动的移植,保证系
统设备的正确使用,实现平台对外通信。如图 4.4 所示, Linux 4.9.0 内核使用总线架
构的设备模型。

 在总线架构的设备模型中,系统的设备和驱动是分离的,使用总线机制对二者进

行匹配。总线设备模型为系统的驱动移植提供了一致性接口,简化了移植流程,提高
了开发效率。
进行 SoC 平台通信接口设备的驱动移植,具体分为两种方法:
1 )当内核提供该设备驱动时,直接使用内核中的驱动。
(2)对于内核中不提供驱动的设备,为其设计驱动程序并进行移植。
首先,通过查看内核 config 配置文件, Linux-4.9.0 内核提供千兆以太网、 USB
HUB UART 的设备驱动支持。因此采用方法( 1 )进行驱动移植,具体如下:使
make menuconfig 命令开启内核配置;将设备驱动配置为静态加载,实现系统启
动时驱动自加载功能;使用 arm-linux-gcc 完成 zImage 的编译生成。如图 4.5
示,在使用 zImage 完成系统启动后,通过 dmesg 命令查看内核日志,千兆以太
网、 USB HUB UART 的驱动程序已完成注册,设备可以正常使用。
Linux-4.9.0 内核中不提供 AX88772B 网卡芯片的驱动程序, USB 扩展的百兆以
太网接口无法直接使用,因此采用方法(
2 )进行 AX88772B 网卡驱动程序的移植。
出于减小开发难度和节约开发时间的目的,本文使用 AX88772B 官方驱动源码,
并在其基础上根据平台功能需求进行相应设计。通过分析, AX88772B 在使用中,通
过外部存储器保存用户写入的 PHY 芯片 MAC Media Access Control Address )地址,
进而完成驱动程序注册。为了满足系统快捷化和多样化的配置需求,本文提出一种基
AX88772B 芯片的 MAC 地址动态设置方法。具体方法为:将用户自定义 MAC
址预先存储在 Flash 设备中;驱动程序在注册中,如果未检测到外部存储器,则从
Flash 中读取用户 MAC 地址,完成注册。如图 4.6 所示,完成 AX88772B 驱动程序
的修改,并在 Linux 环境下生成内核驱动模块,方便用户根据使用情况进行动态加
载。
如图 4.7 所示,系统加载 asix.ko 内核模块,驱动在注册过程中通过 flash 为两个
AX88772B 网卡分配 MAC 地址,网卡驱动移植成功。
4.1.2 伺服裸机系统构建
CPU1 上搭载伺服裸机系统需要完成以下三部分工作: Linux 系统在运行时将
CPU 使用数量设置为 1 CPU0 完成 CPU1 伺服应用程序的加载; CPU0 完成 CPU1
的唤醒。
Linux 系统在启动阶段,默认使用 SMP 对称处理模式,同时对两个 CPU 进行管
理,协调 CPU 之间的相关工作。因此,在使用 AMP 架构时,需要限制 Linux 系统
只占用 CPU0 CPU1 预留用于伺服裸机系统。 Linux 启动过程中,内核文件根据环
境变量 bootargs 对系统进行相应配置,用户可以通过修改变量 bootargs 实现 CPU 使
用数量的指定。变量 bootargs 的生成分为直接指定法和 Bootloader 生成法两种方式。
其中,直接指定法是在内核配置过程中设置 bootargs ,这种方法保证 bootargs 在重新
配置前的唯一性和有效性; Bootloader 生成法是在 Bootloader 文件中设置 bootargs
并在 Bootloader 执行完毕后将其传递给内核。这种方法提供了用户修改 bootargs
可能性和快捷性,有利于软件的开发和维护。本文采用 Bootloader 生成法。在
Bootloader 启动过程中对 bootargs 进行动态配置和保存,将 Linux 系统使用的 CPU
数量设置为 1 ,从而保证 CPU1 的空闲状态。环境变量 bootargs 值配置如表 4.2 所示。
在保证 CPU1 处于空闲状态后, CPU0 需要完成伺服应用程序 CPU1_APP 的加
载。 CPU1_APP 的加载工作是将应用程序写入用户指定的内存空间中。 Xilinx SoC
加载裸机程序提供了两种实现方法:第一种是使用 Jtag 烧写器将 CPU1_APP 写入内
存。此方法需要使用到外部烧写器,而且只能实现程序的单次加载,因此适用于系统
开发和调试阶段。第二种方法是使用 Xilinx SDK 工具将 CPU1_APP 集成到 Bootloader
中形成 BOOT.bin 文件;系统启动时执行 BOOT.bin 文件,自动寻找 CPU1_APP 并将
其加载到指定内存中。第二种方法不需要烧写器,加载操作方便;但是,多文件集成
的加载方式破坏了伺服应用程序的独立性,不利于后续软件的单独更新。
本文提出一种基于 Bootcmd 环境变量的应用程序加载方法。 Bootcmd
Bootloader 的一种环境变量,保存了 Bootloader 在启动后执行的指令操作。通过在
Bootloader 启动阶段,对 Bootcmd 进行动态设置,添加加载 CPU1_APP 程序的指令
操作并保存。如图 4.8 所示,平台在复位操作后, Bootloader 会执行 Bootcmd 中的命
令,将 CPU1_APP 加载到指定内存中。本方法同样适用于 FPGA 烧写文件的动态加
载,有效保证了用户文件的独立性。

Zynq 7020 SoC AMP 架构下, CPU1 SoC 上电后首先执行芯片固件程序进
入休眠状态。此时,必须通过 CPU0 才能将 CPU1 唤醒。基于 Xilinx 提供的 CPU1
醒方法, 在进行 CPU1 伺服软件的重运行操作时,需要将双系统进行复位,不满足
运动控制系统的使用要求。
因此,本文提出一种针对 SoC AMP 架构下的 CPU1 可单独重运行的方法。方法
的实现流程如下:( 1 )系统启动阶段, CPU0 完成 CPU1_APP 的加载;
(2)系统启动 完成后,CPU0 将一段可实现 CPU1 程序跳转的指令写入地址 0x0 的内存中;
(3) CPU0 中执行 CPU1 的复位操作;
(4) CPU1 重启后,执行地址 0x0 处的跳转指令,
跳转到 CPU1_APP 加载地址
(5) CPU1 执行 CPU1_APP ,伺服系统重运行完成。
基于图 4.9 所示方法,完成 CPU1 程序的加载和运行,实现伺服系统的搭建。
4.2 核间通信模块设计
基于双核间多任务通信需求,本文采用共享内存 OCM 作为通信媒介,并进行如
下通信模块设计:共享内存的管理方法、核间信号量设计和消息邮箱设计。
4.2.1 共享内存的管理方法
共享内存是双核间任务通信的物理介质,用于保存通信数据。本文采用 SoC
片内部的 256K 片上内存作为共享内存,其在 4G 寻址空间的地址范围为
0xFFFC0000~0xFFFFFFFF 。片上共享内存 OCM SoC 芯片启动过程中,会被用于
系统启动文件的加载和运行;系统启动完成后, OCM 内部数据并不为空。因此,在
使用 OCM 进行任务通信时,为了保证 OCM 中数据的安全性和一致性,需要进行如
下操作:
1 )机器人控制程序开始运行时, Linux 系统完成 OCM 访问申请并对 OCM
行初始化;
2 )每次完成伺服系统重运行后, Linux 系统需要对 OCM 进行初始化;
3 )机器人控制程序运行结束时, Linux 系统关闭内存映射,释放共享内存。
针对以上操作,设计并实现了用于 Linux 系统访问 OCM 的三个接口函数,分别
为: System_Ocm_Req() System_Ocm_Init() System_Ocm_Free() ,函数功能依次为
OCM 申请、 OCM 初始化和 OCM 释放。
Linux 系统中,用户进程无法同裸机程序一样直接对物理内存进行访问。为了
保证用户进程对共享内存的快速访问, System_Ocm_Req() 函数通过内存映射方法
Memory Map ,简称 MMAP ),完成共享内存的申请操作。 MMAP Linux 系统下
的一种系统调用,其功能是将一个文件或者其他对象映射到进程的地址空间。如图
4.10 所示, System_Ocm_Req() 中使用 MMAP 完成 256KB 大小的 OCM 物理内存空
间的访问申请。申请成功后, System_Ocm_Req() 函数返回一个基地址指针,用户进
程通过指针方式对 OCM 进行读写操作。
System_Ocm_Init() 函数主要完成对 OCM 的状态检查,读写校验和擦除。状态检
查中, Linux 访问 OCM 状态寄存器并判断 OCM 是否存在通信错误,如果存在错误
则对其进行复位操作;如果状态正常,则进行读写校验。读写校验中,通过向 OCM
写入用户测试数据,写入完成后将 OCM 中数据读出,比较写读前后数据的一致性。
如果读写校验成功,对 OCM 进行擦除操作,保证双核系统通信的安全性;否则,表
OCM 校验失败, Linux 系统进行相应的出错处理。
在机器人控制软件运行结束时,为了保证系统的安全性,需要关闭 OCM 在进程
空间中的映射,此时通过 System_Ocm_ Free () 函数实现。 System_Ocm_ Free () 中通过
使用 munmap() 系统调用,实现映射关系的解除,完成 OCM 的释放。如图 4.11 所示,
Linux 在任务执行阶段,对 OCM 的进行有序访问。
4.2.2 核间信号量设计
为了保证双核对 OCM 数据访问的互斥性和一致性,引入信号量设计思想,并根
据双核间任务通信的使用要求完成核间信号量的设计。信号量是一种用于多进程(或
线程)情况下,避免共享资源被不同对象同时访问的保护机制 [44] 。采用信号量同步
机制时,进程(或线程)会获取一个非负整数的信号量,表示共享资源的访问状态。
信号量非零时,表示有空闲共享资源,允许进程(或线程)访问;信号量为零时,表
示共享资源为空,此时进程(或线程)将处于等待状态。如果共享资源数量大于 1
称为计数信号量( Counting semaphore );如果共享资源数量为 1 ,信号量只有 0 1
两种状态,称为二进制信号量( binary semaphore )。
本文设计了二进制的核间信号量,并根据双核间任务通信时序,对核间信号量的
访问进行约束。核间信号量表示 OCM 数据区的访问状态,具体定义如表 4.3 所示。
其中,核间信号量为 1 时,表示 OCM 数据区处于空闲,可以发起任务通信;核间信
号量为 0 时,表示 OCM 数据处于忙状态,任务通信正在进行。如果信号量出现为其
他状态,表明双核系统在任务通信过程中发生通信错误。

在双核间任务通信开始前, Linux 系统对信号量进行初始化,将其设置为 1 。在
双核间任务通信阶段,对信号量进行以下操作:
1 )双核系统对信号量均有可读 / 可写权限,若读写操作同时发生时,读操作优
先权高于写操作优先权。
(2)双核系统任务通信阶段,进行“ CPU0 -CPU0 修改 -CPU1 -CPU1 修改”
顺序的信号量访问。
其中,( 1 )保证了在任务通信过程中,双核系统可以根据通信状态对信号量进行
设置;在访问优先级设置上,读操作高于写操作,当双核系统同时对信号量进行读写
操作时,保证信号量先被读取,避免通信状态的丢失。(
2 )设置了通信过程中双核系
统对信号量的访问顺序。在双核间任务通信时,通信由 Linux 系统先发起,此时系统
读取信号量并判断其状态,当信号量为 1 时开始访问 OCM ;当信号量为 0 时,表示
任务通信已处于进行状态。图 4.12 表示双核系统任务通信阶段的信号量状态切换。
linux 系统完成 OCM 访问后,将信号量设置为 0 。伺服系统持续读取信号量,当
信号量为 1 时,表示未发生通信;当信号量为 0 时,表示通信正在进行,伺服系统开
始访问 OCM 。当伺服系统完成 OCM 访问后,将信号量重新设置为 1 ,表示 OCM
于空闲状态。
4.2.3 数据消息邮箱设计
双核系统任务通信阶段,需要支持多种类型数据通信,因此采用消息邮箱实现数
据传输。消息邮箱是一种任务间的数据通信方法,设计简单且系统开销少 [45] 。系统
任务将通信数据打包处理后发送给邮箱,邮箱接收到数据邮件后,根据邮箱状态将邮
件转发至其他任务。针对多轴运动控制的使用要求和邮箱通信的特点,本文设计两种
邮箱通信方式,分别为固定长度邮箱通信和可变长度邮箱通信。
固定长度邮箱通信中,邮件数据长度固定,系统可根据通信数据的使用要求设置
8/16/32/64 位。采用固定长度邮箱进行任务通信时,在双核系统初始化阶段,需要
对邮箱地址进行设置,保证双核系统对同一邮箱的访问。
可变长度邮箱通信时,邮件内容为通信数据帧,数据帧长度不定。为了保证邮件
的正确解析,双核系统需要对数据帧进行统一设置。因此,设计一种支持读写命令和
可变数据长度的数据帧格式,帧结构如表 4.4 所示。邮件数据帧的数据采用 32 位对
齐方式,方便双核系统进行数据帧的保存和解析。同时,在双核系统初始化阶段,需
要对邮箱地址进行设置,保证双核系统对同一邮箱的访问。
为固定长度和可变长度两种邮箱通信方式设计不同的接口函数,分别为
DRV_Control() DRV_ASYControl() ,函数的具体功能定义如表 4.5 和表 4.6 所示。
信迈提供ZYNQ+LINUX+Xenomai+运动控制系统实时系统移植方案。

猜你喜欢

转载自blog.csdn.net/YEYUANGEN/article/details/129783845