Программирование AVR AVR109: самопрограммирование AVR Mon, December 09 2024  

Поделиться

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

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


AVR109: самопрограммирование AVR Печать
Добавил(а) microsin   

Здесь приведен перевод апноута "AVR109: Using Self Programming on tinyAVR and megaAVR devices" [1]. Затронуты следующие вопросы:

• Пример кода на C программы, которая сама программирует память программ
• Чтение и запись областей памяти FLASH и EEPROM
• Чтение и запись битов защиты (Lock Bits)
• Чтение битов фьюзов (Fuse Bits)
• Как это работает с утилитой AVR911 Open Source Programmer [2]
• Совместимость с AVRProg
• Протокол, оптимизированный для эффективного программирования

[Введение]

Этот апноут описывает, как AVR может использовать инструкцию Store Program Memory (SPM) для программирования самого себя. Обычно такое программирование используется для бутлоадеров. Программа примера (firmware микроконтроллера, bootloader) обменивается через UART с компьютером PC, на котором запущена утилита программирования AVR Open Source Programmer (AVROSP) [2] из апноута AVR911. Это позволяет программировать FLASH и EEPROM без необходимости во внешнем программаторе. Код firmware по протоколу также совместим с оболочкой программатора AVRProg (только для устройств, поддерживаемых AVRProg), которая поставляется вместе с AVR Studio (или Atmel Studio).

Программа bootloader записана в специальную секцию загрузки Boot Section памяти FLASH. Это обычная программа, которая обрабатывает обмен с компьютером-хостом PC, и реализует программирование как Flash, так и EEPROM. После программирования можно применить защиту различных (по выбору) уровней, индивидуально для областей памяти загрузки (boot FLASH memory) и приложения (application FLASH memory). Таким образом предоставляется уникальная и удобная возможность программирования AVR, с разрешением применить защиту записываемого в память программного обеспечения (firmware protection).

[Инструкция SPM]

Чтобы лучше понять возможность самопрограммирования AVR, здесь будут рассмотрены базовые принципы организации памяти и работы инструкции SPM. Память FLASH разделена на 2 секции, одна из них секция приложения (Application section), другая секция загрузчика (Boot Loader section). Включение в работу секции загрузчика управляется установкой специальных фьюзов AVR.

Прим. переводчика: такое деление FLASH на секции имеется не у всех моделей AVR, в основном только для устройств ATmega.

Секция приложения содержит основной код приложения, в то время как секция загрузчика содержит код для реального самопрограммирования. Инструкция SPM может быть выполнена только из секции загрузчика. Примечание: память секции загрузчика может использоваться и для обычного программного обеспечения.

Память FLASH также разделена на страницы (page) по 32, 64 или 128 слов. Использование страниц памяти будет объяснено позднее. Весь пул памяти, и секции и приложения, и секции загрузчика, поделен на страницы. Например, устройство с 8 килобайт FLASH и размером страницы в 32 слова (64 байта) будет иметь 128 страниц. Организация памяти показана на рис. 1.

Прим. переводчика: в одном слове содержится 2 байта. Это связано с организацией системы команд RISC-ядра AVR, одно слово обычно соответствует одной инструкции ассемблера AVR. Деление на страницы связано с особенностью технологии памяти FLASH.

Рис. 1. Организация памяти AVR.

AVR109-memory-organization-fig1

Размер секции загрузчика (Boot Loader section) может быть выбран программированием двух битов фьюзов BOOTSZx (здесь x равно 0 или 1). Таким образом, этими фьюзами можно выбрать один из 4 определенно заданных вариантов. Фьюзы BOOTSZx могут быть изменены с использованием последовательного или параллельного программирования (Serial Programming или Parallel Programming). Для этого нужен специальный программатор ISP или HVSP [3]. Подробности такого программирования смотрите в даташите на устройство.

Если реализован загрузчик (bootloader), то он может быть запущен либо непосредственно из кода приложения (как вызов подпрограммы call или прямым переходом jmp), или с помощью запрограммированного бита фьюзов BOOTRST. Когда бит фьюзов BOOTRST запрограммирован, то при сбросе Reset (или включении питания) CPU запустит выполнение программы не с адреса 0, а с адреса начала секции загрузчика (Boot Loader section). Фьюз BOOTRST, как и фьюзы BOOTSZx, может быть изменен с использованием последовательного или параллельного программирования.

Возможность операции Read-While-Write

В дополнение к делению памяти FLASH на секции приложения и загрузчика, FLASH также разделена на две секции фиксированного размера. Первая секция является секцией Read-While-Write (RWW). Вторая секция No-Read-While-Write (NRWW). Секция NRWW по размеру всегда равна самой большой возможной секции загрузчика (из 4 вариантов выбора), так что секция загрузчика всегда находится в секции NRWW (занимает всю память NRWW или её часть). Это показано на рис. 2.

Рис. 2. Секции RWW и NRWW.

AVR109-RWW-NRWW-sections-fig2

Различия в секциях RWW и NRWW состоит в том, что секция NRWW доступна при обновлении секции RWW. Невозможно получить доступ к секции RWW, когда она обновляется. Когда обновляется NRWW (к примеру, загрузчик перезаписывает сам себя), CPU останавливается во время всей операции. Другими словами нельзя читать при записи (No-Read-While-Writing, NRWW) на секции NRWW, но можно читать при записи (Read-While-Writing, RWW) на секции RWW. За подробностями обратитесь к даташиту на устройство.

Эта функциональность делает возможным продолжить выполнение критического кода, когда обновляется секция RWW. Имейте в виду, что критический код должен находиться в пределах секции NRWW (необязательно в секции загрузчика). Для подробностей см. раздел с описанием прерываний.

Устройства ATmega163 и ATmega323 не имеют секции NRWW и RWW, в них реализован только выбираемый раздел на секции приложения и загрузчика. Любое обновление памяти Flash приводит к остановке CPU на выполнение всей операции.

Использование инструкции SPM

Операции самопрограммирования производятся с использованием инструкции SPM. Операция выбирается через регистр SPMCR (в некоторых устройствах этот регистр называется SPMCSR). Организация регистра показана на рис. 3.

Рис. 3. Регистр SPMCR.

AVR109-SPMCR-register-fig3

Когда используется функция SPM, бит SPMEN должен быть всегда установлен в предела 4 циклов до выполнения инструкции SPM. Это сделано для предотвращения непреднамеренного обновления FLASH. Программное обеспечение должно убедиться, что не будет вызвано прерывание между установкой бита SPMEN и выполнением инструкции SPM, что превысит лимит времени 4 цикла. Другие 4 подсвеченных на рис. 3 бита выбирают между различными функциями SPM. Бит SPMEN автоматически очищается вместе с битом функции по завершении операции. Функции SPM описаны далее.

Page Erase. Вся память FLASH обновляется страница за страницей. Перед тем, чтобы записать новые данные в страницу, эта страница должна быть очищена.

Прим. переводчика: при очистке страницы все её байты переводятся в значение 0xFF. Очевидно, что если зачем-то нужно поменять на странице только несколько байт, и остальные оставить при этом неизменными, то нужно вычитать данные всей страницы в буфер SRAM, поменять в буфере эти байты, очистить страницу, и потом записать содержимое страницы данными буфера.

Регистр Z используется для выбора очищаемой страницы. Установите значение регистра Z в адрес для указания байта на странице, которая должна быть очищена. Младшие биты адреса байта, которые отвечают за позиционирование байта в пределах страницы, будут проигнорированы. К примеру, на устройствах с размером страницы 32 слова (64 байта) 6 младших бит регистра Z будут проигнорированы.

Прим. переводчика: под регистром Z понимается пара 8-битных регистров R31:R30, рассматриваемая как один 16-битный регистр Z. Регистр Z используется в системе команд для адресации.

Чтобы очистить страницу, запретите прерывания (если они были разрешены), установите биты PGERS и SPMEN в регистре SPMCR, выполните инструкцию SPM и разрешите прерывания (если они были до этого разрешены).

Loading Page Buffer (загрузка буфера страницы). Чтобы записать новые данные на страницу, сначала должен быть заполнен буфер страницы (Page Buffer). Page Buffer это специальный выделенный аппаратный буфер (не SRAM) только для записи, который временно удерживает содержимое страницы. Этот буфер должен быть заполнен пословно, одно слово за другим. Содержимое буфера копируется в память FLASH за одну операцию.

Регистр Z используется для выбора слова, записываемого в буфер. Младший бит (LSB) регистра Z игнорируется, так что за одну операцию всегда записывается слово. Побайтовый доступ невозможен. Старшие биты Z, которые выбирают страницу, также игнорируются при записи в Page Buffer. Структура бит Z-регистра для страницы размером 32 слова (64 байта) показана на рис. 4. У страниц большего размера для выбора слова используется соответственно большее количество бит Z-регистра.

Рис. 4. Запись в буфер страницы (Page Buffer).

AVR109-writing-to-Page-Buffer-fig4

Чтобы записать слово в Page Buffer, загрузите записываемое слово в пару регистров R1:R0. Установите значение Z-регистра для корректного указания адреса слова, и в регистре SPMCR установите только бит SPMEN. Затем выполните инструкцию SPM в пределах 4 тактов.

Page Write. Когда Page Buffer загружен новыми данными, он должен быть записан в память FLASH. Чтобы выполнить это, установите Z-регистр по такому же правилу, как было указано для функции Page Erase. Затем установите биты PGWRT и SPMEN в регистре SPMCR, и выполните инструкцию SPM в пределах 4 циклов. Содержимое регистров R1:R0 игнорируется. Использование Z-регистра для страницы размером 32 слова (64 байта) показано на рис. 5.

Рис. 5. Запись страницы в память FLASH.

AVR109-writing-Page-to-FLASH-fig5

Процесс записи страницы занимает некоторое время, в течение которого нельзя обновлять Page Buffer и выполнять другие инструкции SPM. Для определения завершения операции записи страницы может опрашиваться бит SPMEN. Процедура обновления может также управляться по прерываниям. См. раздел по прерываниям ниже для получения дополнительной информации.

Флаг занятости секции RWW (RWW Section Busy Flag). когда выполняются операции Page Erase или Page Write на секции RWW, то аппаратно устанавливается флаг RWWSB, что показывает недоступность секции. Флаг RWWSB должен быть очищен программно, когда завершится операция SPM. Это делается путем установки битов RWWSRE и SPMEN в регистре SPMCR, за которой нужно выполнить инструкцию SPM в пределах 4 циклов. Альтернативно флаг автоматически очищается при старте загрузки Page Buffer. Флаг RWWSB может использоваться другими частями приложения для проверки - доступна ли в текущем состоянии секция RWW. Для дополнительной информации обратитесь к даташиту на устройство.

Имейте в виду, что при использовании функции RWWSRE содержимое Z-регистра и регистров R1:R0 игнорируется. Также имейте в виду, что если будет произведен доступ к секции RWW без нового разрешения её после операции очистки или записи, то все адреса секции RRW будут читаться как 0xFFFF. Это относится и к чтению FLASH инструкцией LPM, и если делаются вызовы подпрограмм (call) или переходы (jmp) в секцию RWW. В результате, если запустить на выполнение код в секции RWW без разрешения доступа к ней, то будет выполнен программный код "0xFFFF", что в конечном счете приведет к "падению" программного счетчика через пространство кода, пока не будет встречена первая выполняемая инструкция кода. В этом случае первый выполняемый код окажется в по первому адресу секции NRWW.

Boot Lock Bits (биты защиты загрузки). Секции приложения и загрузчика могут быть защищены на различных уровнях. Для каждой секции отдельно имеется 4 уровня защиты. Здесь приведено короткое описание этих режимов защиты.

Таблица 1. Режимы защиты загрузки (Boot Lock Modes).

Режим Биты Описание
Mode 1 11 Полный доступ на чтение и запись.
Mode 2 10 Нет доступа на запись.
Mode 3 00 Нет доступа ни на запись, ни на чтение (нельзя прочитать данные или выполнить код прерывания) из другой секции.
Mode 4 01 Нет доступа на чтение (нельзя прочитать данные или выполнить код прерывания) из другой секции.

Имейте в виду, что как только биты запрограммированы (очищены), невозможно "распрограммировать" их снова без использования последовательного или параллельного программирования (для этой операции нужен отдельный программатор [3]). Например, чтобы реализовать однократное обновление приложения, установите Boot Lock mode 1 для секции приложения, и mode 4 для секции загрузчика. Это предотвратит доступ приложения к загрузчику (Boot Loader), и даст загрузчику полный доступ к обновлению секции приложения. Как только обновление секции приложения завершено, загрузчик должен установить mode 3 на секции приложения, чем заблокировать к ней дальнейший доступ.

Чтобы запрограммировать биты защиты загрузки (Boot Lock bits), загрузите регистр R0 корректными значениями бит, установите биты BLBSET и SPMEN в регистре SPMCR и выполните инструкцию SPM в течение 4 тактов. Содержимое Z-регистра при этом игнорируется. Использование инструкции LPM вместо SPM даст чтение битов.

Что нужно иметь в виду при использовании прерываний

Можно использовать прерывания при записи секции RWW, но программное обеспечение должно предотвратить любой другой доступ к секции RWW. Другими словами, при обновлении секции RWW обработчики прерывания (interrupt service routines, ISR) для выполнения должны быть размещены в секции NRWW, включая вектора прерывания (Interrupt Vectors).

При использовании бита IVSEL в регистре GICR приложение может использовать реализацию двух раздельных таблиц векторов прерываний (Interrupt Vector table). Одна таблица будет находиться в секции приложения, и еще одна в секции загрузчика, используемая при обновлении секции RWW. Это разрешит приложению при самопрограммировании продолжить критические процессы, к примеру контроль безопасности, или поддержку протоколов обмена (по такому принципу работают все бутлоадеры с поддержкой интерфейса USB на библиотеке V-USB, в частности USBasploader и BootloadHID [4, 5]). Для подробностей по прерываниям и флагу IVSEL обратитесь к даташиту на устройство. Если вторичная таблица векторов прерываний не используется, то при обновлении секции RWW прерывания должны быть запрещены.

Прерывание инструкции SPM. На всех устройствах, поддерживающих самопрограммирование, за исключением ATmega163 и ATmega323, можно управлять операциями обновления FLASH с использованием прерываний. Установка бита SPMIE в регистре SPMCR разрешит прерывание SPM ready. Это может использоваться для определения момента завершения текущей операции SPM (вместо поллинга бита SPMEN).

Конфликты EEPROM

Имейте в виду, что все операции записи в EEPROM должны быть завершены до начала выполнения инструкции SPM, и наоборот. Запись/очистка FLASH и EEPROM не могут происходить одновременно.

Типичные процедуры обновления

На рис. 6 показаны два общих варианта реализации процедур обновления программного обеспечения. Алгоритм слева описывает операцию Read-Modify-Write, используемую для обновления маленькой части FLASH, к примеру строки константы, размещенной в памяти FLASH. Алгоритм справа описывает операцию записи страницы, используемой при обновлении целых страниц без предварительного чтения их предыдущего содержания, к примеру для записи данных, принятых через UART.

Рис. 6. Типичные процедуры обновления FLASH.

AVR109-typical-update-flowcharts-fig6

[Пример реализации бутлоадера]

Программа загрузчика (Boot Loader), представленная в этом апноуте, использует в качестве управляющей утилиты AVROSP [2]. Эта утилита реализует консольный интерфейс с пользователем. Пример загрузчика реализует функции для чтения или обновления областей памяти FLASH и EEPROM на целевом устройстве (target device. Под этим термином понимается микроконтроллер, на котором работает загрузчик). Загрузчик также позволяет читать и обновлять биты защиты (Lock bits) и читать биты фьюзов (Fuse bits) на целевом устройстве.

Совместимость с AVRProg

Совместимость с AVRProg (это утилита оболочки программатора Atmel, поставляемая в составе AVR Studio) основывается на кодах устройств, которые не определены для всех устройств. Файл preprocessor.xls содержит заданные коды устройств, но некоторые из них пока не реализованы в исполняемом файле AVRProg. Для такого случая используйте код устройства, у которого такие же размеры памяти FLASH и/или EEPROM. AVROSP, с другой стороны, полагается только на байты сигнатуры, и по этой причине он может программировать все устройства, у которых есть возможность самопрограммирования.

Протокол обмена

Протокол, используемый программой загрузчика, является подмножеством протокола, определенного для AVRProg. Список поддерживаемых команд показан в таблице 2. Все команды начинаются с одиночной буквы. Программатор возвращает десятичный код 13 (возврат каретки) или запрошенные данные после завершения команды. На неизвестные команды выдается ответ "?".

Таблица 2. Команды AVRProg.

Описание команды Хост записывает Хост читает
ID Data Data
Вход в режим программирования (Programming Mode) P 13
Автоинкремент адреса a 0xDD
Установить адрес (Set Address) A ah al 13
Запись памяти программ (Write Program Memory), младший байт c dd 13
Запись памяти программ (Write Program Memory), старший байт C dd 13
Записать страницу (Page Write) m 13
Прочитать биты защиты (Read Lock Bits) r dd
Прочитать память программ (Read Program Memory) R 2*dd
Прочитать память данных (Read Data Memory) d dd
Записать память данных (Write Data Memory) D dd 13
Стирание памяти чипа (Chip Erase) e 13
Записать биты защиты (Write Lock Bits) l dd 13
Прочитать биты фьюзов (Read Fuse Bits) F dd
Прочитать старший байт фьюзов (Read High Fuse Bits) N dd
Прочитать байт расширенных фьюзов (Read Extended Fuse Bits) Q dd
Выйти из режима программирования (Leave Programming Mode) L 13
Выбрать тип микроконтроллера (Select Device Type) T dd 13
Прочитать байты сигнатуры (Read Signature Bytes) s 3*dd
Вернуть коды поддерживаемых микроконтроллеров (Return Supported Device Codes) t n*dd 0
Вернуть идентификатор программного обеспечения firmware (Return Software Identifier) S s[7]
Вернуть версию программного обеспечения firmware (Return Software Version) V dd dd
Вернуть тип программатора (Return Programmer Type) p dd
Установить состояние светодиода (Set LED) x dd 13
Очистить светодиод (Clear LED) y dd 13
Выйти из бутлоадера (Exit Bootloader) E 13
Проверить поддержку блоков (Check Block Support) b "Y" 2*dd
Запуск загрузки блока FLASH (Start Block Flash Load) B 2*dd "F"
n*dd
13
Запуск загрузки блока EEPROM (Start Block EEPROM Load) B 2*dd "E"
n*dd
13
Запуск чтения блока FLASH (Start Block Flash Read) g 2*dd "F" n*dd
Запуск чтения блока EEPROM (Start Block EEPROM Read) g 2*dd "E" n*dd

Описание программы загрузчика

Основная программа загрузчика [6] начинает работу с проверки - нужно ли запустить процедуру программирования, или нужно запустить код из секции приложения. В этом примере выбор основывается на проверке значения порта PIND. Если заданная пользователем ножка порта D после сброса удерживается в состоянии лог. 0, то программа загрузчика перейдет в режим программирования (Programming mode). Если не на этой ножке лог. 1, то выполнение программы начнется с адреса 0x0000 (как если бы произошел обычный сброс). По такому же принципу запускается и загрузчик USBasploader [4].

В Programming mode программа загрузчика принимает команды, которые поступают через UART от утилиты AVROSP. Каждая команда выполняет связанную с ней задачу. Любая команда, которая не распознана загрузчиком, выдает в ответ программе AVROSP символ "?". Для получения инструкций - как перекомпилировать загрузчик (bootloader) для различных устройств AVR и различных размеров секции загрузки (boot section), обратитесь к пошаговым инструкциям в файле preprocessor.xls [6] (формат Microsoft Excel).

Main.c. Модуль main.c программы загрузчика обрабатывает обмен с хостом PC и выполняет принятые от него команды. Рис. 7 показывает алгоритм функционирования main.c.

Рис. 7. Как работает main.c(1).

AVR109-Main-Program-Execution-fig7

Примечание 1: как показано на рис. 7, если был произведен вход в программу загрузчика (активен режим Programming mode), то есть только один способ выхода отсюда - сброс устройства.

Serial.c. Модуль UART (serial.c) реализует простые подпрограммы UART, работающие по принципу опроса (polling). Как уже было описано ранее, причина такой реализации в том, что прерывания не разрешены в секции загрузки (Boot section) для некоторых установок бит защиты загрузки (Boot Lock).

[Ссылки]

1. AVR109: Using Self Programming on tinyAVR and megaAVR devices site:atmel.com.
2. AVR911: Open Source программатор для микроконтроллеров AVR.
3. Программаторы для AVR.
4. AVR-USB-MEGA16: USB bootloader USBasp для микроконтроллера ATmega32.
5. AVR-USB-MEGA16: USB bootloader BootloadHID для микроконтроллера ATmega16.
6. AVR109.zip - исходный код загрузчика, проекты для GCC и IAR.

 

Комментарии  

 
0 #1 Самохвалов Сергей Ва 21.09.2021 13:27
Скачал исходный код загрузчика AVR109 для IAR. Настроил под Atmega2561, всё отлично работает. Под atmega32 адаптировал - ничего не получается. Даже ассемблером пробовал менять lock-биты командой SPM - на Atmega2561 работает, а на atmega32 - нет. Две недели бьюсь. Нужен результат. Помогите! У нас до сих пор эти ATmega32 много где применяются и надо бы иметь возможность удалённо менять прошивки.

microsin: особенности применения инструкции SPM зависят от конкретного микроконтроллер а. У Atmega2561 и ATmega32 они могут отличаться, вероятно поэтому в Вашем случае не работает изменение бит защиты у ATmega32.

Вот что написано по этому поводу в даташите на ATmega32:

«Program Flash memory space is divided in two sections, the Boot program section and the Application Program section. Both sections have dedicated Lock bits for write and read/write protection. The SPM instruction that writes into the Application Flash memory section must reside in the Boot Program section.»

Короче говоря, если SPM выполняется не из области памяти загрузчика, то поменять биты защиты не получится. Проверьте, где находится код, который должен менять биты защиты.
Цитировать
 

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


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

Top of Page