Программирование ARM IAR EWB for ARM: работа с внутренней памятью программ (internal flash memory) Fri, July 21 2017  

Поделиться

нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


IAR EWB for ARM: работа с внутренней памятью программ (internal flash memory) Печать
Добавил(а) microsin   

В статье рассмотрен вопрос перепрошивки flash-памяти контроллеров AT91SAM7X128, AT91SAM7X256, AT91SAM7X512 под управлением программы firmware.

Иногда по разным причинам (bootloader, сохранение настроек, каких-то данных, обновление программы) необходимо иметь возможность модифицировать память программ кристалла непосредственно в выполняемой программе. Быстрый старт в этом вопросе - пример от Atmel c:\Program Files\IAR Systems\Embedded Workbench 5.0 Evaluation\ARM\examples\Atmel\at91sam7x-ek\basic-internalflash-project\. В примере вы найдете все необходимое, он несложен. Но чтобы все заработало, необходимо исправить в нем ошибку.

В регистре MC_FMR (контроллер EFC или EFC0 и EFC1, если используется чип AT91SAM7X512) есть очень важное поле из 8 бит - FMCN. В даташите написано, что туда надо записывать количество циклов тактовой частоты за 1 мкс. В примере basic-internalflash-project все делается в точности, как сказано в даташите - от значения тактовой частоты BOARD_MCK вычисляется 8 бит для поля FMCN и сохраняется в глобальной переменной lMckFMCN (это делается последовательностью вызовов FLASHD_Initialize(BOARD_MCK) -> EFC_SetMasterClock(mck) -> lMckFMCN = FMCN_BITS(lMck)). Потом эта величина используется внутри вызовов EFC_PerformCommand для записи в регистр MC_FMR. Все было бы хорошо, если бы информация в даташите по вычислению поля FMCN была верной.

На самом деле это не так, с чем довелось столкнуться при программировании кристалла AT91SAM7X512. Как известно, у этого кристалла два контроллера flash - EFC0 (обслуживает flash 0x100000..0x13FFFF) и EFC1 (обслуживает flash 0x140000..0x17FFFF). Эти два контроллера ведут себя по-разному по отношению к значению поля FMCN в регистре MC_FMR. Если вычислить поле FMCN как указано в даташите (в примере basic-internalflash-project так все и делается), то контроллер EFC1 программирует свою память совершенно нормально, а программирование памяти контроллером EFC0 сопровождается непредсказуемым поведением ядра микроконтроллера. Опишу условия моего опыта.

Мне было необходимо записать область памяти 0x110000..0x17FFFF кристалла AT91SAM7X512, тактовая частота ядра 48 МГц (кварц на 18.432 МГц, проект заточен для поддержки USB). Почему-то записать могу только в область 0x140000..0x17FFFF, которая обслуживается EFC1, а запись в область 0x110000..0x13FFFF заканчивается глюками и падениями - портятся регистры, программа вылетает то в Abort_Handler, то в Undefined_Handler, то в Reset_Handler, то в Prefetch_Handler. Глюк происходит в FLASHD_Write, при вызове EFC_PerformCommand, и каждый раз случайным образом. Причем если пройти тело EFC_PerformCommand по шагам, то вылета нет.

Константа, записываемая в поле FMCN, у меня равнялась 48 (0x30) - все правильно, ведь за 1 мкс пройдет 48 циклов тактовой частоты. Однако методом подбора значения этого поля мне удалось выяснить, что глюки пропадают начиная с значения поля FMCN, равного 51. Таким образом, для надежной работы следует подобрать значение поля FMCN, либо взять его с запасом, например 64 (0x40) для частоты 48 МГц (и соответственно поправить код макроса FMCN_BITS, вычисляющего значение поля FMCN).

Остальную информацию этой статьи можно почерпнуть из даташита и кода примера basic-internalflash-project.

[Flash AT91SAM7X512]

1. Flash поделена на страницы по 256 (AT91C_IFLASH_PAGE_SIZE) байт, всего 2048 (AT91C_IFLASH_NB_OF_PAGES) страниц. Первые 1024 страницы (0x100000..0x13FFFF) обслуживаются EFC0, следующие 1024 страницы (0x140000..0x17FFFF) обслуживаются EFC1. Память может быть записана только постранично, по 256 байт.

2. Flash также поделена на сектора блокировки по 16384 (AT91C_IFLASH_LOCK_REGION_SIZE) байт, всего 32 сектора (AT91C_IFLASH_NB_OF_LOCK_BITS). В одном секторе 64 страницы по 256 байт. Каждому сектору соответствует бит защиты, который предотвращает запись данных в свой сектор.

3. Для организации собственного bootloader-а (например, с целью обновления firmware) удобно выделить младшие адреса flash (например 0x100000..0x1007FFF) непосредственно под код bootloader, а остальную часть flash (0x108000..0x17FFFFF) - под обновляемую программу.

4. Перед стартом перепрошивки нужно не забыть вызвать FLASHD_Initialize(BOARD_MCK). После этого необходимо защитить код bootloader вызовом FLASHD_Lock (AT91C_IFLASH, 0x107FFF, 0, 0), а перепрошиваемый код разблокировать вызовом FLASHD_Unlock(0x108000, AT91C_IFLASH + AT91C_IFLASH_SIZE - 1, 0, 0).

5. Писать данные можно блоками любого размера, начиная с любого адреса вызовами FLASHD_Write, не заботясь ни о чем (страничная организация памяти и наличие двух регионов, обслуживаемых разными контроллерами, разруливается уже внутри подпрограммы FLASHD_Write), но оптимальнее всего писать блоками, размер которых в байтах делится нацело на 256, и начиная с адреса, младшие 8 бит которого равны 0. В этом случае FLASHD_Write не делает никаких ненужных дополнительных телодвижений.

6. В процессе записи внутренней flash должны быть отключены все прерывания, кроме прерываний, связанных с контроллерами EFC. Кстати, в примере basic-internalflash-project при работе с flash-памятью прерывания не используются, готовность и состояние контроллеров EFC опрашиваются поллингом (периодическими чтениями регистров).

7. Необходимо правильно настроить количество циклов ожидания при работе с flash-памятью. Это делается в модуле board_lowlevel.c, процедура LowLevelInit (запись регистра EFC_FMR).

[Ссылки]

1. IAR EWB for ARM: учимся управлять сегментами на примере добавления версии по фиксированному адресу.
2IAR EWB for ARM: как поменять абсолютный начальный адрес выполнения программы.
3. IAR EWB for ARM: как из кода C сделать безусловный переход на абсолютный адрес.
4AT91SAM7X: простейший bootloader, читающий firmware с карты SD/MMC (используется EFSL)

 

Добавить комментарий


Защитный код
Обновить

Top of Page