Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Инициализация структуры во Flash
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
pokk
Добрый день , подскажите как можно продублировать инициализированную структуры во flash.
Дело в том, что понадобилось сохранять настройки программы в flash, но для зашиты их решил сделать несколько дубликатов.
Делаю это примерно так:
Код
S_GlobalSettingAllVar DefaultGlobalSettingAllVar={ //Начальные настройки(устанавливаются после нажатия кнопки Reset)
   .NetSetting={
      .mac = {0x00, 0x08, 0xdc, 0xab, 0xc1, 0x11},   //6
      .ip = {192, 168, 1, 4},                     //4
      .sn = {255, 255, 0, 0},
      .gw = {192, 168, 0, 0},
   },
   .Password={"fghfgh"},
}
S_GlobalSettingAllVar GlobalSettingAllVar={ //рабочая структура
   .NetSetting={
      .mac = {0x00, 0x08, 0xdc, 0xab, 0xc1, 0x11},   //6
      .ip = {192, 168, 1, 4},                     //4
      .sn = {255, 255, 0, 0},
      .gw = {192, 168, 0, 0},
   },
   .Password={"fghfgh"},
}

В принципе можно так же сделать и дублирующие структуры, но в этом варианте мне не нравится то что при необходимости поменять значения, то придется менять во всех дублирующих структурах и можно в какой-то ошибиться.
Хотелось бы сделать инициализацию в одной из структур, которая при прошивки разместилась по нескольким адресам.

Как заставить компилятор разместить структуры во flash даже если по коду они не используются?(по коду использую адрес)

Ps. компилятор IAR stm32, но думаю это не сильно принципиально.
ViKo
Скопировать пословно. У меня есть структуры с текущим режимом работы и с новым, полученным с панели управления. Когда отрабатываю заданный режим, копирую новую структуру в текущую. Только у меня энергонезависимая ОЗУ.
jcxz
Цитата(pokk @ May 24 2016, 10:27) *
Дело в том, что понадобилось сохранять настройки программы в flash, но для зашиты их решил сделать несколько дубликатов.

А какой сакральный смысл в нескольких копиях во флешь?
Сергей Борщ
QUOTE (pokk @ May 24 2016, 07:27) *
В принципе можно так же сделать и дублирующие структуры
В ваших структурах есть один большой недостаток - в них нет никакой контрольной суммы, а значит у вас нет критерия для выбора - какая из этих копий содержит правильные данные. Я в своих программах делаю так: в программе хранится один образ настроек "по-умолчанию", в отдельном сегменте для настроек хранятся текущие настройки. В самих исходниках этим текущим настройкам никакое значение не присвоено, этот сегмент даже помечен как незагружаемый, чтобы не забивать настройки заново после каждой перепрошивки. При запуске программа считает контрольную сумму текущих настроек и, если она не совпала, переписывает текущие настройки значениями "по-умолчанию". Вы можете считать контрольную сумму всех копий и копировать в остальные ту, у которой контрольная сумма совпала, но не забудьте каждую копию разместить в своей странице флеша.
pokk
Цитата
А какой сакральный смысл в нескольких копиях во флешь?

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

У меня алгоритм такой.
1) после включении программы происходит копирование одной из структур в ОЗУ.
2) сравнение по байтно 3 массива и если 2 байт из разных копиях верны а третий байт нет то он заменяется из двух совпавшим(структура в ОЗУ).
3) Если был сбой(какой-то из 3х копий не совпал), то перезаписываем все 3 копии восстановленными данными(В ОЗУ)

Таким образом в случае потери одной из копий настроек (после броска питания) она будет восстановлена после перезагрузки.

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




MrYuran
А ещё лучше поставить сбоку FRAM и вообще больше не париться.
Писать что угодно, куда, когда и сколько угодно раз.
Счетчик моточасов, например, ежесекундно переписывать.

А с флешью я нынче работаю так:
есть несколько сегментов, в которых лежат одинаковые копии данных, подписанные CRC.

При считывании проверяется CRC и при несовпадении считывается следующая копия, а испорченная восстанавливается.
При записи происходит проверка целостности.

Если все копии испорчены (не представляю, как такое может случиться) записываются дефолтные данные. Собственно, это происходит при первом включении, когда в инфо сегментах FF..FF
pokk
Цитата
А с флешью я нынче работаю так:
есть несколько сегментов, в которых лежат одинаковые копии данных, подписанные CRC.

Как такое указать компилятору?
MrYuran
Цитата(pokk @ May 24 2016, 09:35) *
По этому надеялся на то что можно выделить секцию под настройки и указать линкекру разместить её в нескольких местах (может написал фигню с секциями и линкером не работал).

#pragma location (емнип), reed IAR Compiler Reference
ViKo
Да, у меня тоже есть CRC в структурах. Если она не верна (проверяется при включении), записываю структуру дефолтными данными. CRC вычисляется и записывается при переносе режимов из новой структуры в старую.
jcxz
Цитата(pokk @ May 24 2016, 12:35) *
1) после включении программы происходит копирование одной из структур в ОЗУ.
2) сравнение по байтно 3 массива и если 2 байт из разных копиях верны а третий байт нет то он заменяется из двух совпавшим(структура в ОЗУ).
3) Если был сбой(какой-то из 3х копий не совпал), то перезаписываем все 3 копии восстановленными данными(В ОЗУ)
Таким образом в случае потери одной из копий настроек (после броска питания) она будет восстановлена после перезагрузки.

Если был какой-то сбой, то скорей всего у Вас часть структуры окажется стёртой (заполненной FF например) и запросто совпадёт с другой тоже стёртой и вместе они уничтожат 3-ю валидную структуру sm.gif
Лучше, как тут уже советовали, дополнить структуру CRC, хранить достаточно 2 копии, и в каждой копии хранить дополнительно счётчик износа FLASH.
Перед обновлением структуры, выбираете в какой из копий счётчик меньше, создаёте в ОЗУ новый образ для записи (с инкрементированным счётчиком) дополненный CRC.
Стираете и записываете поверх структуры с минимальным счётчиком.
Если же при старте ПО окажется, что одна из копий или пуста или содержит неверную CRC, то для след. записи выбирается именно она, вне зависимости от счётчика, а начальное значение счётчика берётся из другой структуры (валидной) увеличенное на 1.
И хранить в ОЗУ копию не надо (зачем тратить ОЗУ?), раз структура находится во FLASH МК. Достаточно хранить указатель на валидную копию структуры.
Jenya7
я делал так
Код
void LoadFlashParams(void)
{
    //load the data from the first page
    memcpy(&flashParams, (uint32_t*)FLASH_PAGE125, sizeof(flashParams));
    uint32_t crc = crc32(0, (uint8_t*)&flashParams, sizeof(flashParams));
    if (crc != flashParams.crc)  //the first page damaged or the first time load
    {
        //load the data from a second page
        memcpy(&flashParams, (uint32_t*)FLASH_PAGE126, sizeof(flashParams));
        crc = crc32(0, (uint8_t*)&flashParams, sizeof(flashParams));
        if (crc != flashParams.crc)  //the second page damaged or the first time load
        {
            //two pages failed - initialize parameters, don't write to flash
            //INITIALIZATION OF STRUCT

            crc = crc32(0, (uint8_t*)&flashParams, sizeof(flashParams));
            flashParams.crc = crc;

            //WriteToFlash(FLASH_PAGE125);
            //WriteToFlash(FLASH_PAGE126);
        }
        else  //second page OK
        {
            //backup the data on the first page
            WriteToFlash(FLASH_PAGE125);
        }
    }
    else  //first page OK
    {
        //load the data from a second page
        memcpy(&flashParams, (uint32_t*)FLASH_PAGE126, sizeof(flashParams));
        crc = crc32(0, (uint8_t*)&flashParams, sizeof(flashParams));
        if (crc != flashParams.crc)  //the second page damaged
        {
            //backup the data on the second page
            WriteToFlash(FLASH_PAGE126);
        }
    }
}
pokk
Цитата
Если был какой-то сбой, то скорей всего у Вас часть структуры окажется стёртой (заполненной FF например) и запросто совпадёт с другой тоже стёртой и вместе они уничтожат 3-ю валидную структуру sm.gif

С чего копии окажутся стертыми? Каждая копия находится на разных страницах, тем самым когда произвожу стирание то уничтожается только 1 копия.

Цитата
И хранить в ОЗУ копию не надо (зачем тратить ОЗУ?), раз структура находится во FLASH МК. Достаточно хранить указатель на валидную копию структуры.

А как тогда перезаписать структуру ? в любом случае её надо будет считать в озу обновить и записать. В моем варианте первый шаг отбрасывается.
jcxz
Цитата(pokk @ May 24 2016, 16:30) *
С чего копии окажутся стертыми? Каждая копия находится на разных страницах, тем самым когда произвожу стирание то уничтожается только 1 копия.

Потому что подали команду стирания и в этот момент сбой питания произошёл.
И какой же у Вас процесс модификации структуры? Вот изменилась она, что делаете? Все 3 переписываете? Или как?

Цитата(pokk @ May 24 2016, 16:30) *
А как тогда перезаписать структуру ? в любом случае её надо будет считать в озу обновить и записать. В моем варианте первый шаг отбрасывается.

В Вашем варианте я не понимаю как Вы переписываете эти структуры чтобы было безопасно?
k155la3
Цитата(pokk @ May 24 2016, 09:35) *
. . . .

Сергей Борщ, в моем случае надо . . . . ., по этому не было такой нужны в CRC . . . .


Есть люди, которые свято верят, что CRC следует использовать только когда надо .
Наприимер, если соединительный провод между приборами 1-2-3 м, то использование CRC излишне и вредит sm.gif
(намек на "надежный канал связи").
Если бы с таким подходом был заложен стандарт на Ethernet/IP - сидели бы мы до сих пор без www.
pokk
Цитата
И какой же у Вас процесс модификации структуры? Вот изменилась она, что делаете? Все 3 переписываете? Или как?

Да все три по очереди, стереть первую копию записать, стереть вторую копию записать...
Код
void Write_SettingVAR_flash(void){
    //-------------------------------------------------
    FLASH->KEYR = FLASH_KEY1;
    FLASH->KEYR = FLASH_KEY2;
    //-----------------------------------------------------------------------------------------------------
    FLASH_ErasePage(ADDR_FLASH_CONST);
    FLASH_ProgramPage(ADDR_FLASH_CONST,(unsigned char*)&Global_Flash_SettingAllVar,Table_flash_Setting_len);
    //-----------------------------------------------------------------------------------------------------
    FLASH_ErasePage(ADDR_DUBLE1_FLASH_CONST);
    FLASH_ProgramPage(ADDR_DUBLE1_FLASH_CONST,(unsigned char*)&Global_Flash_SettingAllVar,Table_flash_Setting_len);
    //-----------------------------------------------------------------------------------------------------
    FLASH_ErasePage(ADDR_DUBLE2_FLASH_CONST);
    FLASH_ProgramPage(ADDR_DUBLE2_FLASH_CONST,(unsigned char*)&Global_Flash_SettingAllVar,Table_flash_Setting_len);
    //-----------------------------------------------------------------------------------------------------
    FLASH->CR |= FLASH_CR_LOCK; /* Lock the flash back */
    //-----------------------------------------------------------------------------------------------------
}

Цитата
Потому что подали команду стирания и в этот момент сбой питания произошёл.

Это может произойти только в одном из копий и она да повредится, остальные копии уже записались либо ещё не стерлись.



jcxz
Цитата(pokk @ May 25 2016, 15:13) *
Да все три по очереди, стереть первую копию записать, стереть вторую копию записать...

Вот стёрли Вы вторую, и тут бах! - выключились. А после включения получили: 1-я - новое содержимое; 2-я - стёрта; 3-я - старое содержимое.
И с Вашим методом сравнения получите потерю содержимого этих структур.

Цитата(pokk @ May 25 2016, 15:13) *
Это может произойти только в одном из копий и она да повредится, остальные копии уже записались либо ещё не стерлись.

Вот эти остальные у Вас и будут разные. И когда начнёте сравнивать побайтно, получите что в 3-х разных копиях три разных варианта значений.
Как можно не замечать очевидного???
ШСА
Цитата(pokk @ May 25 2016, 12:13) *
Да все три по очереди, стереть первую копию записать, стереть вторую копию записать...

Кроме всего прочего, у Вас будет очень сильный износ флеши. Если размер структуры много меньше размера секции флеши и рабочая копия есть в ОЗУ, то выгоднее с точки зрения износа флеши (а, следовательно, достоверности данных в ней) и проще записывать каждую обновлённую структуру сразу же после предыдущей. По окончании записи, в предыдущей затирать первый байт (слово). При считывании определяем актуальную запись по первому слову.
Тогда флеш будет расходоваться максимально рационально, причём стираться будет только после использования всей свободной области, т.е. редко. А в случае сбоя просто актуальными окажутся предыдущие настройки.
jcxz
Цитата(ШСА @ May 25 2016, 17:13) *
Кроме всего прочего, у Вас будет очень сильный износ флеши. Если размер структуры много меньше размера секции флеши и рабочая копия есть в ОЗУ, то выгоднее с точки зрения износа флеши (а, следовательно, достоверности данных в ней) и проще записывать каждую обновлённую структуру сразу же после предыдущей. По окончании записи, в предыдущей затирать первый байт (слово). При считывании определяем актуальную запись по первому слову.
Тогда флеш будет расходоваться максимально рационально, причём стираться будет только после использования всей свободной области, т.е. редко. А в случае сбоя просто актуальными окажутся предыдущие настройки.

Конечно, в этом случае лучше создать кольцевой буфер из N записей. Каждая запись - полная конфигурационная структура. Весь буфер должен занимать как минимум 2 блока стирания.
И стирать байты в предыдущей записи не нужно - кольцо надо поддерживать в таком состоянии, чтобы в нём был разрыв из N стёртых записей. При старте ПО должно находить место этой стёртой дырки,
и последняя записанная запись перед этой дыркой - это последняя актуальная конфигурация. Если же её CRC не совпадает (процесс её записи был прерван), валидной считается предыдущая (если её CRC верный).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.