管理内存和延迟注意事项

本主题介绍在 MT3620 芯片上运行的实时应用程序的基本内存使用情况和延迟注意事项。

注意

有关内存配置或 DMA 的更多详细信息,请参阅 MediaTek 发布的 MT3620 数据表;如果问题仍然存在,你可以通过电子邮件 Azure.Sphere@avnet.com从 Avnet 请求“MT3620 M4 数据表”。

实时核心上的内存布局

下表汇总了实时核心上可用的内存:

内存类型 基址
中医 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
  • 程序标头中的 FileSiz 和 MemSiz 字段中指定的文件偏移量和大小 () 适合应用程序的 ELF 文件

如果应用程序的 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 Embedded Toolchain 的一部分)显示应用程序的程序标头。 标头中显示的虚拟地址列 (VirtAddr) 指示负载段的目标地址。 这并不意味着处理器本身会执行任何其他转换。 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) 数据 (按符号 (块初始化,并将初始化但可变的数据从只读闪存复制到 RAM 中。 然后,应用程序启动并运行自己的初始化函数。 在大多数情况下,不需要更改现有应用程序。 将应用程序中的 BSS 数据归零是不必要的,但无害,因为加载程序已将内存归零。

在某些情况下,根据 ELF 文件的布局方式,将可变数据从闪存复制到 RAM 可能会导致问题。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
...
}

实时和延迟注意事项

RTApps 和高级应用程序争相访问闪存,即使它们不相互通信。 因此,从 XIP 闪存运行的 RTApp 可能会遇到高且不可预知的延迟。 写入闪存(例如更新期间)可能涉及高达数百毫秒的延迟峰值。 根据应用程序的要求,可以通过多种方式进行管理:

  • 将所有代码和数据放在 TCM 中。 从 TCM 运行的代码不容易受到闪存争用。

  • 将代码拆分为关键和非关键部分,并从 flash 运行非关键代码。 具有实时要求的代码(例如监视器计时器)不应在其他代码访问闪存时运行。 内存目标 描述如何面向 XIP 闪存而不是 TCM。

  • 使用缓存。 应用程序可以使用最低 32KB 的 TCM 作为 XIP 缓存。 此方法不会在缓存未命中提供硬实时保证,但可提高典型性能,而无需将所有代码移动到 RAM 中。 有关 XIP 缓存配置的信息,请参阅“MT3620 M4 数据表”。