Об инициализации структур

У меня для прошивки программа AVRDUDESS. Там есть флаг "Erase flash and EEPROM (-e)". Этот флаг сброшен.

Фьюз включи и всё.

…вопрос не в том, что можно, а что нельзя, а какие опции стояли у ТС, когда он получил свои ошибки

На самом деле, вместо кучи обсуждений, ТС давно бы мог сделать то что я писал в #65 п2… и все было бы понятно

1 лайк

У AVR, насколько я помню, установка фьюза как раз и отмечается сброшенной галкой

Вот часть командной строки. Если флаг установлен, то в строке появляется -e
-c usbasp -p m328pb -P usb -b 115200 -B 0.5 -e -U flash:w:"C:\#ARDUINO\Sp\Sp.ino.with_bootloader.standard.hex":a -U eeprom:r:"C:\#ARDUINO\Sp\eeprom.eep":i

Отвлекусь “чуть- чуть”. Прошиваю hex - файл с загрузчиком потому, что должна быть возможность перезагрузки МК. В скетче есть такая строка: if (flag == true) wdt_reset(); Некоторым образом через COM - порт делаю: flag=false МК перезагржается. Если hex - файл без загрузчика, то происходит зацикливание.

БутЛуп (то самое зацикливание) давно уже преодолено и без загрузчика. Поищите в гугле или спросите Дракулу, он знает

Вот честно, рассуждаете про сброшенный флаг и при этом приводите строчку, где есть ЯВНАЯ запись ЕЕПРОМ в файл…
Вы намеренно мозг форуму выносите ?

Толчем воду в ступе. Третий раз повторяю - сделайте тест, что в ЕЕПРОМе и не отнимайте у людей время впустую…

Я, когда логика позволяет, пользуюсь еще одним методом. В структуре данных присутствует подпись (сигнатура корректности). В самом простом случае можно последним полем структуры записывать уникальное число. Если при старте программы считано это число, то все остальные данные в структуре тоже предполагаются валидными. Если нет, то в структуру присваиваются умолчательные значения (и можно ее записать в еепром).

2 лайка

на самом деле я бы сказал что это “не еще один” метод, а самый первый и очевидный в этом случае :slight_smile:

Не, есть посложнее, но они не всегда стоят усилий. Чуть сложнее, но надежнее, помимо сигнатуры (которая может совпасть с мусором) еще считать контрольную сумму. И хранить данные (для настроек это актуально) в журналируемом формате, т.е. циклический буфер из нескольких идентичных по формату стурктур, из которых при чтении выбирается самая свежая и корректно подписанная, а запись идет в хвост буфера. Даже если произошел сбой, можно запуститься с предыдущими (а когда надо и с еще более ранними данными).

Обычно кучу случаев закрывает собой реализация с двумя копиями, если не требуется глубокий откат по времени. Ну и как-никак экономия циклов перезаписи, при грамотном сегментировании по стираемым страницам.

То есть установить фьюз - мега сложно?

Отнюдь. (Это “отнюдь” касается в первую очередь последних 4-х слов цитаты)
Через выравнивание это можно реализовать на любом языке, а вот через ООП - только на языках, поддерживающих ООП. (неожиданно, правда?)

То есть как всегда: начинать нужно с проектирования: сначала определиться, для чего будет использоваться структура: будет ли она передаваться по линиям связи, будет ли она храниться во внешних файлах, возможна ли ее обработка на устройствах с различной архитектурой, и только потом начинать конструировать эту структуру.

Хотя, надо сказать, простая привычка размещать данные внутри структуры изначально выровненными на естественную границу, еще никому не навредила.

Не понял эту фразу. Не сложно будет «развернуть» по понятнее?

Это значит, однобайтовые данные выравниваются на границу байта, двухбайтовые - на четную границу, четырехбайтовые - на границу 4-х байт и т.д.
Ну как-то так:

struct MyStruct {
  double a;
  float b;
  int32_t c;
  int16_t d;
  byte e;
  byte f;
  byte g;
  byte reserv1; // а вот это - тоже привычка - делать длину структуры кратной 4-м байтам
  byte reserv2; 
  byte reserv3; 
} __attribute__((packed));
1 лайк

Ради интереса - возьми свою структуру с байтами и булами и посмотри, какой у нее sizeof(). Если sizeof() больше, чем то, что ты написал (вангую, что будет больше) - в этом и причина.

1 лайк

В том-то и дело, что он где-то больше, а где-то – нет. Зависит от всевозможных опций. Если бы он везде и всегда был одинаков (уж больше или нет, как получится) то и проблемы бы не было.

1 лайк

Встречал, кстати, мнение, что packed структуры занимают меньше места и, таким образом, экономят память. Ну, может data ram и экономят, а вот instruction ram распухает.

Я стараюсь везде использовать или битовые поля от uint32_t или сам uint32_t. Самые быстрые операции - с типами, которые являются “натуральными“ для CPU: для 32-х битовых процессоров, соответственно, int или unsigned int (unsigned int как правило - самый быстрый тип данных). Для меня было неприятным откровением узнать, что на ESP32 bool - это char. Тоже мне, сэкономили память..

Но вообще говоря, возвращаясь к теме топика - сама идея хранить структуры в еепром - не самая лучшая. Лучше хранить поля и читать их в структуру. Так хотя бы будет бинарная совместимость между новыми версиями прошивки и старыми версиями ЕЕПРОМ данных. Обновит, например, пользователь вашего устройства прошивку.. а в новой прошивке добавился один мембер в вашу структуру, а другой - пропал. Все, приплыли, считать ЕЕПРОМ в новую структуру уже не выйдет.

1 лайк

Частично касаясь обсуждаемой темы. Для поддержки разметки формата хранения данных и не привязываясь к их размещению в структуре давным давно сделал примерно такое и до сих пор хватает. Можно оптимизировать, добавлять сахарку (чтобы не повторяться с именами в макросах), но тут показана сама идея.

struct t_DeviceSettings
{
  int               iIdent;
  t_KeyboardValues  KeyboardValues;
  time_t            tmLastEvent;
  unsigned long     ulPeriodSec;
  unsigned long     ulDurationSec;
  float             fFlowScale;
  unsigned long     ulWaterDoseMl;
};

#define OFFSET_SETTINGS(MEMBER) (int)(&((struct t_DeviceSettings*)0)->MEMBER)

void WriteBuffer(void *pBuffer, const int iAddr, const int iSize);
void ReadBuffer(void *pBuffer, const int iAddr, const int iSize);

...
float fFlowScaleWrite = 1.0;
WriteBuffer(&fFlowScaleWrite, OFFSET_SETTINGS(fFlowScale), sizeof(fFlowScaleWrite));

Тут прием в вычислении смещения переменной в структуре, чтобы работать только с ней (макрос). Все остальное фигня.

1 лайк

Скажите спасибо, что не unsigned int. Язык это вполне допускает:

И, далее …

И, да, кстати, а чего Вы хотели? Чтобы тип bool занимал меньше байта? Так это противоречит фундаментальным основам языка. Вы хотите, чтобы компилятор нарушал правила языка? Или чего?