I have a simple C program written for an ATmega168:
#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();
}
My 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)
When I compile this (both directly from command line with avr-gcc and in CLion through my CMakeLists file), the compiler (linker?) seems to be overwriting the interrupt vector table with my main function. When I use objdump on the .elf file to generate the disassembly of the code, I get:
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
According to the datasheet for the ATmega168, this is perfectly ok in a scenario where there are no interrupts:
"If the program never enables an interrupt source, the Interrupt Vectors are not used, and regular program code can be placed at these locations."
but since I have interrupts, I'm expecting the disassembly to look something like:
...
0x0000 jmp main ; RESET
...
0x001A jmp __vector_13 ; TIM1_OVF_vect
...
Is there something missing in my code or compilation that is causing the compiler to incorrectly think I'm not using interrupts, or am I completely misinterpreting my disassembly output?
Edit: Building with CMAKE_VERBOSE_MAKEFILE ON, I get the following for build and link:
...\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
which is exactly what's defined in the CMakeLists.txt (ie, nothing extra being thrown in).
I did some experiments and came to this conclusion:
You don't get a vector table because you don't provide one. Apparently the option -nostdlib
excludes that part (of the library?) that implements the table.
So the first error is the usage of said option.
But this is not enough, as the linker does not know the MCU, and so which table to use. (Or which part of the library to include.)
So the second error is to not provide the appropriate option -mmcu=atmega168
.
With this linker call Now the vector table is built:
avr-gcc -mmcu=atmega168 -Wall -Wextra -g main.c.obj -o clion_avr_c_demo
Notes: