======Расположение функций в ОЗУ, программирование EEPROM======
=====Отключение прерываний=====
При программировании FLASH памяти важно, чтобы программа исполнялась из ОЗУ, потому что нельзя
одновременно писать в Flash память и исполнять из нее команды. Flash память переключается в режим программирования и, если происходит обращение на чтение, то процессор сваливается в HardFault.
Одного лишь выполнения кода работы с FLASH из ОЗУ недостаточно. Если таблица векторов прерываний и функции обработчиков прерываний находятся в FLASH, то обращение к ним так же вызовет HardFault. Поэтому в процессе работы с FLASH необходимо выключать все прерывания, либо реализовать перенос таблицы векторов и обработчиков в ОЗУ. Отключить обработчики прерываний можно следующим образом:
__set_PRIMASK(1); // Отключение всех прерываний кроме NMA и HardFault
или
__set_FAULTMASK(1); // Отключение всех прерываний кроме NMA
Подробнее - [[DOC:DocList:IrQ|Прерывания и приоритеты]]
Если в проекте не используются прерывания, то выключать их не нужно. Важно лишь при использовании прерываний не забывать их выключать на время работы с EEPROM.
=====Пример работы с EEPROM =====
Работу с EERPOM рассмотрим на примере от производителя - //Sector_Operations//. После установки PACK от Миландр, этот пример расположен по такому пути:
C:\Keil_v5\ARM\PACK\Keil\MDR1986BExx\1.4\Examples\MDR1986VE9x\MDR32F9Q1_EVAL\EEPROM\Sector_Operations
//Целиком аналогичный проект для 1986ВЕ1Т можно скачать с [[https://github.com/StartMilandr/1.3-EEPROM_WR_RD|GitHub]].//
Создаем новый проект, как описано в [[prog:start:new_project|"Создание проекта"]], только процессор выбираем 1986ВЕ92. При создании подключаем разделы библиотеки - Startup_MDR1986DT9x, EEPROM, PORT, RST_CLK. В проект добавляем файл //main.c// из указанного выше пути. В статье [[prog:start:new_project|"Создание проекта"]] мы создавали новый файл// main.c//, здесь же проще кликнуть правой клавишей мыши на папке user и выбрать //"Add Existing File ..."// . Компилируем, ошибок быть не должно.
Загружаем проект в кристалл и выполняем следующие действия:
- Включаем режим отладки
- Ставим точку останова на первой функции обращения к EEPROM.
- Запускаем F5 или кнопкой в тулбаре
- Останавливаемся перед входом в выбранную функцию и видим, что код находится в адресах Flash памяти.
{{doc:ram_debug_08.png}}
Теперь заходим внутрь функции EEPROM_ErasePage,
- Нажимаем F11 или используем кнопку в тулбаре.
- Видим, что указатель команд находится в начале функции.
- Наблюдаем, что функция находится в адресах Flash памяти.
{{doc:ram_debugram_08.png}}
Получается, что пример, запущенный по умолчанию, не располагает функции работы с EEPROM в области памяти ОЗУ. Такой код при исполнении будет сваливаться в HardFault. Если осуществить дальнейший запуск программы, то будет видно, что исполнение никогда не выйдет из функции EEPROM_ErasePage.
=====Располагаем файл "MDR32F9Qx_eeprom.c" в ОЗУ=====
Давайте расположим весь библиотечный файл работы с EEPROM в ОЗУ. Для этого при клике правой клавишей мыши на файле выбираем "//Options for Component ...//".
{{doc:ram_fileoptions.png}}
В открывшемся окне в закладке //Memory// выбираем расположение //Code// в доступных областях памяти.
{{doc:ram_fileoptions_ipam.png}}
Доступные области памяти определены в окне Options проекта, здесь нам надо только выбрать область ОЗУ - IRAM1 (Internal RAM1).
{{doc:1986ve9x_iram.png}}
При размещении исполняемого кода в ОЗУ для **МК 1986ВЕ1Т** необходимо выбирать память IRAM2, адреса которой начинаются с 0x20100000. Только к этой памяти имеет доступ шина AHB_Lite, поэтому код из этой памяти может исполняться. Этот же диапазон следует выбирать для данных при работе с DMA.
ВАЖНО также выставить опцию - //"Use Memory Layout from Target Dialog"//, в закладке //Linker// опций проекта. Без этого код файла MDR32F9Qx_eeprom.c не окажется в диапазонах памяти ОЗУ.
{{doc:1986ve9x_linker.png}}
Компилируем проект, загружаем в кристалл и в режиме отладки снова идем внутрь функции EEPROM_ErasePage. Теперь в окне ассемблера видно, что наша функция находится в адресах ОЗУ.
{{doc:ram_eeinram.png}}
Если теперь запустить проект, то он отработает успешно.
=====Располагаем отдельные функции в памяти=====
Существует еще один вариант разместить функции в памяти ОЗУ. Вернем проект в исходное состояние. Если посмотреть определение функции EEPROM_ErasePage в "MDR32F9Qx_eeprom.h", то видно, что она определена с некоторыми атрибутами:
__RAMFUNC void EEPROM_ErasePage(uint32_t Address, uint32_t BankSelector) __attribute__((section("EXECUTABLE_MEMORY_SECTION")));
Атрибут __RAMFUNC не воспринимается Keil, это, видимо, атрибут для среды разработки IAR. У меня нет данных по этому вопросу.
Запись __attribute__((section("EXECUTABLE_MEMORY_SECTION"))) воспринимается Keil так, что он пытается разместить эту функцию в секцию памяти с именем EXECUTABLE_MEMORY_SECTION. Для того чтобы использовать этот атрибут, необходимо внести исправления с скаттер-файл.
{{doc:ram_linksct.png}}
Когда мы включили опцию «Use Memory Layout from Target Dialog», то создался файл *.scr по умолчанию. При каждой компиляции этот файл будет обновляться. Для того чтобы этого не происходило, теперь выключим опцию «Use Memory Layout from Target Dialog». Далее найдем скаттер файл в папке проекта и откроем его блокнотом. Вот его листинг по умолчанию:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x20000000 0x00001000 { ; load region size_region
ER_IROM1 0x20000000 0x00001000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20001000 0x00001000 { ; RW data
.ANY (+RW +ZI)
}
}
Здесь определены две обрасти памяти Flash и ОЗУ. Нам необходимо добавить запись, чтобы данные, помеченные атрибутом EXECUTABLE_MEMORY_SECTION из всех объектных файлов, располагались в адресах ОЗУ. Вот как это делается.
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x20000000 0x00001000 { ; load region size_region
ER_IROM1 0x20000000 0x00001000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20001000 0x00001000 { ; RW data
*.o (EXECUTABLE_MEMORY_SECTION)
.ANY (+RW +ZI)
}
}
Более подробно про скаттер-файл можно прочитать в описании [[http://www.keil.com/support/man/docs/armlink/armlink_pge1407248176212.htm|Keil]]
Скомпилируем проект, загрузим и убедимся, что наш проект работает корректно, и функции EEPROM расположены в ОЗУ.
Первый способ - расположение всего файла в ОЗУ - более прост и поскольку в файле MDR32F9Qx_eeprom.c сосредоточена только работа с EEPROM, то этот способ получил большее распространение.
=====ВАЖНО=====
**Функция стирания по секторам стирает заданный сектор в указанном банке - в информационном или основном. НО функция стирания микросхемы целиком, при выборе информационного банка стирает основную память тоже!**
EEPROM_EraseAllPages(EEPROM_Info_Bank_Select); // Стирает основную память и информационную