AVR109
Самопрограммирование
Характеристики:
- Код примера применения AVR109 помещается в загрузочном блоке любого AVR микроконтроллера
- Чтение и запись EEPROM и Flash памяти
- Использует протокол AVRProg
- Чтение и запись битов защиты
Введение
В данном примере применения описывается как настроить AVR микроконтроллеры для самопрограммирования при помощи команд сохранения памяти программы (SPM). AVR микроконтроллеры могут связываться через UART с персональными компьютерами, на которых запущена программа программирования AVRprog. Она позволяет программировать микроконтроллеры с Flash и EEPROM памятью без помощи внешнего аппаратного программатора.
Программа загрузчика находится в загрузочной области Flash памяти. Эта программа устанавливает связь с ведущим персональным компьютером и облегчает программирование Flash и EEPROM памяти микроконтроллера. Однажды запрограммированные различные уровни защиты могут быть индивидуально применены для программирования загрузочной памяти и Flash памяти прикладной программы. Таким образом, AVR микроконтроллеры имеют уникальную возможность обеспечения различной степени защиты областей встроенной памяти.
Обсуждение SPM
Ниже приведены различные рассуждения, позволяющие лучше понять способность самопрограммирования AVR микроконтроллеров.
Организация памяти
Flash память AVR микроконтроллеров разделена на две области: секция прикладной программы и секция программы загрузчика. Область прикладной программы содержит код основной прикладной программы, а область загрузчика содержит код программы, позволяющей осуществлять самопрограммирование микроконтроллера. SPM команды могут выполняться только из области загрузчика. (Замечание: тем не менее, область загрузчика может использоваться в качестве обычной памяти прикладной программы).
Flash память разделена на страницы, каждая из которых содержит 32, 64 или 128 слов. Назначение и использование страниц будет объяснено позже. Вся память (и память прикладной программы и память загрузчика) разделена на страницы. Например, микроконтроллер с 8 килобайтами Flash памяти и размером страницы 32 слова (64 байта) будет иметь 128 страниц. Организация памяти показана на рисунке 1.
Рисунок 1. Организация памяти
Размер области памяти загрузчика может быть установлен при помощи двух специальных конфигурационных бит BOOTSZx. Они позволяют выбрать один из четырех возможных размеров области памяти загрузчика. Установить биты BOOTSZx можно при помощи последовательного или параллельного программатора. Более подробно это рассмотрено в технических описаниях AVR микроконтроллеров.
Если загрузчик реализован, то он может быть вызван путем выполнения команд Call или Jump из прикладной программы или путем установки бита специального конфигурационного бита BOOTRST. Если бит BOOTRST установлен, то после каждого сброса микроконтроллер вместо перехода к выполнению программы, начинающейся с нулевого адреса памяти прикладной программы, выполняет программу загрузки, находящуюся в области загрузчика. Изменен бит BOOTRST может быть при помощи параллельного или последовательного программатора.
Возможность "чтения при записи"
В дополнение к выбираемому делению памяти на прикладную и загрузочную, встроенная Flash память также разделена на два раздела с фиксированными размерами. Первый раздел - "читаемый при записи" (RWW) раздел. Второй - "не читаемый при записи" (NRWW) раздел. Размер NRWW раздела всегда равняется размеру наибольшей возможной области памяти загрузчика. Поэтому раздел загрузчика занимает весь NRWW раздел или только его часть. Деление памяти на RWW и NRWW разделы показано на рисунке 2.
Рисунок 2. Деление памяти на RWW и NRWW разделы
Отличие между этими разделами состоит в том, что NRWW секция доступна при обновлении RWW секции. К RWW секции невозможно обратиться при обновлении. Когда NRWW секция обновляется (например, обновляя непосредственно код загрузчика), вычислительное ядро останавливается. Другими словами, невозможно осуществлять чтение при записи NRWW секции, но возможно читать при записи RWW секции. Более подробно это рассмотрено в технических описаниях на микроконтроллеры.
Эти функциональные возможности позволяют продолжить выполнение прикладной программы при обновлении RWW секции. Обратите внимание, что код этой программы должен содержаться в NRWW секции (не обязательно в разделе загрузчика). Более подробно это рассмотрено ниже в разделе описания прерываний.
Микроконтроллеры ATmega163 и ATmega323 не имеют NRWW и RWW секций - у них имеются только деление на память загрузчика и память прикладной программы. Любое обновление Flash памяти этих микроконтроллеров приводит к остановке их вычислительного ядра.
Использование SPM команды
Все действия по самопрограммированию выполняются при помощи SPM команды. Выбор режима осуществляется при помощи регистра SPMCR. Структура этого регистра показана на рисунке 3.
Рисунок 3. Регистр SPMCR
При использовании SPM функции бит SPMEN должен быть установлен не ранее, чем за четыре цикла до выполнения команды SPM. Это необходимо для предотвращения несанкционированного обновления Flash памяти. Прикладная программа должна гарантировать отсутствие вызова подпрограмм обработки прерывания между установкой бита SPMEN и выполнением SPM команды. Другие, выделенные цветом на рисунке, четыре бита осуществляют выбор режима SPM. По окончании режима бит SPMEN автоматически сбрасывается вместе с функциональным битом.
SPM функции описаны ниже.
Стирание страницы
Вся Flash память обновляется страницами. Перед записью новых данных страница должна быть стерта.
Для выбора страницы, подлежащей стиранию, используется Z регистр. Он предназначен для указания номера стираемой страницы. Младшие биты, выбирающие слово на странице, игнорируются. Например, в микроконтроллере, имеющем размер страницы 32 слова (64 байта), игнорируются шесть младших бит Z регистра.
Для того чтобы стереть страницу необходимо установить биты PGERS и SPMEN в регистре SPMCR и выполнить команду SPM.
Загрузка буфера страниц
Перед записью новых данных в страницу необходимо сначала стереть буфер страниц. Буфер страниц - это доступный только для записи отдельный буфер, не относящийся к ОЗУ, который содержит одну временную страницу. Страницы в него должны заноситься последовательно. Перезапись буфера страниц во FLash память происходит за одну операцию.
Для выбора слова, которое будет записано в буфер, используется Z регистр. МЗБ Z регистра игнорируются так как запись всех слов происходит за одну операцию. Таким образом невозможно выбрать только один байт. При записи буфера страниц игнорируются старшие биты Z регистра. Структура Z регистра для микроконтроллера с 32 словными (64 байтовыми) страницами показана на рисунке 4. Микроконтроллеры, имеющие большие размеры страницы для выбора слов используют больше бит.
Рисунок 4. Запись в буфер страниц
Чтобы записать слово в буфер страниц необходимо загрузить его в регистры R1:R0. Для записи необходимо только записать правильное слово и установить бит SPMEN в регистре SPMCR. В течение четырех циклов после этого должна быть выполнена SPM команда.
Запись страницы
Данные после того, как они были загружены в буфер страниц, должны быть записаны во Flash память. Для выполнения этого необходимо, как это было описано выше в пункте описания алгоритма стирании страницы, установить Z регистр. Затем устанавливаются биты PGERS и SPMEN в регистре SPMCR, а потом в течение четырех циклов необходимо запустить SPM команду. Содержимое регистров R1:R0 при этом игнорируется. Использование Z регистра для микроконтроллера с 32 словными (64 байтными) страницами показано на рисунке 5.
Рисунок 5. Запись страницы во Flash память
Для определения готовности микропроцессора к следующему обновлению необходимо опрашивать бит SPMEN. Процедура обновления может быть прервана управляющим прерыванием. Более подробно это рассмотрено ниже в разделе описания прерываний.
RWW секция флагов занятости
При записи и стирании страниц RWW секции аппаратно устанавливается флаг RWWSB, указывая на то, что секция недоступна. Флаг RWWSB должен быть сброшен программно по окончании SPM режима. Это выполняется установкой битов RWWSRE и SPMEN в регистре SPMCR и последующим запуском SPM команды. Также этот флаг может быть сброшен путем запуска загрузки буфера страниц. Флаг RWWSB может использоваться другими частями прикладной программы для контроля доступности RWW секции. Более подробно это рассмотрено в технических описаниях на микроконтроллеры.
Обратите внимание, что содержимое Z регистра и регистров R1:R0 игнорируется при использовании RWWSRE функции.
Также следует заметить, что, если после выполнения операции записи или считывания RWW секция стала доступна без переактивизации, то все адреса в RRW секции считываются как 0xFFFF. Так будет и после считывания Flash памяти при помощи LPM и после выполнения вызова или перехода в RWW секцию. Переход в RWW секцию без предварительной ее переактивизации приведет к тому, что выполнится команда, находящаяся по адресу 0xFFFF, а все предшествующие ей команды, которые должны были быть выполнены, будут пропущены.
Биты блокировки загрузки
Секции прикладной программы и программы-загрузчика могут быть защищены на различных уровнях. Для обоих разделов имеется четыре уровня защиты. Краткое описание этих режимов приведено в таблице 1.
Таблица 1. Режимы блокировки загрузки
Режим |
Биты |
Описание |
Режим 1 |
11 |
Полный доступ для чтения - записи |
Режим 2 |
10 |
Нет доступа для записи |
Режим 3 |
00 |
Нет доступа для записи и нет доступа для чтения (данные или обработка прерывания) из других секций |
Режим 4 |
01 |
Нет доступа для чтения (данные или обработка прерывания) из других секций |
Обратите внимание, что все эти биты могут изменяться только при помощи последовательного или параллельного программатора. Например, для микроконтроллера, прикладная программа которого будет обновляться, необходимо установить режим 1 для секции прикладной программы и режим 4 для секции загрузчика. Это препятствует доступу к программе загрузчика из прикладной программы и обеспечивает загрузчику возможность доступа к секции прикладной программы. После обновления загрузчик установит третий режим для прикладной программы, что заблокирует дальнейший доступ к ней.
Для программирования битов блокировки загрузки необходимо загрузить соответствующие данные в регистр R0, установить биты BLBSET и SPMEN в регистре SPMCR и в течение четырех циклов выполнить команду SPM. Содержимое Z регистра при этом игнорируется.
Использование LPM команды вместо SPM команды позволит считать биты.
Прерывание
При записи RWW секции возможно использование прерывания, но подпрограмма обработки прерывания не должна выбирать другую RWW секцию. Другими словами, подпрограммы обработки прерывания, включая векторы прерываний, которые будут выполняться при обновлении RWW секции, должны размещаться в NRWW секции.
Для выбора двух различных таблиц векторов прерывания прикладная программа должна использовать бит IVSEL регистра GICR. При обновлении RWW секции должна использоваться одна секция прикладной программы и одна секция программы-загрузчика. Это позволяет прикладной программе продолжать критические процессы типа отслеживание политики безопасности при самопрограммировании. Более подробно это рассматривается в технических описаниях на микроконтроллеры в разделе описания прерываний и IVSEL флага.
Если второй вектор прерываний не используется, то при обновлении RWW секции прерывания должны быть отключены.
SPM прерывание
У всех микроконтроллеров, поддерживающих режим самопрограммирования, за исключением микроконтроллеров ATmega163 и ATmega323, при помощи прерываний возможно контролировать процесс обновления Flash памяти. Установка бита SPMIE в регистре SPMCR позволит формировать SPM прерывание. Оно может использоваться для отслеживания окончания режима SPM.
Конфликты EEPROM памяти
Обратите внимание, что все операции записи EEPROM должны быть окончены перед выполнением SPM команды и наоборот. Запись/стирание Flash и EEPROM памяти не может происходить одновременно.
Типовые процедуры обновления
На рисунке 6 показаны две стандартные процедуры обновления. Левая блок - схема на этом рисунке описывает алгоритм "считывания-модификации-записи" небольших частей Flash памяти, например, констант, содержащихся во Flash памяти. Правая блок-схема описывает алгоритм записи страницы, использующийся для записи страницы без предварительного считывания ее содержимого, например, запись данных, поступивших от UART.
Рисунок 6. Блок-схемы стандартных процедур обновления
Пример программы-загрузчика
Пример программы- загрузчика, приведенный в данном примере применения, в качестве пользовательского интерфейса использует программу AVRprog, доступную на сайте www.atmel.com. Эта программа-загрузчик позволяет считывать или обновлять Flash и EEPROM память выбранного микроконтроллера. Также она позволяет считывать и обновлять биты Lock и Fuse.
Протокол
Протокол, использованный в примере программы-загрузчика, предназначен для работы с программатором AVRprog, хотя программа-загрузчик и не поддерживает всего набора команд. Перечень поддерживаемых команд приведен в таблице 2. Все команды начинаются с одной буквы. После выполнения команды программатор возвращает значение 13d (возврат каретки) или требуемые данные. Неизвестным командам возвращается значение «?».
Таблица 2. Команды AVRProg
Команда |
Запись ведущим |
Считывание ведущим |
ID |
Данные |
Данные |
|
Вход в режим программирования |
«P» |
|
|
13d |
Автоматическое увеличение адреса |
«a» |
|
dd |
|
Установка адреса |
«A» |
ah al |
|
13d |
Запись младшего байта в память программы |
«c» |
dd |
|
13d |
Запись старшего байта в память программы |
«C» |
dd |
|
13d |
Окончание записи страницы |
«m» |
|
|
13d |
Считывание битов Lock |
«r» |
|
dd |
|
Считывание памяти программы |
«R» |
|
dd (dd) |
|
Считывание памяти данных |
«d» |
|
dd |
|
Запись памяти данных |
«D» |
dd |
|
13d |
Стирание кристалла |
«e» |
|
|
13d |
Запись битов Lock |
«l» |
dd |
|
13d |
Запись битов Fuse |
«f» |
dd |
|
13d |
Считывание битов Fuse |
«F» |
|
dd |
|
Считывание старших битов Fuse |
«N» |
|
dd |
|
Выход из режима программирования |
«L» |
|
|
13d |
Выбор типа микроконтроллера |
«T» |
dd |
|
13d |
Считывание байтов подписи |
«s» |
|
3*dd |
|
Возвращение кода поддерживаемого микроконтроллера |
«t» |
|
n* dd |
00d |
Возвращение идентификатора программы |
«S» |
|
s[7] |
|
Возвращение версии программы |
«V» |
|
dd dd |
|
Возвращение версии аппаратных средств |
«v» |
|
dd dd |
|
Возвращение типа программатора |
«p» |
|
dd |
|
Включение светодиода |
«x» |
dd |
|
13d |
Выключение светодиода |
«y» |
dd |
|
13d |
При выполнении AVRprog.exe отыскивает на любом доступном СОМ порту любой поддерживаемый программатор. Для связи используется 19.2 кбит/с интерфейс формата 8N1 (8 информационных разрядов, нет проверки на четность и один стоповый бит). Поэтому UART приемника также должен быть настроен на работу с этой скоростью и в этом режиме.
При работе с микроконтроллером ATmega161, последовательность действий при определении программатора следующая:
AVRprog:4 'ESC': очистка буферов UART.
AVRprog:'S' - запрос идентификатора программы
MegaAVR:'AVRB161' (загрузчик). AVRprog принимает любую строку,
состоящую из семи символов и начинающуюся с букв 'AVR'.
AVRprog:'a' -запрос на автоматическое увеличение адреса
megaAVR:'y' - Да
AVRprog:'t' - запрос о поддерживаемых микроконтроллерах
megaAVR: '60' для mega161 и '00' для указания конца списка
AVRprog:'T 'и' 60' - указание программатору, что выбран микроконтроллер ATmega161
AVRprog:'y '+dd 'y' +dd 'y' + dd 'x' +dd - активизация светодиодов
Последовательность команд при программировании:
AVRprog:3 'ESC': очистка буферов UART.
AVRprog:'T 'и' 60' - указание программатору, что выбран микроконтроллер ATmega161
AVRprog:'P' - разрешение программирования
AVRprog:'e' - стирание области прикладной программы
AVRprog:'P' - разрешение программирования
AVRprog:'A' - установка адреса 0x0000
AVRprog:'A' - установка начального адреса программирования
AVRprog:'c' - передача младшего байта данных
AVRprog:'C' - передача старшего байта данных
При заполнении временного буфера:
AVRprog:'A' - установка адреса страницы
AVRprog:'m' - запись страницы
После этого продолжается программирование:
AVRprog:'c' - передача младшего байта данных
AVRprog:'C' - передача старшего байта данных
После того, как все байты переданы, выполняются следующие команды:
AVRprog:'A' - установка адреса последней страницы
AVRprog:'m' - запись последней страницы
AVRprog:'L' - выход из режима программирования
Последовательность команд при проверке данных:
AVRprog:'P' - разрешение программирования
AVRprog:'A' - установка адреса
AVRprog:'R' - чтение памяти программы
ATmega161: двухбайтные данные.
AVRprog продолжает посылать «R» до тех пор, пока не будут считаны все данные, после чего посылается «L» для выхода из режима программирования.
Описание программы
Основная программа запускается для контроля выполнения программирования или если должна быть выполнена программа их секции прикладной программы. В данном применении это определяется значением PIND. Если на определенном пользователем выводе порта D при сбросе присутствует низкий логический сигнал, то программа войдет в режим программирования (вывод определяется в исходном тексте main.c). Если на этом выводе был высокий уровень, то программа начнет выполняться с адреса 0000$ (как при обычном сбросе).
В режиме программирования управляющая программа получает команды от AVRprog через UART. Каждая команда активизирует выполнение соответствующей задачи. Эта программа не использует команды управления работой светодиода, но они реализованы для того, чтобы избежать потери синхронизации программатором AVRprog. Любая команда, которая не распознается программой, приводит к возврату программатору AVRprog символа "?".
Main.c
Программа main.c устанавливает связь с ведущим персональным компьютером и выполняет полученные команды. На рисунке 7 наказана блок-схема алгоритма работы этой программы.
Рисунок 7. Блок-схема алгоритма работы основной программы
Обратите внимание, что выход из этой программы возможен только через сброс микроконтроллера.
Serial.c
Программа UART (serial.c) всего-навсего осуществляет опрос подпрограммы UART. Как было сказано ранее, причина необходимости периодического опроса этой подпрограммы состоит в том, что при некоторых настройках битов блокировки загрузки в программе загрузчика прерывания не разрешены.
Assembly.s90
Все подпрограммы, использующие SPM, написаны на ассемблере. Это сделано для того, чтобы избежать конфликтов в коде. SPM команды требуют помещать данные в Z регистр (r31:r30) и в пару регистров r1:r0. Это можно реализовать и на С, но на ассемблере проще реализовать контроль, а также позволяет снизить перегруженность С кода.
Вызов процедуры Assembly
В зависимости от того, какие параметры переданы при вызове процедуры Assembly, она выполняет одну из двух функций:
пусто write_page (беззнакое целочисленное значение адреса, беззнаковое строковое значение функции);
Первый передаваемый параметр - это адрес страницы, которую необходимо записать. Второй параметр определяет функцию, должна выполниться. Если передать значение 0x05, то произойдет запись указанной страницы, а если 0x03, то стирание ее.
беззнаковое целочисленное значение read_program_memory (беззнаковое целочисленное
значение адреса, беззнаковое строковое значение функции);
В этой подпрограмме первый параметр - это адрес страницы, которую необходимо считать. Второй параметр указывает функцию, которая будет выполнена. Если передать значение функции 0x00, то подпрограмма вернет данные, находящиеся по указанному адресу. Если в качестве второго параметра передать значение 0x09, а в качестве адреса 0x0000, 0x0001 или 0x0003, то подпрограмма вернет значения битов Fuse, Lock Bit или Fuse High. В этом случае, основная программа игнорирует 8 старших значащих битов возвращенного целого числа.
Ниже приведен листинг подпрограммы Assemly.
NAME assembly(16)
RSEG CODE(0)
RSEG UDATA0(0)
PUBLIC fill_temp_buffer
PUBLIC write_page
PUBLIC write_lock_bits
PUBLIC read_program_memory
EXTERN ?CL0T_1_40_L08
RSEG CODE
#include "iom161.h"
write_page:
MOV R31,R17
MOV R30,R16 ; передача адреса в z регистр (R31=ZH R30=ZL)
OUT SPMCR,R20 ; установка параметра, соттвтетствующего вызову второй функции
SPM ; выполнить запись страницы
RET
fill_temp_buffer:
MOV R31,R21
MOV R30,R20 ; передача адреса в z регистр (R31=ZH R30=ZL)
MOV R1,R17
MOV R0,R16 ; передача данных в регистры 0 и 1
LDI R18,0x01
OUT SPMCR,R16
SPM ; Запись в память программы
RET
read_program_memory:
MOV R31,R17 ; R31=ZH R30=ZL
MOV R30,R16 ; передача адреса в z регистр
SBRC R20,0 ; считать биты защиты? (второй аргумент = 0x09)
OUT SPMEN,R20; если "Да", то установить второй аргумент в регистре SPMEN
LPM ; считывание МЗБ
MOV R16,R0
INC R30
LPM
MOV R17,R0 ;считывание СЗБ (игнорируется при чтении бита защиты)
RET
write_lock_bits:
MOV R0,R16
LDI R17,0x09
OUT SPMCR,R17
SPM ; запись битов защиты
RET
END
Специальные замечания
- В микроконтроллерах ATmega161 и ATmega163 секция программы-загрузчика располагается в памяти начиная с адреса $3C00 по адрес $3FFF, поэтому файл компоновщика должен изменить программу таким образом, чтобы она расположилась в этой области. Для этого необходимо заменить значение строки "Program address space" на следующее значение:
// Program address space (internal Flash memory)
-Z(CODE)INTVEC,RCODE,CDATA0,CDATA1,CCSTR,SWITCH,
FLASH,CODE=3C00-3FFF
В результате этого код будет расположен в загрузочном блоке. Кроме того, для задания адреса вектора сброса $1E00 Fuse бит BOOTRST должен быть установлен.
- Подпрограмма загрузчика должна иметь возможность определения режима, в котором должен работать микроконтроллер после сброса (режим программирования или режим выполнения прикладной программы).
Это реализуется путем проверки состояния определенного вывода при сбросе. Если все выводы находятся в высоком состоянии, то программа-загрузчик осуществляет переход к выполнению основной программы. Реализовано это может быть на С при помощи следующей последовательности команд:
пусто (*funcptr) (пусто) = 0x0000; // установка указателя функции
funcptr (); // переход по указанному адресу
- Если на определенном пользователем выводе при сбросе присутствует низкий уровень, то осуществляется вход в режим программирования. Из режима программирования выйти невозможно. Чтобы вернуться в нормальный режим на этом выводе должен быть установлен высокий уровень и осуществлен сброс микроконтроллера.
- При определенном состоянии битов защиты загрузки при выполнении команд из Flash памяти загрузочной секции могут быть недоступны прерывания. По этой причине, программа UART, реализованная в описанной демонстрационной программе, использует периодический опрос вместо подпрограммы обслуживания прерываний.
- Для указания адреса страницы/адреса временного буфера при выполнении SPM команды используется Z регистр. Также этот регистр используется как указатель данных С компилятором IAR. Это вызывает конфликты. Поэтому все подпрограммы, имеющие дело с SPM, написаны на ассемблере.
- Для увеличения непосредственного контроля требуется усложнять процедуры, написанные на С. Это еще одна причина написания подпрограмм, выполняющих SPM, на ассемблере.
- Размер программы равняется 504 байтам, поэтому она может быть расположена только в микроконтроллерах, имеющих размер загрузочного сектора 512 байт или больше.
Чтобы уменьшить размер кода, необходимо произвести оптимизацию в соответствии с приведенными ниже рекомендациями:
- Использовать конструкцию if, then, else вместо команды case.
- Использовать конструкцию For (;;) {} вместо while (1) {}.
- В файле CSTARTUP.S90 все неиспользованные ссылки были удалены. Это относится к ссылкам " __ low_level_init", команде "#if #endif" и модулю C _EXIT .
- Все переменные должны иметь наименьший возможный размер.
- По возможности использовать беззнаковые переменные.
Более подробно ознакомиться с повышением эффективности кода, написанного на С можно в примере применения "AVR035: Efficient C Coding for AVR".
Ссылки по теме:
|
|
121 Kb Engl AVR308 Исходный фаил |
|
|
Пример программы |
|