管理内存和延迟注意事项
重要
这是 Azure Sphere(旧版)文档。 Azure Sphere(旧版)将于 2027 年 9 月 27 日停用,用户此时必须迁移到 Azure Sphere(集成)。 使用位于 TOC 上方的版本选择器查看 Azure Sphere(集成)文档。
本主题介绍在 MT3620 芯片上运行的实时应用程序的基本内存使用和延迟注意事项。
注意
有关内存配置或 DMA 的更多详细信息,请参阅 MediaTek 发布的 MT3620 数据表;如果问题仍然存在,可以通过电子邮件Azure.Sphere@avnet.com从 Avnet 请求“MT3620 M4 数据表”。
实时内核上的内存布局
下表总结了实时内核上可用的内存:
内存类型 | 基址 |
---|---|
TCM | 0x00100000 |
XIP 闪存 | 0x10000000 |
SYSRAM | 0x22000000 |
每个实时内核都有192 KB 的紧密耦合内存 (TCM),它映射到从 0x00100000 开始的三个 64 KB 的存储体中。 TCM 访问速度很快,但只有实时内核才能访问内存。 TCM 不能与高级应用程序共享,也不能与在不同核心上运行的支持实时的应用程序 (RTApp) 共享。
每个实时内核还有 64 KB 的 SYSRAM,其从 0x22000000 开始映射。 DMA 控制器也可将 SYSRAM 作为目标,以便外设可以访问它。 从实时核心访问 SYSRAM 比访问 TCM 慢。 与 TCM 一样,SYSRAM 无法与其他应用程序共享。
就地执行 (XIP) 闪存与高级应用程序共享。 每个内核都可在地址 0x10000000 看到反映闪存的 XIP 映射的窗口。 如果应用程序的 ELF 文件包含具有以下属性的段,则 OS 会在启动应用程序之前配置 XIP 映射:
- 加载地址(在程序头的 VirtAddr 列中指定)等于 0x10000000
- 应用程序的 ELF 文件可容纳的文件偏移量和大小(在程序头的 FileSiz 和 MemSiz 字段中指定)
如果应用程序的 ELF 文件中存在具有这些属性的程序头,则会设置 XIP 窗口的位置,以便该段在 0x10000000 可见。 该文件只能有一个 XIP 段,并且必须指向 0x10000000;它不能指定任何其他地址。
ELF 部署
RTApp 映像必须是 ELF 文件。 ELF 映像包装在 Azure Sphere 映像包中,并作为应用程序进行部署。 为了加载应用程序,Azure Sphere OS 会启动在实时内核上运行的 ELF 加载程序。 加载程序处理 ELF 文件中的每个 LOAD 段,并将其加载到程序头中虚拟地址指示的内存类型中。
使用 arm-none-eabi-readelf.exe -l
(小写的 L,GNU Arm 嵌入式工具链的一部分)显示应用程序的程序头。 程序头中显示的虚拟地址列 (VirtAddr) 指示 LOAD 段的目标地址。 这并不意味着处理器本身会执行任何其他转换。 Azure Sphere ELF 加载程序不使用物理地址 (PhysAddr)。
请看以下示例:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000098 0x00100000 0x00100000 0x00000 0x00e78 RW 0x8
LOAD 0x0000a0 0x10000000 0x10000000 0x03078 0x03078 RWE 0x10
LOAD 0x003118 0x00100e78 0x10003078 0x000f0 0x000f0 RW 0x4
0x00100000 处的段将紧密耦合内存 (TCM) 作为目标。 加载程序从映像包将数据复制到 RAM 中,或者根据需要将 TCM 初始化为零。
0x10000000 处的段映射到内核的 XIP 窗口中。 在运行时,对
0x10000000 + offset
的访问在其离开实时内核时转换为<address-of-XIP-segment-in-flash> + offset
。虚拟地址 0x00100e78 处的数据段映射到 TCM 中。
ELF 运行时注意事项
ELF 加载程序执行原始二进制文件(或链式引导加载程序)在启动时将执行的一些任务。 具体而言,它根据程序头将 BSS (block-started-by-symbol) 数据初始化为零,并将经过初始化但可变的数据从只读闪存复制到 RAM 中。 应用程序随后启动并运行自己的初始化函数。 在大多数情况下,不需要对现有应用程序进行更改。 不必要将应用程序中的 BSS 数据归零,但此操作没有负面影响,因为加载程序已经将内存归零。
在某些情况下,将可变数据从闪存复制到 RAM 可能会导致问题,具体取决于 ELF 文件布局方式。ELF 加载程序按顺序处理程序标头,而无需更改文件中段的整体布局。 随后,它不仅将 XIP 段本身映射到 0x10000000,还会按顺序映射任何后续段。 如果 ELF 文件中的段按顺序排列而没有任何对齐或间隙,则 OS 启动代码可以使用指针运算来查找数据段的起点。 但是,如果 ELF 文件具有不同的布局,则指针运算不会生成正确的地址,因此应用程序启动代码不得尝试复制数据部分。 如果应用程序或 RTOS 使用链式引导加载程序或需要在归零 BSS 或初始化可变数据之前设置堆栈 Canary,这可能会导致问题。
内存目标
可通过编辑应用程序的 linker.ld 脚本来在 TCM、XIP 闪存或 SYSRAM 中将代码作为目标。 Azure Sphere 示例应用程序从 TCM 运行,但每个应用程序的 linker.ld 脚本文件描述的都是如何将 XIP 闪存作为目标。 如以下示例所示,可以通过将 CODE_REGION 和 RODATA_REGION 的别名设置为 FLASH(而不是默认的 TCM)来更改要在 XIP 上运行的示例:
REGION_ALIAS("CODE_REGION", FLASH);
REGION_ALIAS("RODATA_REGION", FLASH);
若要确定编译的应用程序是从 TCM 还是 XIP 闪存运行,请使用 arm-none-eabi-readelf.exe
(GNU Arm 嵌入式工具链的一部分)。 在 .out 文件上运行它,该文件与映像包位于同一目录中,并指定 -l
(小写的 L)标志以查看代码和只读数据的放置位置。 闪存中的代码和只读数据在地址 0x10000000 进行加载;TCM 中的代码和数据在 TCM 区域进行加载。
以下示例显示从闪存运行的应用程序。
arm-none-eabi-readelf.exe -l UART_RTApp_MT3620_BareMetal.out
Elf file type is EXEC (Executable file)
Entry point 0x10000000
There are 2 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000074 0x00100000 0x00100000 0x00284 0x003c0 RW 0x4
LOAD 0x000300 0x10000000 0x10000000 0x013b9 0x013b9 R E 0x10
Section to Segment mapping:
Segment Sections...
00 .data .bss
01 .text .rodata
矢量表位置
在 ARMv7-M 设备上,矢量表必须在至少为 128 字节且不小于表大小的二次幂边界上对齐,如 ARMv7-M 架构参考手册中所述。 MT3620 上的每个 I/O RT 核心都支持 100 个外部中断。 因此,包括堆栈指针和 15 个标准异常在内,该表有 116 个 4 字节条目,总大小为 464 字节,向上舍入为 512 字节。
当代码从 XIP 闪存运行时,矢量表必须放置在 0x10000000 处,并且必须在 ELF 文件中的 32 字节边界上对齐。 当代码不是从 XIP 闪存运行时,该表通常放置在 TCM0 的开头,即 0x100000。 在这两种情况下,为了确保该表的虚拟地址正确对齐,将矢量表放在一个专用段中,并将 CODE_REGION 设置为适当的地址。
Azure Sphere 示例存储库中的 MT3620 BareMetal 示例演示了如何执行此操作。 main.c 中的矢量表声明将其 section
属性设置为 .vector_table
。 链接器脚本将 CODE_REGION 的别名设为以 TCM 或 XIP 开头,ALIGN 属性设置 ELF 文件中文本部分的对齐方式,如下所示:
SECTIONS
{
.text : ALIGN(32) {
KEEP(*(.vector_table))
*(.text)
} >CODE_REGION
...
}
实时和延迟注意事项
即使不相互通信,RTApp 和高级应用程序也会争用闪存访问权限。 因此,从 XIP 闪存运行的 RTApp 可能会遇到不可预测的高延迟。 写入闪存(例如在更新期间)可能涉及高达数百毫秒的延迟峰值。 根据应用程序的要求,可以通过多种方式对此进行管理:
将所有代码和数据放入 TCM。 从 TCM 运行的代码不容易受到闪存争用的影响。
将代码拆分为关键部分和非关键部分,并从闪存运行非关键代码。 其他代码访问闪存时,应不必运行具有实时要求的代码,例如监视程序计时器。 内存目标介绍了如何将 XIP 闪存(而不是 TCM)作为目标。
使用缓存。 应用程序可以使用最低 32 KB 的 TCM 作为 XIP 缓存。 在缓存失误的情况下,此方法不提供硬实时保证,但可提高典型性能,而无需将所有代码都移动到 RAM 中。 有关 XIP 缓存配置的信息,请参阅“MT3620 M4 数据表”。