在上一篇文章中,Valter Minute 讨论了总体架构以及非对称(也称为异构)多核 SoC 的优势。对于次要 Cortex-M4 内核的操作平台有多种选择:Valter 文章中讨论的示例使用 eCos RTOS,飞思卡尔推广自己的 RTOS MQX。
然而,根据应用程序的不同,人们甚至可能更喜欢裸机解决方案,例如移植旧版固件或为了其简单性。但是,也有缺点,最突出的是缺少外围设备的驱动程序。本文展示了为 Vybrid 的 Cortex-M4 内核创建定制的裸机固件时的一些技术缺陷。
作为一个示例环境,我决定为开源固件库 libopencm3 贡献 Vybrid 支持。该库在 LGPL 版本 3 下获得许可,因此明确允许将封闭源应用程序与该库链接。尽管它的名字,这个库也支持各种 Cortex-M4 微控制器,因此它非常适合 Vybrid 的 Cortex-M4 内核。使用该库,我们可以利用对 Cortex-M4 内核外设的支持,例如系统滴答定时器或嵌套中断控制器。有人可能会争辩说,使用库并不是真正的裸机,但是由于库的几乎所有组件都是完全可选的,因此与使用完整的 RTOS 相比,它更接近于裸机。
该代码尚未合并到上游项目中,但已经可以从 Github 获得(切换到 fsl-vf6xx 分支):https ://github.com/falstaff84/libopencm3和https://github.com/falstaff84/libopencm3-examples 。 此处的详细构建说明:http: //falstaff.agner.ch/2014/07/10/libopencm3-bare-metal-vybrid-examples/
内存和闪存
标准微控制器和 Vybrid 的 Cortex-M4 之间的第一个也是最显着的区别是不同的内存和闪存架构。在微控制器上,非易失性存储器通常可在控制器的线性地址空间中访问,从而允许它执行就地固件 (XIP)。在 Vybrid 上,非易失性内存通常不会以允许其就地执行的方式实现。相反,固件由主操作系统(例如 Linux)从存储介质(例如 NAND 闪存)加载到 RAM 中,随后由 Cortex-M4 内核执行。
有不少于三种内存类型可供运行:紧密耦合内存、片上内存 (OC-RAM/SRAM) 和外部 (DDR) 内存。紧密耦合内存 (TCM) 是可用的最快内存,因为它直接连接到 Cortex-M4 内核。但是,可用的内存量也非常有限。片上存储器 SRAM 是一种流行的选择,因为它在尺寸和速度方面提供了良好的折衷。飞思卡尔提供了一份详尽的文档,讨论了可用内存类型的速度和建议(请参阅 AN4947,了解 Vybrid 架构)。
另一方面是 Cortex-M4 的哈佛式架构,它由两条总线组成,一条用于数据,一条用于指令。为了确保硬件相应地使用这两条总线,内存映射提供别名以使用两条总线访问相同的内存位置:
OC-RAM Code-Bus: 0x1f000000-0x1f03ffff
OC-RAM System-Bus: 0x3f000000-0x3f03ffff
为获得最佳性能,应在链接器文件的内存描述中考虑到这一点;libopencm3 库定义了两个内存区域,代码总线 (pc_ram) 和系统总线 (ps_ram)。在以下示例中,可用内存被分成两半,每个部分有 256K 的 RAM。由于地址是整个内存范围的别名,因此可以根据项目需要自由调整这两个部分的大小。
链接器控制文件片段:examples/vf6xx/colibri-vf61/colibri-vf61.ld
MEMORY
{
pc_ram (rwx) : ORIGIN = 0x1f000000, LENGTH = 256K
ps_ram (rwx) : ORIGIN = 0x3f040000, LENGTH = 256K
}
在节部分,我们需要将代码节(文本)和数据节(例如 bss)的位置分配给这两个内存区域。
链接器控制文件片段:lib/vf6xx/libopencm3_vf6xx.ld
SECTIONS
{
.text : {
*(.vectors) /* Vector table */
。 = ALIGN(0x400);
*(.text.reset_handler) /* Force reset handler at start */
*(.text*) /* Program code */
。 = ALIGN(4);
} 》pc_ram
。..
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
。 = ALIGN(4);
_ebss = 。;
} 》ps_ram
。..
}
向量表和入口地址
另一个重要方面是向量(中断)表。在 Cortex-M4 上,向量表0x00000000在复位时读取。在微控制器上,这通常位于非易失性存储器中。在 Vybrid 上,Cortex-M4 内核最初是关闭的。在固件的初始化代码中,我们可以使用向量表偏移寄存器 (VTOR) 来定义向量表的自定义位置。在上面的链接器文件中,向量表明确放置在固件的开头。lib/vf6xx/vector_chipset.c 中的初始化代码确保在启动时设置 VTOR 寄存器。
对于 Cortex-M4 微控制器,入口点(也称为复位向量)是向量表的一部分。这引入了对 Vybrid 的循环依赖,因为我们从固件代码中初始化向量表(无法从 Cortex-A5 内核访问 VTOR 寄存器)。为了解决这个难题,辅助内核的入口点(“复位向量”)由系统复位控制器 (SRC) 模块的寄存器在外部定义。对于飞思卡尔的启动实用程序“mqxboot”,在 Cortex-A5 内核上运行的 mcc 内核模块中的启动实现可确保相应地设置此寄存器。用户需要将入口点作为参数传递给“mqxboot”。注意:地址需要将位 0 设置为 1,以告诉 CPU 目标是 Thumb 代码(另请参阅参考手册的“运行辅助内核”一章)。
例如,要将固件 demo.bin 加载到 SRAM 并在辅助内核上启动它,可以在主内核上运行的 Linux 上使用 mqxboot:
mqxboot
mqxboot demo.bin 0x3f000000 0x1f000401
加载地址需要可从 Cortex-A5 访问。在本例中,这是 SRAM 的开始。但是,入口点地址是仅适用于 Cortex-M4 内核的代码总线别名。
时钟
由于 Cortex-M4 在源自 Cortex-A5 内核时钟的系统时钟上运行,因此从 Cortex-M4 侧更改时钟并不是一个好主意。然而,为了计算时序,读取时钟寄存器以获得当前速度是必要的。在libopencm3中,计算逻辑在lib/vf6xx/ccm.c下实现。主要时钟是 ARM 内核时钟 (ccm_core_clk)、平台总线时钟(也是 Cortex-M4 内核时钟 (ccm_platform_bus_clk) 以及 IPS(外设)时钟 (ccm_ipg_bus_clk))。
沟通
另一方面是与运行在 Cortex-A5 上的主操作系统进行通信的通信基础设施。libopencm3 实现目前不支持通信。可能最简单的通信实现是定义一个可以从双方访问的共享内存区域(考虑使用使用独占加载/存储指令 LDREX/STREX 的同步机制)。更复杂一点的是 MQX RTOS 的多核通信 (MCC) 组件的实现。该组件利用硬件信号量模块 (SEMA4) 以及四个 CPU 到 CPU 中断之一在有新消息可用时通知另一个 CPU。可以下载最近的 MQX 版本(4.0.2 及更高版本)以获取 MCC 的源代码(验证许可证是否涵盖您的用例)。
结论
在 Vybrid 上移植或实现裸机固件是可能的,而且不是很复杂。毕竟,Vybrid 内部的 Cortex-M4 仍然是执行 ARMv7-M 架构的 Cortex-M4 内核。除了外围驱动程序,链接器文件以及初始设置代码需要一些特殊考虑。
作者:Stefan Agner, Toradex
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !