Перенос программы между разными моделями

Перенос программы между разными моделями

Иногда может возникнуть необходимость в переносе программы с одной модели AVR на другую. Если под рукой находится исходный текст, то в этом нет ни какой проблемы. Другое дело, когда в распоряжении имеется только 16-тиричный hex-файл. В этом случае можно воспользоваться описанным ниже способом, затратив лишь немного времени на доработку программы.

Сразу необходимо оговорится, что подобное возможно только в том случае если перенос программного обеспечения производится на микроконтроллер с объемом FLASH-памяти превышающем исходный как минимум в два раза. Модели должны быть также совместимы на уровне РВВ, используемых в программе. В значительной степени все вышесказанное относится, например, к моделям ATmega8535, ATmega16, ATmega32 и др. В дальнейшем все примеры будут относиться к переносу программы с ATmega8535 на ATmega16.

Рис.1 Выполнение кода, предназначенного для ATmega8535,

в адресном пространстве модели ATmega16

Непосредственному выполнению программного кода в адресном пространстве нового процессора помешают два обстоятельства. Первое из них это несоответствие между таблицами векторов прерывания. В пределах целого семейства не существует двух микроконтроллеров, у которых адреса векторов совпадают. Кроме того и размеры самих таблиц у всех моделей различны. Вторая, значительно более серьезная проблема, проявляется в искаженном действии инструкций rjmp k, rcall k, brbs k, brbc k и всех остальных, осуществляющих относительные переходы (относительно текущего значения программного счетчика) в памяти программ. Понять это можно, если взглянуть на рис.1. На нем изображено адресное пространство памяти программ микроконтроллеров ATmega8535 и ATmega16. Допустим, что в слове программ под номером 0x0E00 встретится инструкция rjmp PC+0x0400. К программному счетчику при этом будет добавлено смещение 0x0400, в результате чего произойдет относительный переход по новому адресу. Очевидно, что этим адресом будет являться 0x0E00+0x0400 = 0x0200. Переполнение 0x1000 у 12-разрядного программного счетчика программ ATmega8535 будет отброшено. Совсем иначе обстоит дело с микроконтроллером ATmega16, у которого на борту расположено 8192 16-разрядных слова программ и, соответственно, 13-битный счетчик команд. Переполнение в этом случае не произойдет и после перехода rjmp PC+0x0400 программа продолжит свое выполнение с команды по адресу 0x1200. Функционирование устройства будет нарушено.

Проблема с несоответствием векторов прерываний решается достаточно легко. У AVR-микроконтроллеров положения вектора сброса и таблицы прерываний могут быть перемещены в область загрузчика

.cseg .org LARGEBOOTSTART jmp initial ;начало основной прграммы jmp 0x0001 ;внешнее прерывание 0 ATmega8535 jmp 0x0002 ;внешнее прерывание 1 ATmega8535 jmp 0x0003 ;совпадение TCNT2 и OCR2 ATmega8535 jmp 0x0004 ;переполнение TCNT2 ATmega8535 jmp 0x0005 ;захват в ICP1 ATmega8535 jmp 0x0006 ;совпадение TCNT1 и OCR1A ATmega8535 jmp 0x0007 ;совпадение TCNT1 и OCR1B ATmega8535 jmp 0x0008 ;переполнение TCNT1 ATmega8535 jmp 0x0009 ;переполнение TCNT0 ATmega8535 jmp 0x000A ;прерывание от модуля SPI ATmega8535 jmp 0x000B ;получение байта по USART ATmega8535 jmp 0x000C ;опустошение UDR в USART ATmega8535 jmp 0x000D ;передача байта по USART ATmega8535 jmp 0x000E ;прерывание от АЦП ATmega8535 jmp 0x000F ;завершение записи в EEPROM ATmega8535 jmp 0x0010 ;прерывание от компаратора ATmega8535 jmp 0x0011 ;прерывание от модуля TWI ATmega8535 jmp 0x0012 ;внешнее прерывание 2 ATmega8535 jmp 0x0013 ;совпадение TCNT0 и OCR0 ATmega8535 jmp 0x0014 ;завершение выполнения spm ATmega8535 initial: ldi R16,1 << IVCE ;таблицу векторов прерывания out GICR,R16 ;переносим в область загрузчика ldi R16,1 << IVSEL out GICR,R16 jmp 0 ;переходим на начало программы

Для этого необходимо сбросить FUSE-бит BOOTRST. Биты BOOTSZ1: BOOTSZ0 будут определять размер Boot Loader Section (см. разд. Самопрограммирование AVR). В данном примере BOOTSZ1:BOOTSZ0=00 (размер загрузочной секции 1024 слова, сброс по адресу LARGEBOOTSTART=0x1C00). 

Таким образом, каждый раз после запуска устройства программа будет стартовать по адресу 0x1C00 и начинаться с метки initial. Последовательность следующих пяти команд фиксирует таблицу векторов прерывания в области загрузчика и передает управление на начало основной программы с нулевого адреса.

Допустим, в ходе работы устройства в основной программе возникает прерывание от переполнения таймера-счетчика 0. Процессор перейдет на обработчик прерывания по адресу 0x1C12, что соответствует положению вектора прерывания от таймера 0 для модели ATmega16. Слово программ 0x1C12 должно содержать инструкцию перехода на адрес соответствующего вектора в основной программе для модели ATmega8535 (в данном случае jmp 0x0009). Тоже самое касается и всех остальных векторов из области загрузчика. 

Теперь рассмотрим, как можно исправить действия  различного рода инструкций относительного перехода. Для этого все свободные адреса с 0x1000 по 0x1FFF в памяти программ ATmega16 “забиваются” командами вызова подпрограммы new_adr:

.cseg .org 0x1000 . rcall new_adr rcall new_adr rcall new_adr . .org 0x1800 new_adr: push R16 in R16,SREG push R16 push ZH push ZL in ZH,SPH in ZL,SPL ldd R16,Z+6 subi R16,low(0x1001) std Z+6,R16 ldd R16,Z+5 sbci R16,high(0x1001) std Z+5,R16 pop ZL pop ZH pop R16 out SREG,R16 pop R16 ret rcall new_adr rcall new_adr . rcall new_adr

Смысл подпрограммы new_adr заключается в следующем. Когда возникнет  ошибочный переход в запрещенное адресное пространство, например, переход по адресу 0x1200 вместо 0x0200, то после вызова rcall new_adr адрес возврата 0x1201 (возврат на следующую команду) будет сохранен в стеке. В теле new_adr этот адрес (размещается в SRAM) подлежит коррекции. В нашем случае из него нужно вычесть смещение 0x1001. После завершения new_adr программа продолжит свое выполнение не с команды по адресу PC = 0x1201, а с нового места PC = 0x1201 – 0x1001 = 0x0200.

Подпрограмма new_adr должна находится по адресу 0x1800, чтобы быть в пределах досягаемости инструкций rcall k (±2047 слов).

В файле m8535to16.asm находится полный текст программы, а в m8535to16.hex, соответственно исполняемый код. Если возникнет необходимость в переносе программы с ATmega8535 на ATmega16, то в любом текстовом редакторе к исходному hex-файлу нужно присоединить файл m8535to16.hex и загрузить новую прошивку в микроконтроллер (установки FUSE-битов BOOTSZ1:BOOTSZ0=00, BOOTRST=0):

:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;файл предназначенный :XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;для ATmega8535 ̣̣̣̣̣̣̣̣ ̣̣̣̣̣̣̣̣ :XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX :XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX :00000001FF ;удаление строки окончания файла! + :020000020000FC ;добавление к исходному hex-файлу :10200000FFD7FED7FDD7FCD7FBD7FAD7F9D7F8D73C ;файла m8535to16.hex :10201000F7D7F6D7F5D7F4D7F3D7F2D7F1D7F0D76C ̣̣̣̣̣̣̣̣ ̣̣̣̣̣̣̣̣ :103FE0000FD80ED80DD80CD80BD80AD809D808D8B5 :103FF00007D806D805D804D803D802D801D800D8E5 :00000001FF

С очень большой вероятностью модифицированная программа успешно заработает на новой модели. Правда такая доработка накладывает и ряд ограничений. Переход, в случае попадания в запрещенный диапазон адресов, будет длиться на 37 циклов дольше и потребует в стеке дополнительных 8 б. Вызов каждого прерывания будет отложен на 2 цикла. И, конечно, каждый переход из основной программы в область 0x1000…0x1FFF обязательно должен попадать на инструкцию rcall new_adr.

Перейти к следующей части:


Категория: Микроконтроллеры
Метки:

Написать коментарий

*
= 4 + 7

Добавить изображение

Последние статьи