Тема: запись переменной в флеш память плк
![]()
запись переменной в флеш память плк
подскажите как записать переменную в флеш память плк а потом прочитать ее оттуда или может по другому как то может в файл текстовый сохранить а потом оттуда прочитать состояние переменных или как то по другому
04.03.2012, 12:04 #2
![]()
Пользователь Регистрация 17.12.2007 Сообщений 108
Плк 150 запись и чтение.
Создается файл с именем переменной.
Постоянно перезаписывать файл нельзя— упорите флеш.
зап:
dwHandle := SysFileOpen(‘Pr_XX.t’,’
Последний раз редактировалось nalnik; 15.07.2015 в 12:22 .
04.03.2012, 12:12 #3
![]()
Пользователь Регистрация 23.01.2008 Адрес Белгородская область, Валуйки Сообщений 274
спасибо попробую
06.03.2012, 12:47 #4
![]()
Пользователь Регистрация 13.10.2011 Адрес Златоуст Сообщений 1,021
См. в справке RETAIN.
13.12.2012, 15:12 #5
![]()
Пользователь Регистрация 08.12.2012 Сообщений 26
Сообщение от nalnik 
Плк 150 запись и чтение.
Создается файл с именем переменной.
Постоянно перезаписывать файл нельзя— упорите флеш.
зап:
dwHandle := SysFileOpen(‘Pr_XX.t’,’w’);
SysFileWrite(dwHandle,ADR(Pr_XX),SIZEOF(Pr_XX));
SysFileClose(dwHandle);
Чтение:
dwHandle := SysFileOpen(‘Pr_XX.t’,’r’);
SysFileRead(dwHandle,ADR(Pr_XXf),SIZEOF(Pr_XXf)-1);
SysFileClose(dwHandle);
Работает.
Pr_XX — имя переменной
SysLibFile.lib — добавь библиотеку.
SysFileRead(dwHandle,ADR(Pr_XXf),SIZEOF(Pr_XXf)); — минус один, видимо, по ошибке
13.12.2012, 21:13 #6
![]()
Пользователь Регистрация 17.12.2007 Сообщений 108
нет это не ошибка!
13.12.2012, 21:47 #7
![]()
Пользователь Регистрация 08.12.2012 Сообщений 26
Сообщение от nalnik 
нет это не ошибка!
Сегодня проверял на ПЛК 100. Без -1 — работает, написал список переменных в файл. С -1 например UInt,Word работает до 255, так как из двух записанных байт восстанавливает один (из 4 -3, из 8 -7). Есть варианты когда можно проигнорировать целый байт?
19.12.2012, 23:39 #8
![]()
Пользователь Регистрация 28.10.2010 Сообщений 277
объясните тупому, что здесь делает переменная dwHandle? Какая-то индикация то файл открылся? Тогда зачем её пихать в функцию записи?
И еще, может кто подскажет как единоразово при включении ПЛК считать значение переменной из файла? откуда взять индикацию того что ПЛК включился после пропадания питания? Мне нужно примерно раз в 12 часов писать значение наработки двигателей во флеш и в случае пропадания питания или перезаливки проекта\сброса плк (когда RETAIN переменные слетают или могут слететь) восстанавливать это значение в программе.
Как записать переменную во флеш память 80с51F120

80с51f120 — это микроконтроллер, который широко используется во многих электронных устройствах. Одна из его важных возможностей — возможность записи переменных во флеш память. Запись переменных во флеш память может быть полезна при создании программного обеспечения для микроконтроллера, особенно если требуется сохранить данные на постоянной основе.
Первый шаг для записи переменной во флеш память 80с51f120 — это определение адреса во флеш памяти, где переменная будет храниться. Для этого необходимо указать соответствующую область памяти и адрес, который будет использоваться для записи переменной.
После определения адреса необходимо использовать специальную программу для записи значения переменной в указанную область памяти. Некоторые программы предоставляют графический интерфейс пользователя для удобства использования, тогда как другие могут требовать написания программного кода.
Важно отметить, что запись переменной во флеш память может быть небезопасной операцией, так как неправильная запись данных может повредить другие программы или данные в памяти. Поэтому перед записью переменной во флеш память рекомендуется создать резервную копию данных и ознакомиться с подробными инструкциями по использованию выбранной программы.
Подготовка к записи переменной во флеш память
Переменные во флеш память можно записать с помощью процессора 80с51f120. Для этого необходимо выполнить следующие шаги:
- Проверьте доступность флеш памяти: Убедитесь, что ваш процессор поддерживает запись во флеш память. Эта информация должна быть указана в документации к вашему процессору.
- Инициализируйте флеш память: Перед записью переменной во флеш память необходимо инициализировать ее. Это можно сделать с помощью специальных функций и команд процессора. Обратитесь к документации к вашему процессору для получения подробной информации об инициализации флеш памяти.
- Определите адрес для записи переменной: Выберите адрес во флеш памяти, по которому будет записана переменная. Убедитесь, что выбранный адрес не используется для других целей и что он достаточно далеко от начала флеш памяти.
- Запишите переменную во флеш память: Используя функции и команды процессора, запишите значение переменной в выбранный адрес во флеш памяти. Убедитесь, что запись производится без ошибок.
- Проверьте запись переменной: После записи переменной во флеш память, выполните считывание значения из выбранного адреса и проверьте, что записанное значение совпадает с ожидаемым.
Важно помнить, что запись переменных во флеш память требует специальных знаний и навыков в программировании. Неправильная запись данных во флеш память может привести к потере данных или некорректной работе программы. Поэтому рекомендуется обращаться к документации и консультироваться с опытными специалистами перед записью переменных во флеш память.
Процесс записи переменной во флеш память
Запись переменной во внутреннюю флеш память микроконтроллера 80с51f120 – это процесс, который позволяет сохранить данные на постоянное хранилище, чтобы они оставались доступными даже после перезагрузки устройства. Следующая инструкция описывает шаги, необходимые для успешной записи переменной во флеш память данного микроконтроллера.
- Определите адрес флеш памяти. Перед тем, как начать процесс записи переменной, вам необходимо определить адрес флеш памяти, куда вы хотите сохранить вашу переменную. Обратите внимание, что во флеш памяти есть зарезервированные области, которые могут быть уже заняты другими данными или кодом программы. Поэтому важно выбрать свободный адрес, который не будет перезаписываться другими данными.
- Создайте функцию записи. Для удобства вам следует создать функцию, которая будет выполнять запись переменной во флеш память. Эта функция должна принимать значение переменной и адрес флеш памяти в качестве аргументов. Внутри функции необходимо создать код, который запишет значение переменной в указанный адрес флеш памяти.
- Подготовьте микроконтроллер. Перед тем, как выполнить запись переменной, вам нужно подготовить микроконтроллер к работе с флеш памятью. Это может включать в себя различные настройки регистров микроконтроллера и прочие подготовительные действия.
- Вызовите функцию записи. После подготовки микроконтроллера и создания функции записи вы можете вызвать эту функцию, используя соответствующие аргументы. Это позволит произвести запись переменной во флеш память выбранного адреса.
- Проверьте результат. После выполнения записи переменной во флеш память необходимо проверить, что операция прошла успешно. Это можно сделать, считав значение, которое было записано в флеш память, и сравнив его с исходным значением переменной. Если значения совпадают, то запись переменной во флеш память была успешной.
Следуя этим шагам, вы сможете записать переменную во флеш память микроконтроллера 80с51f120 и сохранить данные для последующего использования.
Проверка записи переменной во флеш память
Для проверки записи переменной во флеш память 80с51f120 можно использовать специальные инструкции и регистры микроконтроллера.
1. В начале необходимо определить переменную, которую нужно записать во флеш память. Например, можно объявить переменную с именем «data» типа «int»:
2. Далее необходимо определить адрес во флеш памяти, по которому будет храниться переменная. Для этого можно использовать макросы, предоставленные производителем микроконтроллера. Например, для микроконтроллера 80с51f120 можно использовать макрос «__code» и указать адрес во флеш памяти:
__code int *flashAddress = (__code int*)0x1000;
3. Запись переменной во флеш память осуществляется с помощью инструкции «movx». Например, чтобы записать значение переменной «data» по адресу «flashAddress», можно использовать следующую инструкцию:
movx @flashAddress, data
4. Для проверки записи переменной во флеш память можно прочитать значение по указанному адресу и сравнить с ожидаемым значением. Например, можно прочитать значение по адресу «flashAddress» и сравнить с переменной «data» с помощью инструкции «movx»:
movx A, @flashAddress
cpl A
jnz error_label
5. Если значение прочитанной переменной и ожидаемого значения совпадают, то запись переменной во флеш память выполнена успешно. Если значения не совпадают, то произошла ошибка записи во флеш память. В таком случае можно использовать различные способы обработки ошибки, например, вывод сообщения об ошибке, перезапись переменной во флеш память и повторная проверка записи.
Таким образом, для проверки записи переменной во флеш память 80с51f120 необходимо определить переменную, адрес во флеш памяти, выполнить запись переменной по указанному адресу и проверить значения переменной в памяти.
Особенности использования флеш памяти 80С51F120
Микроконтроллер 80С51F120, как и многие другие микроконтроллеры, оснащен встроенной флеш-памятью, которая служит для хранения программного кода и данных. В этом разделе мы рассмотрим особенности использования флеш памяти данного микроконтроллера.
1. Размер и организация памяти:
- Микроконтроллер 80С51F120 имеет 256 Кбайт встроенной флеш-памяти.
- Память разделена на страницы размером 512 байт.
- Каждая страница содержит 16 секторов по 32 байта.
- Адресация памяти производится байтами.
2. Запись во флеш память:
- Перед записью во флеш память необходимо выполнить ее стирание.
- Стандартный процесс стирания флеш памяти может занимать до 10 мс, поэтому не подлежит выполнению во время работы микроконтроллера в реальном времени.
- Запись во флеш память выполняется по страницам размером 512 байт.
- Нельзя записывать данные в уже заполненные ячейки памяти, необходимо использовать команду стирания.
3. Чтение из флеш памяти:
- Чтение данных из флеш памяти производится побайтно.
- Во время чтения флеш память может быть использована во время работы микроконтроллера в реальном времени.
4. Управление флеш памятью:
Для управления флеш памятью 80С51F120 используется специальный набор инструкций, которые позволяют выполнять операции по стиранию, записи и чтению данных.
| Инструкция | Описание |
|---|---|
| ERASE_ALL | Удалить все данные во флеш памяти |
| ERASE_PAGE | Удалить данные в заданной странице |
| WRITE_BYTE | Записать байт данных в флеш память |
| READ_BYTE | Считать байт данных из флеш памяти |
Используя эти инструкции и зная организацию памяти, вы сможете эффективно использовать флеш память 80С51F120 для хранения программного кода и данных.
Преимущества записи переменной во флеш память
Запись переменной во флеш память микроконтроллера 80с51f120 имеет ряд преимуществ, которые могут быть полезны при разработке и оптимизации программного обеспечения.
1. Сохранение данных
Флеш память микроконтроллера является неизменяемой и позволяет сохранять данные даже при отключении питания. Это делает ее идеальным местом для хранения постоянных данных, таких как настройки, конфигурации или другие неизменяемые параметры, которые могут быть использованы после перезагрузки устройства.
2. Оптимизация использования ОЗУ
Запись переменной во флеш память позволяет освободить оперативную память (ОЗУ) для других задач. Это особенно важно при работе с микроконтроллерами, где объем ОЗУ может быть ограничен.
3. Ускорение запуска программы
Загрузка данных из флеш памяти может быть быстрее, чем загрузка данных из других источников, таких как внешние устройства хранения данных. Это может ускорить запуск программы и повысить ее общую производительность.
4. Увеличение надежности
Запись переменной во флеш память обеспечивает более высокую надежность хранения данных по сравнению с другими видами памяти. Флеш память имеет более долгий срок службы и лучшую стойкость к внешним воздействиям, таким как вибрации, удары или электромагнитные помехи.
В заключение, запись переменной во флеш память микроконтроллера 80с51f120 имеет ряд преимуществ, которые могут быть полезны при разработке программного обеспечения. Это позволяет сохранять данные, оптимизировать использование оперативной памяти, ускорять запуск программы и повышать надежность хранения данных.
Вопрос-ответ
Какие особенности имеет флеш память 80с51f120?
Флеш память 80с51f120 имеет определенные особенности, такие как ограниченное количество записей и прочитываемость данных после записи. Также, для записи данных во флеш память необходимо использовать специальные команды.
Что нужно для записи переменной во флеш память 80с51f120?
Для записи переменной во флеш память 80с51f120 необходимо знать адрес ячейки памяти, в которую будет производиться запись, и значение переменной. Также необходимо использовать специальные команды записи во флеш память.
Могу ли я записать переменную во флеш память 80с51f120 без знания адреса ячейки памяти?
Нет, для записи переменной во флеш память 80с51f120 необходимо точно знать адрес ячейки памяти, в которую будет производиться запись. Без этой информации невозможно выполнить операцию записи во флеш память.
Как разместить переменную по определенному адресу в Keil
Изредка возникает задача сохранить во flash памяти контрольную сумму, картинку, строчку текста, настройку. Иногда возникает задача сохранить не просто в ОЗУ, а в определенной области, чтобы для этой области например включить/выключить DCACHE. Или например иметь функцию, исполняемую из ОЗУ чтобы можно было присылать по UART и сразу исполнять новый код функции.
Рассмотрим задачу на примерах. В качестве испытуемого будет народный stm32f401ret6 со следующей адресацией flash памяти (страница 51 даташита):
#define ADDR_FLASH_SECTOR_0((uint32_t) 0x08000000) //Sector 0, 16 Kbytes #define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) //Sector 1, 16 Kbytes #define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) //Sector 2, 16 Kbytes #define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) //Sector 3, 16 Kbytes #define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) //Sector 4, 64 Kbytes #define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) //Sector 5, 128 Kbytes
Первый путь — ручной:
uint32_t keyFlash __attribute__((at(0x08004000))) = 0xAABBCCDD;
Здесь мы записали 32-битное число 0xAABBCCDD по адресу 0x08004000. Этот путь имеет следующий недостаток. Пусть мы точно разместили число в flash по адресу 0x08004000, рядом могут располагаться код программы, значения для констант. Если мы захотим перезаписать число по адресу, придётся стирать весь сектор, потому что во flash писать можно только посекторно. Я даже не знаю что будет, если выполняемые в данном секторе flash памяти инструкции попытаться стереть, но это очевидно плохая идея. Так что если предполагается возможность изменения данных во flash в процессе работы, под эти данные следует выделить отдельный сектор (сектора). И это нас приводит к второму пути.
Второй путь заключается в использовании скеттер (scatter) файла.Теорию можно прочесть здесь. Также желательно понимать что такое объектный файл. Совсем в двух словах, после работы препроцессор->компилятор получается множество
файлов *.o
где звездочка значит любое имя. Например, из main.c получается файл main.o
Рассмотрим пример scatter файла.
В дефолтный scatter файла, который генерирует сам Keil.
; ************************************************************* ;Scatter-Loading Description File generated by uVision stm32f401ret6 ; ************************************************************* LR_IROM1 0x08000000 0x00080000 < ; load region size_region ER_IROM1 0x08000000 0x00080000 < ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) >RW_IRAM1 0x20000000 0x00018000 < ; RW data .ANY (+RW +ZI) >>
Были добавлены две правки. Первое, исходный файл выделял под программу всю флеш:
Но я для примера выделю только 0 сектор (он начинается с 0x08000000 ) размером 16 кБ (0x00004000 — это 16*1024 байт в шестнадцатеричной системе).
ER_IROM1 0x08000000 0x00004000 < ; Sector 0: 16kB
где 0x08000000 — начальный адрес сектора, 0x00004000 — количество байт в секторе. По аналогии можно выделить два сектора, и не обязательно 0 и 1, а например 4 и 5 или при некоторых ухищрения даже например 0 и 5. (Но в stm32f4 таблица векторов прерываний должна располагаться в 0 секторе, так что в моём случае 0 сектор точно придётся выделить)
Вторая правка, в дефолтный scatter файл был добавлен execution region, который я решил назвать MYREGION. В этом регионе есть секция mysection, которая ищется во всех объектных файлах. Если линкер найдёт синтаксическую единицу (читай переменную) из этой секции, то эта синтаксическая единица попадёт в регион MYREGION.
LR_IROM1 0x08000000 0x08001000 < ; load region size_region
ER_IROM1 0x08000000 0x00004000 < ; Sector 0: 16kB
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
>
RW_IRAM1 0x20000000 0x00000900 < ; RW data
.ANY (+RW +ZI)
>
MYREGION 0x0800C000 FIXED *.o (mysection)
>
>
А теперь собственно в файле main.c заведем нашу синтаксическую единицу для хранения в регионе:
const uint16_t ADC_Buf[7] __attribute__((section(«mysection»))) = ;
И тут нас ждёт ловушка. Язык высокого уровня мы любим за оптимизацию. Включаем -O3 и наша неиспользуемая в программе константа исчезает. Тут случай, когда про toolchain можно сказать «слишком умный». Чтобы объяснить, что в секции mysection у нас всё только нужное, зайдём на вкладку Linker в Misc controls и пропишем
—keep=»main.o(mysection)»

Изредка бывает ситуация, когда мы хотим ограничить распространения региона только на синтаксические единицы из определенного файла, пусть main.c тогда вместо
MYREGION 0x0800C000 FIXED *.o (mysection)
>
пишите
MYREGION 0x0800C000 FIXED main.o (mysection)
>
А ещё можно например все переменные из файла пусть main.c заставить жить в вашей секции вот так
MYREGION 0x0800C000 FIXED main.o(+RW +ZI)
>
При тестировании не забывайте делать Full chip erase, чтобы точно очищать всю flash. А то окажется, что ваш текущий код работает неверно, а смотрите и радуетесь вы результату работы предыдущего кода.

Кому оказалась интересна тема scatter файлов, предлагаю упражнение. Наверняка вы писали программу моргания светодиодом. Я перелагаю вам написать одну программу, которая работает верно: зажигает и тушит светодиод, А вторая программа будет зажигать и зажигать светодиод:
void blink() < while(1)< on(); delay(); on(); delay(); >>
После этого я предлагаю вам посмотреть содержимое памяти и глазами найти отличие. Далее blink() с помощью scatter файла поместите в ОЗУ, пусть оттуда выполняется. Затем перед вызовом функции blink() в main() попробуйте написать код, который починит blink(), чтобы она и зажигала и тушила. О своих (не) успехах пишите в лс или комментариях, может быть получится ещё одна заметка.
Дополнительные материалы:
Как не инициализировать переменные в кейл?
Про слово FIXED
Заметка про сохранение структур во flash памяти на STM32

При разработке проекта для микроконтроллера часто возникает необходимость сохранения данных во Flash-память перед выключением устройства, например глобальные структуры, содержащие информацию о настройках различной периферии, данные с внешних датчиков и прочее. В этом посте я хочу показать простой механизм записи структуры во FLASH память микроконтроллера STM32, которым я сам часто пользуюсь в своих проектах.
Для начала рассмотрим работу с flash на контроллере STM32F103C8T6 (blue pill). Начнем с изучения документации. Смотрим, как разбита память, в reference manual, в разделе Embedded Flash memory. Либо можно подключить контроллер через программатор и посмотреть в Cube Programmer.

Память контроллера разбита на страницы объемом 1 Кбайт. В datasheet приведена длительность на операцию стирания — максимум 40 мс.

Пользовательская прошивка хранится в начале памяти, поэтому для записи данных я использую страницы с конца микроконтроллера. Будем писать в 126 страницу по адресу 0x0801F800. 127 страница остается как запасная, если данные не помещаются на одну страницу.
#define flashADDR 0x0801F800
Далее создадим структуру, содержимое которой будет записываться в ячейку памяти:
struct < uint8_t var1; uint16_t var2; uint32_t var3; double var4; >test_struct;
Заполняю ее случайными значениями:
test_struct.var1 = 200; test_struct.var2 = 59999; test_struct.var3 = 98765; test_struct.var4 = 45.11;
Теперь перейдем к записи во Flash. Более подробно про это можно почитать тут и тут, но если коротко, то в начале нам необходимо разблокировать память, стереть нужную нам страницу, после уже произвести запись и заблокировать обратно.
Создадим отдельную функцию и переменные:
uint8_t writeFlash (uint32_t addr) < HAL_StatusTypeDef status; uint32_t structureSize = sizeof(test_struct); FLASH_EraseInitTypeDef FlashErase; uint32_t pageError = 0;
После этого отключаем прерывания, чтобы не нарушать процесс записи и разблокируем память:
__disable_irq(); status = HAL_FLASH_Unlock();
Настроим процесс стирания - укажем, что удалять будем постранично (еще можно массово), с какого адреса начнем и сколько страниц это затронет. Последнее рассчитаем, исходя из размера структуры.
FlashErase.TypeErase = FLASH_TYPEERASE_PAGES; FlashErase.PageAddress = addr; FlashErase.NbPages = structureSize / 1024 + 1;
Теперь очистим необходимое нам пространство. Если случилась ошибка в процессе стирания, то закрываем память и сообщаем об этом.
if (HAL_FLASHEx_Erase(&FlashErase, &pageError) != HAL_OK)
Теперь все готово к записи нашей структуры. Создаем указатель на неё и с помощью функции HAL_FLASH_Program записываем все её содержимое. Функция первым аргументом запрашивает, каким объемом будут писать данные - по 1, 2 или четырем байтам за раз (FLASH_TYPEPROGRAM_BYTE/HALFWORD/WORD соответственно). Забавно то, что дальше эта функция, вне зависимости от вашего выбора, будет писать строго по 2 байта (конкретно на этом камне). Я думаю, это сделано для того, чтобы поддержать единообразие hal от камня к камню, потому что на F401 эта функция уже умеет работать с различными режимами записи. После записи всех данных мы закрываем память, включаем все прерывания и возвращаем статус.
uint32_t *dataPtr = (uint32_t *)&test_struct; for (int i = 0; i < structureSize / 4; i++) < status += HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, dataPtr[i]); addr += 4; >__enable_irq(); HAL_FLASH_Lock(); return status;
Мы записали нашу структуру в память, потом устройство, выключилось, и спустя некоторое время включается обратно. Теперь необходимо прочитать сохраненные данные, для этого заводим функцию чтения, которая заметно проще функции записи:
void readFlash (uint32_t addr) < uint32_t structureSize = sizeof(test_struct); uint32_t *dataPtr = (uint32_t *)&test_struct; for (int i = 0; i < structureSize / 4; i++) < dataPtr[i] = *(__IO uint32_t*)addr; addr += 4; >>
Тут аналогично: в начале определяется размер структуры, а после считываем по 4 байта за раз.
Теперь возьмем контроллер посолиднее - F401 (black pill). Тут механизм записи будет выглядеть немного иначе, так как там деление памяти идет уже на сектора (reference):

Конкретно в моем камне есть только первые 6 секторов, при этом последний из них довольно крупный - 128 Кбайт. Изучим тайминги стирания/записи тут.

Стирание сектора может занимать несколько секунд, однако. Можно увидеть, что этот контроллер поддерживает запись по одному, двум и четырем байтам. Самое интересное тут то, что чем ниже напряжение питания, тем меньше байт за раз можно будет записать. Я попробовал запись по одному байту при VCC = 1.76 В - процесс заметно медленный, но все работает.
Перейдем к коду. От предыдущего он будет отличаться только тем, что страницы необходимо заменить на сектора. Пример для записи по 4 байта. Функции чтения аналогичны.
uint8_t writeFlash (uint32_t addr) < HAL_StatusTypeDef status; uint32_t structureSize = sizeof(test_struct); FLASH_EraseInitTypeDef FlashErase; uint32_t sectorError = 0; __disable_irq(); HAL_FLASH_Unlock(); FlashErase.TypeErase = FLASH_TYPEERASE_SECTORS; FlashErase.NbSectors = 1; FlashErase.Sector = FLASH_SECTOR_5; FlashErase.VoltageRange = VOLTAGE_RANGE_3; if (HAL_FLASHEx_Erase(&FlashErase, §orError) != HAL_OK) < HAL_FLASH_Lock(); __enable_irq(); return HAL_ERROR; >uint32_t *dataPtr = (uint32_t *)&test_struct; for (uint8_t i = 0; i < structureSize / 4; i++) < status += HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, dataPtr[i]); addr += 4; >__enable_irq(); return status; >
/*----------------------------------------------------------------------------*/ uint8_t writeFlash (uint32_t addr) < HAL_StatusTypeDef status; uint32_t structureSize = sizeof(test_struct); FLASH_EraseInitTypeDef FlashErase; uint32_t sectorError = 0; __disable_irq(); HAL_FLASH_Unlock(); FlashErase.TypeErase = FLASH_TYPEERASE_SECTORS; FlashErase.NbSectors = 1; FlashErase.Sector = FLASH_SECTOR_5; FlashErase.VoltageRange = VOLTAGE_RANGE_1; if (HAL_FLASHEx_Erase(&FlashErase, §orError) != HAL_OK) < HAL_FLASH_Lock(); __enable_irq(); return HAL_ERROR; >uint8_t *dataPtr = (uint8_t *)&test_struct; for (uint8_t i = 0; i < structureSize; i++) < status += HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, addr, dataPtr[i]); addr++; >__enable_irq(); return status; > /*----------------------------------------------------------------------------*/ void readFlash (uint32_t addr) < uint32_t structureSize = sizeof(test_struct); uint8_t *dataPtr = (uint8_t *)&test_struct; for (int i = 0; i < structureSize; i++) < dataPtr[i] = *(__IO uint32_t*)addr; addr++; >>
P.S. В процессе работы заметил, что размер данного массива 16 байт вместо рассчитанных 15 (1 + 2 + 4 + 8). Проведя небольшой поиск в интернете, я наткнулся на статью, где объясняется, почему так происходит и как оптимизировать структуры на C для экономии места. Главный совет из этой статьи - располагать элементы в порядке убывания их размера, т.е. с точностью наоборот, как у меня (например: double, double, uint32_t, uint8_t, а не в разнобой)
P.S.S. Изначально думал уместить это в размер поста/заметки, но написал слишком много буков.
- C
- Хранение данных
- Программирование микроконтроллеров
- Производство и разработка электроники