Найти в Дзене

Выбор ассемблера AVRA

При программировании устройств на базе AVR ассемблер AVRASM является стандартом. Беда в том, что он есть только под Windows. В других операционных системах существуют такие компиляторы, как arva, avr-as - основные аналоги атмеловского AVRASM. Я пользуюсь avra. Он почти полностью идентичен AVRASM и в довесок имеет расширенный язык макроопределений. Если не пользоваться расширенными возможностями avra, код для AVRASM будет компилироваться на avra и наоборот. Отсюда и далее я буду использовать avra. Например, код на рисунке первая строка с директивой .device дает компилятору указание собирать для микропроцессора серии atmega32. Далее определяется метка Init, которая в дальнейшем будет использоваться для реализации бесконечного цикла. После идет nop - не опрерация и в конце - rjmp Init - безусловный переход на метку Init. компиляция программы avra test.asm даст там такой вывод: Видно, что прошивка занимает 3 слова (6 байт), при этом ни оперативка SRAM, ни EEPROM не используются. В коде на

При программировании устройств на базе AVR ассемблер AVRASM является стандартом. Беда в том, что он есть только под Windows. В других операционных системах существуют такие компиляторы, как arva, avr-as - основные аналоги атмеловского AVRASM. Я пользуюсь avra. Он почти полностью идентичен AVRASM и в довесок имеет расширенный язык макроопределений. Если не пользоваться расширенными возможностями avra, код для AVRASM будет компилироваться на avra и наоборот. Отсюда и далее я буду использовать avra.

Например, код на рисунке

Рисунок 1. - Простая программа на ассемблере, которая ничего не делает
Рисунок 1. - Простая программа на ассемблере, которая ничего не делает

первая строка с директивой .device дает компилятору указание собирать для микропроцессора серии atmega32. Далее определяется метка Init, которая в дальнейшем будет использоваться для реализации бесконечного цикла. После идет nop - не опрерация и в конце - rjmp Init - безусловный переход на метку Init.

компиляция программы avra test.asm даст там такой вывод:

Рисунок 2. - Результат компиляции программы с рисунка 1
Рисунок 2. - Результат компиляции программы с рисунка 1

Видно, что прошивка занимает 3 слова (6 байт), при этом ни оперативка SRAM, ни EEPROM не используются.

В коде на рисунке 1 явно не указаны сегменты, о умолчанию считается, что все располагается в сегменте кода (.cseg).

Но вернемся все-таки к обзору свойств компилятора avra:

  1. Поддержка расширенного набора директив препроцессора (.define, .undef, .ifdef, .ifndef, .if, .else, .endif, .elif, .elseif, .warning). Они действуют аналогичным образом, что и в Си, так что если ты знаком с ним, никаких трудностей в использовании данных директив не будет.
  2. В AVRA появились новые функции для написания макросов. Это должно способствовать повторному использованию кода, например, при создании собственной библиотеки. В avrasm есть макросы, но их парамеры не типизированы, то есть вызывая макрос, вы в качестве параметра можете передать абсолютно любое значение, будь то регистр, ссылка на память, адрес. Это не совсем удобно, особенно если один и тото же макрос используется для операций с 1,2,4,8-байтовыми числами. В AVRA добавлена возможность писать типизированные макросы.
  3. Поддержка отладки. AVRA создает coff-файл каждый раз, когда сборка проходит успешно. Этот файл позволяет AVR Studio или любому совместимому с coff отладчику имитировать или эмулировать программу.
  4. Поддержка мета-определений. Они помогают отслеживать версии вашего программного обеспечения, а также могут быть использованы для создания серийных номеров конкретных клиентов.
  5. Циклы в макросах. Макро-расширения AVRA позволяют организовывать циклы в макросах. Предусмотрена возможность генерации уникальных меток для переходов.

AVRA предлагает ряд директив, которые не являются частью ассемблера Atmel. Они должны помочь вам в создании универсального и модульного кода.

Директива .define определяет переменную препроцессора, которую можно использовать для построения модульного кода или исключения повторного включения подключаемых модулей.

Например .define twi мы определяем переменную twi, которую можно использовать в языке препроцессора и не только.

Директивы .if .elseif .else .endif - используются для подключения различных кусков программы. Например:

.ifndef twi

.define twi 0

.endif

.if twi==0

.include "twi.asm"

.elseif twi==1

.include "i2c.asm"

.endif

Здесь вы видим, что в зависимости от значения подключается либо аппаратная, либо программная реализация двухпроводного интерфейса. Использование директив препроцессора позволяет писать переносимые программы.

В AVRA появилась расширенная поддержка макросов. Как я уже упоминал, это нововведение относится к типизации макросов. Существует несколько типов:

  1. _8,_16,_24,_32,_40,_48,_56,_64 - регистровые значения соответствующей битности
  2. _i - непосредвтвенные значения (константы или метка в SRAM/FLASH)
  3. _v - пустой параметр

соответственно может писать теперь типизированные макросы, например:

Рисунок 3. - Пример с макросами
Рисунок 3. - Пример с макросами

Обратите внимание на следующие вещи:

  1. объявление пустого макроса без параметров обязательно, иначе ассемблер будет ругаться на предмет его (макроса) отсутствия.
  2. при вызове расширенных макросов параметры передаются в квадратных скобках
  3. При объявлении void параметра он не нумеруется в списке подстановок (см Рисунок 5)
Рисунок 4. - результаты компиляции
Рисунок 4. - результаты компиляции
Рисунок 5. - пример с использованием void (_v) подстановки. Обратите внимание на нумерацию параметров.
Рисунок 5. - пример с использованием void (_v) подстановки. Обратите внимание на нумерацию параметров.

Циклы в макросах. Как понимаешь, макрос - это не подпрограмма, текст макроса полностью копируется в программу, поэтому при организации циклов мы должны каким-то образом помечать возможные переходы. В стандартном AVRASM существуют следующие подходы:

  1. Запоминать адрес точки перехода в локальную макро-переменную

.macro Loop

ldi r16, 10

.set M=PC

nop

dec r16

brne M

.endm

2. Передавать дополнительным параметром номер вызова

.macro Loop

ldi r16, 10

M#@0:

nop

dec r16

brne M#@0

.endm

и вызывать так: Loop 1.

Дугой возможный вариант совмещать макрос и вызов подпрограммы. Так можно уйти от необходимости организовывать циклы в макроопределениях.

AVRA предоставляет иной способ организации циклов в макросах через метки с параметром подстановки %.

Например, предыдущий пример можно переписать так:

.macro Loop

ldi r16, 10

M%:

nop

dec r16

brne M%

.endm

Рисунок 6.- Пример листинка с макросом, содержащим цикл
Рисунок 6.- Пример листинка с макросом, содержащим цикл

А вот ниже смотри листинг кода, что сгенерировал ассемблер.

Рисунок 7. - листинг программы
Рисунок 7. - листинг программы

Обрати внимание, что номер метки автоматически увеличивается при каждом вызове макроса. При первом вызове макроса Loop внутренняя метка получил индекс 1, при втором - 2.