AVR:从头开始创建和理解最少的启动代码和链接器脚本

问题描述 投票:0回答:1

我希望我的问题变得足够简洁。 我目前正在研究执行 main() 之前微控制器中实际发生的情况。我对 Cortex M4 STM 编程有一些经验,也研究过链接器文件一两次,但我的目标是实际为新系统“从头开始”编写最少必要的启动(C 或汇编程序)和链接器脚本我。这意味着,仅使用可用的文档。因此,我选择了Attiny 2313。我还没有尝试刷新代码,只是交叉编译和链接。之后,我会尝试创建一个makefile。我的操作系统是 Ubuntu。

我尝试使用的工具链是avr-gcc,用于检查的objdump和用于链接的GNU LD

我认为从文档中,我弄清楚了必须做什么。微控制器的数据表指出,每次重置时,都必须完成以下操作。

  1. 将堆栈指针初始化到堆栈末尾 = SRAM 末尾(地址 0x3D)
  2. 初始化SREG状态寄存器(地址0x3F)
  3. 定义复位向量(在Flash中的0x0000处?)
  4. 定义向量表的其余部分(从0x0001到0x0012)
  5. 定义熔丝位CKEL、SUT和BODLEVEL
  6. 在链接器文件中定义内存部分

现在,我想我真的不知道如何从启动代码开始。编译器是否已经知道 CKEL、SUT 和 SREG 等符号?我必须自己申报吗?

另外,我还有两个有关链接器文件的更详细的问题:

  1. 我发现对于avr,创建了各种内存部分:.text、.data、.bss、.eeprom、.noinit、.initN、.finiN、.note.gnu.avr.deviceinfo。我是否应该预期这些内存部分中的任何一个正在使用中?或者甚至强制所有部分都在使用中?
  2. 在 STM 的示例链接器脚本中,我找到了这个内存映射部分:
.text :
{
  . = ALIGN(4);
  *(.text)
  *(.text*)
  . = ALIGN(4);
} >FLASH

*(.text) 和 *(.text*) 有什么区别?

此时,我真的很难开始,因为我不清楚会发生什么。另外,我还不知道任何汇编程序,也几乎不知道链接器命令语言。

assembly startup ld avr avr-gcc
1个回答
0
投票

AVR 有许多独特的设计决策,这使得用汇编程序编写代码非常有趣。 AVR cpu 的核心有两件事:获取指令并执行它们。当器件启动时,程序计数器指向地址 0x0000(复位向量)。如果没有 jmp/rjmp 或其他分支指令,它将获取地址 0x0001 中的下一条指令并执行它。

首先,我会专注于学习指令集,尤其是与内存相关的指令(lds、sts、in、out、ld、st、ldi),不要考虑中断向量或任何外设,因为它很快就会变得难以承受。之后尝试用其他语言来模拟你所知道的东西,比如定义一个静态数组并用从 0 开始的数字填充它,这样简单的东西,这样你就能真正成功地编译一些程序并具有调试的能力在 simulstor 中(也包含在 microchip studio 中)

一般来说,您需要关注的概念是(从最重要到最不重要):

  1. 算术指令
  2. 缓冲(JMP/RJMP/BREQ/BRNE 等)
  3. 易失性内存指令(上面列出)
  4. 指针(X、Y、Z 及其与 ld/st 指令的用法)
  5. 堆栈指针(PUSH/POP指令)
  6. 例程(CALL/RALL/RET 指令)
  7. 中断和中断例程(RETI指令和向量)

还有很多概念需要理解。我还建议观看一些 YouTube 视频,获取可以编译和调试的简单代码示例,有人会一步步指导您完成其中的一些内容。

© www.soinside.com 2019 - 2024. All rights reserved.