Comments 18
Как-то в одном из проектов делал подобное но рекомендую скользящую запись а стирать страницу только после того как она заполнится. Так мы уменьшим количество циклов перезаписи памяти в разы.
Правильно. Нечего память изнашивать. При очистке блока он заполняется значениями 0xff (все единицы), операция записи делает побитовую операцию AND с записываемым значением и уже записанным. То есть биты можно сбрасывать в 0 без очистки, этим и нужно пользоваться. Грамотно написанные прошивки для устройств используют такой метод дозаписи данных.
ну так тут одна маленькая структура для примера, в рабочих проектах поболее будет. Но мысль хорошая, надо будет в след. проекте попробовать.
А контроль целостности данных?
А зачем вы читаете структуру циклом по 4 байта?
my_struct = *struct_in_flash_ptr;
Структура должна бы выровнена на 4. Но без выравнивания и ваш вариант не сработает скорее всего.
И самое интересное в этой задаче, это не сама по себе запись и чтение, это в RM описано, а именно алгоритм выравнивания износа.
Если использовавть IAR, там по умолчанию выравнивание включено, но я так бы не стал писать код, если не рассматривать выравниявание, то в структуре 15 байт. Износ для меня не актуален, записвается один раз при калибровке (в идеале), ну никак не 1000 раз. Тут другая проблема вылезла - у 3% микроконтроллеров при определенных обстоятельтствах (пока закономерность не установил - но скорее всего при включении питания) иногда сбрасываются сохраненные данные.
Вообще, у ST есть готовый драйвер эмуляции EEPROM, и при неспособности написать нормальный свой (например, с типизацией, с wear levelling, и для работы с двухбанковой структурой, чтобы и писать, и исполнять из флеша одновременно), можно хотя бы за основу взять его, а не изобретать HAL-велосипеды.
Насчет писания во флеш данных с датчиков - имейте в виду, что после нескольких тысяч циклов записей, страница флеш превращается в тыкву.
А вы не забыли разрешить прерывания в случае ошибки очистки памяти?
Я сам делаю последовательную запись, чтобы не стирать каждый раз. Обязательно использую 2 страницы, чтобы в случае чего при стирании не остаться вообще без данных. Все записи нумеруются, чтобы потом найти последнюю. Контрольная сумма - тоже обязательно. Проверку флагов ошибок после записи и стирания - тоже делаю.
Второй момент: не понял, зачем запрещать прерывания. Во время записи или стирания стм не может читать флешу, соответственно, не может выполнять оттуда код. Поскольку стирание - процесс не быстрый, даже приходится реалтаймовые обработчики прерываний выносить в ОЗУ.
3-й момент: для страниц с кодом обязательно нужно включать защиту от записи. На нескольких чипах встречал порчу кода, когда где-то в прошивке используется запись во флешу. Может, конечно, это и от общей криворукости происходит, но защита не повредит.
Во время записи или стирания стм не может читать флешу, соответственно, не может выполнять оттуда код.
Смотря какой стм, некоторые могут. Но прерывания при достаточной прямоте рук действительно абсолютно не вредят записи/стиранию флеша, выполняясь параллельно с этими операциями.
для страниц с кодом обязательно нужно включать защиту от записи
И как вы потом обновляете прошивку?
И как вы потом обновляете прошивку?
Есть несколько вариантов:
встроенным загрузчиком. Через USB, или другие интерфейсы, которые используется для связи с внешним миром. Не, все, правда. Жаль, что через голый RS485 это не работает, например.
иметь часть прошивки - загрузчик, всегда защищённую от записи. В самом STLink так сделано, например. А если стоит защита от чтения, у большинства стм защита записи первых килобайт флеши автоматом ставится.
на время обновления защиту можно и снять. Но если нет запасных загрузочных интерфейсов, есть опасность "окирпичить" плату где-то далеко у заказчика.
отладить прошивку так, чтобы не надо было обновлять. Для серийных устройств этот вариант лучше, чем потом ездить и "кирпичи" собирать.
Недавно 2-й вариант осилил для CAN-шины.
А зачем своя функция чтения если можно стандартный memcpy() ? Тем более если размер не кратный 4, то хвост структуры не перепишется.
Тема не раскрыта.
Нет описания того, как разместить структуру по нужному адресу во флэш. Линковщик ничего не знает о том, как в вашей программе используется страницы 126 и 127. Ну и не забываем, что сегодня у нас 64К флэша, а завтра 128К. Поэтому коли взялись писать о записи во флэш, тогда покажите как сделать так, чтобы сохраняемые данные всегда оказывались, например, в конце программы по нужным адресам. Кстати, на форумах много вопросов на эту тему.
Настроим процесс стирания - укажем [...] сколько страниц это затронет. Последнее рассчитаем, исходя из размера структуры.
FlashErase.NbPages = structureSize / 1024 + 1;
Но, предположим, размер структуры равен ровно 1024. Какой результат нам даст такое выражение? Оно нам даст результат 2. А зачем нам стирать две страницы, если структура целиком помещается в одну?
По-моему, идиома целочисленного деления с округлением вверх широко известна:FlashErase.NbPages = (structureSize + 1023) / 1024;
Заметка про сохранение структур во flash памяти на STM32