我有一个为 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 中定义的内容(即,没有额外的投入)。