0

我有一个为 ATmega168 编写的简单 C 程序:

#include "avr/io.h"
#include "avr/interrupt.h"

volatile uint8_t intrs;

int main(void){
   TCCR1B |= _BV(CS12) | _BV(CS10); \\ set clock source
   TIMSDK1 |= _BV(TOIE1); \\ Enable overflow interrupts
   ... // initialize timer and intrs
   sei();  \\ enable global interrupts
   while(1){}
}

ISR(TIMER1_OVF_vect){
    //do stuff
    reti();
}

我的 CMakeLists:

cmake_minimum_required(VERSION 3.16)
set(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdlib -Wall -Wextra")

set(TARGET_CPU ATmega168)

project(clion_avr_c_demo C)

include(CMakeVerifyCompiler.txt)

add_compile_definitions("__AVR_${TARGET_CPU}__")

add_link_options(-Wl,--print-memory-usage)

add_executable(${PROJECT_NAME} src/main.c)

当我编译它时(直接从命令行使用 avr-gcc 和在 CLion 中通过我的 CMakeLists 文件),编译器(链接器?)似乎正在用我的 main 函数覆盖中断向量表。当我在 .elf 文件上使用 objdump 生成代码的反汇编时,我得到:

clion_avr_c_demo:     file format elf32-avr

Disassembly of section .text:

00000000 <main>:
   0:   cf 93           push    r28
   2:   df 93           push    r29
   4:   cd b7           in  r28, 0x3d   ; 61
   6:   de b7           in  r29, 0x3e   ; 62
   ... ; clearly the disassembled main function
00000054 <__vector_13>:
  54:   1f 92           push    r1
  56:   0f 92           push    r0
  ... ; clearly the disassembled ISR

根据 ATmega168 的数据表,在没有中断的情况下这是完全可以的:

“如果程序从不启用中断源,则不使用中断向量,并且可以将常规程序代码放置在这些位置。”

但由于我有中断,我希望反汇编看起来像:

...
0x0000      jmp    main        ; RESET
...
0x001A      jmp    __vector_13 ; TIM1_OVF_vect
...

我的代码或编译中是否缺少某些内容导致编译器错误地认为我没有使用中断,或者我完全误解了我的反汇编输出?

编辑:使用 CMAKE_VERBOSE_MAKEFILE 进行构建,我得到以下构建和链接:

...\avr-gcc.exe -D__AVR_ATmega168__ -nostdlib -Wall -Wextra -g -o ...\main.c.obj -c ...\main.c
...\avr-gcc.exe -nostdlib -Wall -Wextra -g -Wl,--print-memory-usage .../main.c.obj -o clion_avr_c_demo

这正是 CMakeLists.txt 中定义的内容(即,没有额外的投入)。

4

1 回答 1

2

我做了一些实验,得出了这个结论:

你没有得到一个向量表,因为你没有提供一个。显然,该选项-nostdlib不包括实现表的那部分(库的?)。

所以第一个错误是使用了上述选项。

但这还不够,因为链接器不知道 MCU,也不知道要使用哪个表。(或者要包含库的哪个部分。)

所以第二个错误是没有提供适当的选项-mmcu=atmega168

使用此链接器调用现在构建了向量表:

avr-gcc -mmcu=atmega168 -Wall -Wextra -g main.c.obj -o clion_avr_c_demo

笔记:

  • 我没有尝试如何提供自己的向量表。这绝对有效。
  • 通过使用所述选项,您还可以排除启动代码。此启动代码是标准做出的承诺,例如清除包含静态变量的 BSS,这些静态变量显式或隐式初始化为零。请注意 DATA 部分。
  • 我没有尝试如何提供自己的启动代码。这绝对有效。
  • 如果您想避免使用标准库的功能,请不要使用它们。如果你想确保没有链接,让链接器生成一个交叉引用并检查它。
于 2022-01-09T15:28:15.347 回答