Getting an initializer element is not constant
compile error when using avr-gcc. Is there any good way to do what I'm trying to do here?
file.c
#include "file.h"
#include "../notes/octave_two_notes.h"
//F2 is defined in octave_two_notes.h
//This is the file giving me the compilation error
struct Song_Note F2_500ms = { .note = F2, .duration_ms = 500 };
song_note.h
#include "note.h"
struct Song_Note {
struct Note note;
uint16_t duration_ms;
} Song_Note;
octave_two_notes.h
extern struct Note F2;
octave_two_notes.c
#define CALC_CTC_FREQ(clock_freq, prescaler, note_freq_hz) ( (uint32_t) clock_freq / ( (uint16_t) note_freq_hz * (uint16_t) prescaler * 2) - 1)
struct Note F2 = {.freq_hz = 87, .ocr_val = CALC_CTC_FREQ(16000000, 8, 87)};
note.h
#include <stdint.h>
struct Note {
uint16_t freq_hz;
uint16_t ocr_val;
} Note;
First of all, these variables should all be declared as const
. Mainly because you want them in flash, not in RAM.
const
will unfortunately not solve the main problem though, because the C language doesn't even regard const
-qualified variables as constant expressions. And variables declared at file scope have "static storage duration" and must therefore be initialized with a constant expression.
The only solution C provides is pretty much to declare the initializer list as an inelegant macro, in this case it has to be inside a header file:
// header file
#define CALC_CTC_FREQ ...
#define F2_INIT \
{ \
.freq_hz = 87, \
.ocr_val = CALC_CTC_FREQ(16000000, 8, 87) \
}
and in the .c file, use that macro:
// c file
const struct Note F2 = F2_INIT;
and then in a .c file elsewhere:
const struct Song_Note F2_500ms = { .note = F2_INIT, .duration_ms = 500 };
Note that the CALC_CTC_FREQ
part should be fine, everything inside it is a constant expression and it is evaluated at compile-time.