【问题标题】:How to use external memory on a microcontroller如何在微控制器上使用外部存储器
【发布时间】:2012-03-02 13:18:33
【问题描述】:

过去,我使用 8 位 AVR 和 MSP430 进行了大量工作,其中 RAM 和闪存都直接存储在芯片上。当您编译和下载您的程序时,它有点“正常工作”,您无需担心变量的实际存储位置和方式。

现在我开始了一个项目,我希望能够将一些外部存储器添加到微控制器(如果重要的话,可以使用 TI Stellaris LM3S9D92),但我不完全确定你是如何让你的代码使用外部 RAM。我可以看到您配置外部总线的方式与任何其他外围设备非常相似,但令我困惑的是处理器如何跟踪何时与外部存储器通信以及何时与内部存储器通信。

据我所知,外部 RAM 映射到与内部 SRAM 相同的地址空间(内部从 0x20000000 开始,外部从 0x60000000 开始)。这是否意味着如果我写了这样的东西:

int* x= 0x20000000;
int* y= 0x60000000;

x 和 y 会分别指向内部和外部 RAM 的前 4 个字节(假设为 32 位整数)吗?如果是这样,如果我做了这样的事情会怎样:

int x[999999999999]; //some super big array that uses all the internal ram
int y[999999999999]; //this would have to be in external ram or it wouldn't fit

我想我需要告诉一些事情关于每种内存类型的边界,还是我都错了,硬件自己解决了?链接器脚本是否处理此问题?我知道它们与内存映射有关,但我不知道究竟是什么。在阅读了如何设置 ARM 交叉编译器之后,我觉得像 winavr (avr-gcc) 这样的东西在幕后为我做了很多这样的事情,所以我不必处理它。

抱歉有点啰嗦,但如果有人能告诉我我是否在这些东西上走在正确的轨道上,我将不胜感激。

更新

对于任何未来的读者,我在谷歌搜索 http://www.bravegnu.org/gnu-eprog/index.html 几个小时后发现了这一点。结合这里的答案,它对我帮助很大。

【问题讨论】:

标签: c microcontroller


【解决方案1】:

通常这正是它的工作原理。您必须正确设置硬件和/或硬件可能已经在固定地址硬编码了一些东西。

你可以问同样的问题,硬件怎么知道当我写一个字节到地址 0x21000010(我刚刚编的)那是 uart 发送保持寄存器并且写意味着我想发送一个字节UART?答案是因为它以这种方式在逻辑中硬编码。或者逻辑可能有一个偏移量,uart 可能能够将它移动到其他一些控制寄存器内容加上 0x10。将控制寄存器(它本身有一些硬编码地址)从 0x21000000 更改为 0x90000000,然后写入 0x90000010,另一个字节从 uart 输出。

我将不得不查看那个特定的部分,但如果它确实支持外部存储器,那么理论上你所要做的就是知道处理器地址空间中的哪些地址映射到该外部存储器并且读取和写入将导致外部存储器访问。

基于 Intel 的计算机,PC,倾向于喜欢一个大的平面地址空间,在你的 Linux 机器上使用 lspci 命令(如果你有的话)或者在 windows 或 mac 上使用其他命令,你会发现你的视频卡已经获得了一块地址空间。如果您通过了 cpu/操作系统的保护并写入该空间中的地址,它将直接从处理器通过 pcie 控制器进入视频卡,从而造成严重破坏或可能只是改变颜色像素。你已经用你的 avr 和 msp430s 处理了这个问题。地址空间中的一些地址是闪存,一些是 ram,cpu 内核外部有一些逻辑,它查看 cpu 内核地址总线并决定将访问发送到哪里。到目前为止,flash bank 和 ram bank 和逻辑都是自包含在芯片边界内的,这并没有超出逻辑响应地址的范围,并由此创建一个外部存储器周期,当它是完成或结果在读取时返回,它完成了内部存储器循环,然后您继续下一件事情。

这有什么意义吗?还是我让情况变得更糟了?

【讨论】:

  • 这对我来说很有意义,我仍然不太明白的一件事:我需要在 C 中手动分配外部/内部 ram 中的变量吗?我不希望堆栈足够聪明以跳过内部/外部边界,但如果我声明大量全局变量怎么办?有没有办法说“如果适合,就把这个变量放在内部 ram 中,否则,让它活在外部 ram 上”?
  • 这类问题不是外存特有的,不管你在什么平台上,你都要管理好你的内存。您可能需要接管链接器的控制权以将您想要放置的任何内容放入该内存中。在嵌入式系统上运行,如果您使用堆栈和堆来确保不会与某些东西发生冲突,则必须管理堆栈和堆。大量的全局变量是一种安全的方法,但不一定是内存效率的。
  • 对于 gnu/gcc 工具,有一个链接器脚本,要么是你编写的,要么是埋在编译器中的某个地方,然后根据你选择的处理器或系统类型选择一个脚本。你可以覆盖它并使用你自己的。 gnu/gcc 链接器脚本可配置且功能强大,以至于创建和使用起来很痛苦,您可以手动调整每个文件的位置,甚至可以调整到函数或变量。通常你希望你的堆栈在最快的内存中。
  • 我认为链接器脚本是我之前卡住的地方。我很确定我现在明白如何将所有变量放入内部 ram 或外部 ram 但我想知道是否有办法让 .data 部分从 0x100-0x200 开始,然后跳到0x400-0x800(只是编数字)。我发现的一切似乎都表明它需要是连续的。
  • @nightrain:通常这种工作方式是您为堆栈分配其中一个内存的一部分。堆栈必须是连续的。如果您可以更改内存映射,以便您可以放置​​外部内存,使其与内部 ram 相邻(例如 internal=0x1000-0x1fff,external=0x2000-0x2fff),那么您可以将所有内存分配给您的堆栈(0x1000-0x2fff)。 CPU 知道哪些地址映射到哪些内存,但代码不需要知道(也不会知道)哪些变量将存储在哪个内存中。
【解决方案2】:

您可以使用保留字 register 向编译器建议它将该变量放入内部存储器位置: 注册 int iInside; 谨慎使用;编译器知道有多少字节的寄存器存储可用,当所有可用空间都用完时,这无关紧要。

仅将寄存器变量用于将非常、非常频繁地使用的事物,例如计数器。

【讨论】:

  • 'internal RAM' 并不意味着 CPU 寄存器。 OP 还想做相反的事情:使用外部存储器(与 µC 分开的芯片)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多