Я работаю над встроенной системой, где некоторые данные калибровки хранятся во флэш-памяти. Данные калибровки хранятся в структуре, которая помещается в специальный раздел, который компоновщик знает для помещения во флэш-память:
struct data_block {
calibration_data mData;
uint16_t mCheckSum;
};
//Define to compile the fixed flash location for image data
const data_block __attribute__((section (".caldata"))) gCalibrationData{};
, где calibration_data
- другая структура POD, которая содержит фактические значения.
Проблема в том, что если я сейчас просто напишу следующее:
const data_block data{gCalibrationData};
if (CheckSum(&(data.mData)) == data.mCheckSum) {
//do stuff
} else {
//Error
}
это всегда относится к ветке ошибок, даже если фактическая контрольная сумма во флэш-памяти абсолютно верна (запись немного по-другому заставляет его работать, см. Ниже).
Это, конечно, понятно: компилятор видит глобальный объект const, который инициализирован по умолчанию, поэтому он знает все значения, поэтому я предполагаю, что он фактически оптимизирует весь if
(если я отлаживаю данные printf через uint16_t *
, я на самом деле получаю правильные значения).
Я думаю, что было бы правильно определить
const volatile data_block __attribute__((section (".caldata"))) gCalibrationData{};
Однако теперь у меня проблема в том, что я не могу назначить энергонезависимую структуру для энергонезависимой, то есть const data{gCalibrationData};
не компилируется. Та же проблема также появляется, если я пытаюсь получить доступ через const volatile data_block *
.
Есть как минимум два или три способа сделать эту работу, и мне не нравится ни один из них:
- удалить квалификатор
const
(и volatile
) из gCalibrationData
. Тем не менее, это что-то вроде хака, основанного на том, что компилятор недостаточно умен, чтобы гарантировать, что gCalibrationData никогда не затрагивается в моей программе, и, с другой стороны, я хотел бы сохранить квалификатор const, так как пытается писать в gCalibrationData по присваиванию это серьезная ошибка.
- доступ
gCalibrationData
через const gCalibrationData * volatile pData
(да, изменчивый - именно то, что я имею в виду). Доступ через указатель, который является изменчивым, заставляет компилятор фактически загружать данные. Опять же, это похоже на взлом, поскольку сам указатель, конечно, не является изменчивым.
- дают
data_block
и calibration_data
оператор присваивания, принимающий const volatile &
, и присваивают им поле за полем. Это кажется правильным с языковой точки зрения, но тогда, когда меняется calibration_data
, мне нужно вручную редактировать оператор присваивания. Несоблюдение этого требования приведет к трудно обнаруживаемым ошибкам.
Мой вопрос: Как правильно считывать данные калибровки? Моими идеальными критериями были бы:
- сам глобальный объект -
const
, чтобы перехватывать непреднамеренные записи.
- нет неопределенного поведения
- доступ путем присвоения структуры непосредственно другой структуре
- или, по крайней мере, чтобы мне не нужно было присваивать каждую переменную примитивного типа в
calibration_data
, см. Вариант 3. выше
- бонусных баллов за безопасность потоков, хотя в моем конкретном случае флэш-память читает или записывает только один поток (все остальные «потоки» являются прерываниями).