Ассемблерные вставки в Arduino

C — код

Arduino IDE основана на ассемблере GNU. Таким образом, можно использовать avr-gcc для программирования микроконтроллера на ассемблере через интерфейс ISP. Однако многие мнемоники и макросы ассемблера также можно использовать в среде C. Это стало возможным благодаря библиотеке, автоматически интегрированной в Arduino IDE, которая, в свою очередь, вставляет и различные другие библиотеки ввода-вывода.

На этом этапе следует дать первое представление о прямом использовании мнемоники, а также первое представление об ассемблере и процессе компиляции. В качестве примера служит скетч «Blink», который можно открыть аналогичным образом в IDE в разделе «основы».

void setup()
{
     pinMode(13, OUTPUT);
}
void loop()
{
     digitalWrite(13, HIGH);
     delay(1000);
     digitalWrite(13, LOW);
     delay(1000);
}

В функции void setup() видим одну единственную инструкцию pinMode(13, OUTPUT); Эта инструкция устанавливает пин 13 платы Ардуино в режим цифрового выхода. Эта инструкция должна быть заменена соответствующим образом. Прежде всего, необходимо обратиться к принципиальной схеме платы Arduino Uno.

Ассемблерные вставки в Arduino

Посмотрим какой порт микроконтроллера задействован для вывода 13 платы. На принципиальной схеме видим что PIN 13 платы Uno подключен напрямую к PB5 ATmega 328P, поэтому он принадлежит порту B микроконтроллера Все настройки портов ввода-вавода организованы в 8-битных регистрах (8-битная архитектура, биты от 0 до 7). Регистр с именем DDRx (регистр направления данных) определяет режим работы вывода контроллера. Логическая «1» настраивает пин на выход, логический «0» — вход.

Теперь получаем для порта B нужное нам значение, которое позволит настроить пин PB5 на вывод. за направление работы пинов порта B отвечает регистр DDRB. Соответственно, 5-й бит этого 8-битного регистра должен быть установлен в «1». Получаем двоичное значение регистра DDRB = 00100000. Это соответствует 20 в шестнадцатеричном и 32 в десятичном исчислении. Остальные семь бит для нашего скетча не имеют значения. На языке Си это будет выглядеть так:

void setup()
{
     DDRB = 0b00100000; 
}
void loop()
{
     digitalWrite(13, HIGH);
     delay(1000);
     digitalWrite(13, LOW);
     delay(1000);
}

Inline Assembler

Для интеграции небольших фрагментов ассемблера непосредственно в код C.
компилятор GCC поддерживает встроенный ассемблер [GCC EXTENDED-ASM]

asm ("hier steht der assembler code");

Для того, чтобы компилятор не оптимизировал код перед asm необходимо добавить ключевое слово volatile:

asm volatile ("hier steht der assembler code");

Содержимое регистров DDRx не может быть перезаписано напрямую. Это сделано в качестве меры защиты. Микроконтроллер имеет 32 так называемых рабочих регистра с r0 по r31 (рабочие регистры общего назначения). Они используются, например, в качестве буфера между регистрами ввода-вывода и ОЗУ.

Ассемблерные вставки в Arduino

Структура памяти Mega328

Например Регистр r16 может использоваться любой командой ассемблера. Команда ldi (LoaD Immediate) используется для записи значения в такой рабочий регистр. Затем значение из r16 загружается в DDRB с помощью команды out. DDRB имеет адрес 0x04, так что теперь получается следующее:

void setup()
{
    asm volatile
     (
         "ldi r16,0x20\n"
         "out 0x04,r16\n"
     );
    }
void loop()
{
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
    delay(1000);
}

Выражение \n используется для обозначения разрыва строки для разделения командных строк asm.

Здесь следует подчеркнуть, что это очень простой пример, который также легко реализовать. В дополнение к обычным командам ассемблера, которые описаны в операторе инструкции Atmel, при программировании на ассемблере необходимо учитывать гораздо больше, чем принято в языках высокого уровня, например, специфические значения, места, где параметры передаются в определенной форме, подключение переменных и регистров и более подробное изучение используемого оборудования. Последнее делает необходимым изучение даташита на микроконтроллер. Тем не менее, работа с аппаратным языком ассемблера имеет смысл. После небольшой тренировки его использование не намного сложнее, чем программирование на языке высокого уровня.

Ассемблер: преимущества и недостатки

Преимущества ассемблера:

Инструкции на ассемблере подходят для машинных кодов и поэтому «ближе к железу», чем языки высокого уровня, такие как C. В принципе, одна инструкция на ассемблере (мнемоника) соответствует соответствующей машинной инструкции. Таким образом, программы, написанные на чистом ассемблере (не на встроенном ассемблере), как правило, компактнее и быстрее, чем скомпилированный код, сгенерированный языками высокого уровня. Например, вы можете включать и выключать выводы контроллера одновременно за очень короткое время, так как вы можете обойти библиотеку wireing.c. Для этого требуется много строк для каждого порта, и все они должны обрабатываться одна за другой в цикле процессора. Для критичных по времени приложений предпочтительнее чистый ассемблер, нежели язык высокого уровня.

Встроенный ассемблер не предлагает такого оптимального использования, поскольку он интегрирован в среду C. Однако такие маленькие кусочки ассемблера можно встроить прямо в код C. Это может быть значительно более оптимально с точки зрения использования регистров, поскольку GCC точно знает, какие регистры нужны, а какие нет. Для приложений, чувствительных ко времени, inlineAssembler также может быть очень полезен.

Недостатки ассемблера:


• Изучение с ассемблера, устранение ошибок и сопровождение программы сложнее, чем в случае с языками высокого уровня.
• Ограничено или вообще невозможно перенесение программы на другие микроконтроллеры.

Машинный язык

Компилятор/ассемблер/отладчик Ardunio IDE создает файл *.hex, который автоматически загружается в память ATmega через USB-интерфейс платы Arduino встроенным загрузчиком. Понятные человеку аббревиатуры переводятся в двоичный код, понятный микроконтроллеру. Этот файл *.hex находится на жестком диске компьютера. Чтобы отобразить местоположение файла, вы можете установить галочку «Показать подробный вывод при компиляции» в разделе «Настройки» в среде IDE, после чего соответствующее примечание появится в поле комментариев среды IDE в разделе «Проверка».

Для простоты сократим наш пример кода до описания рабочего регистра:

void setup()
{
    asm volatile
    (
        "ldi r16,0x20\n"
    );
}
void loop()
{
}

При этом компилятор сгенерирует HEX файл следующего содержания:

:100000000C9434000C9451000C9451000C94510049
:100010000C9451000C9451000C9451000C9451001C
:100020000C9451000C9451000C9451000C9451000C
:100030000C9451000C9451000C9451000C945100FC
:100040000C9465000C9451000C9451000C945100D8
:100050000C9451000C9451000C9451000C945100DC
:100060000C9451000C94510011241FBECFEFD8E026
:10007000DEBFCDBF11E0A0E0B1E0E4EDF1E002C0F1
:1000800005900D92A030B107D9F711E0A0E0B1E0E2
:1000900001C01D92A930B107E1F70E9456000C94EF
:1000A000E8000C94000000E208950895CF93DF93D8
:1000B0000E94AD000E945300C0E0D0E00E945500B5
:1000C0002097E1F30E940000F9CF1F920F920FB624
:1000D0000F9211242F933F938F939F93AF93BF93CE
:1000E0008091040190910501A0910601B091070152
:1000F000309108010196A11DB11D232F2D5F2D37D1
:1001000020F02D570196A11DB11D20930801809369
:10011000040190930501A0930601B093070180911B
:10012000000190910101A0910201B091030101969B
:10013000A11DB11D8093000190930101A0930201C4
:10014000B0930301BF91AF919F918F913F912F91F8
:100150000F900FBE0F901F901895789484B5826011
:1001600084BD84B5816084BD85B5826085BD85B55B
:10017000816085BDEEE6F0E0808181608083E1E80A
:10018000F0E0108280818260808380818160808342
:10019000E0E8F0E0808181608083E1EBF0E0808145
:1001A00084608083E0EBF0E0808181608083EAE717
:1001B000F0E08081846080838081826080838081A0
:1001C000816080838081806880831092C10008955F
:0401D000F894FFCFD1
:00000001FF

Это так называемый формат INTEL Hex, который уже использовался в 1970-х годах для загрузки программ с перфоленты. Предложение всегда начинается с двоеточия, за которым следуют различные управляющие биты, такие как биты адреса, биты идентификации типа, фактические биты данных и контрольные суммы для каждой строки. Затем программа загрузки удаляет дополнительные данные. Чтобы снова найти инструкцию для r16, требуется опкод (код операции) для команды ldi:

Ассемблерные вставки в Arduino

Синтаксис: LDI Rd,K. Значение для K — шестнадцатеричное «20», эквивалентное двоичному «100000». Это приведет нас к коду операции

Ассемблерные вставки в Arduino

Используемый регистр является первым используемым регистром, поэтому он имеет значение «0» в коде операции:

Ассемблерные вставки в Arduino

Это приводит к шестнадцатеричному виду для 2 байтов: «e200»

Этот фрагмент кода фактически встречается один раз в приведенном выше коде .hex (одиннадцатая строка в листингк HEX файла).

Вторая статья по данной теме (продолжение)…

Полезные ссылки:

Arduino:

//www.atmel.com/Images/doc8161.pdfages/doc8161.pdf
http://arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf [ARDUINO SCHEMATIC]

http://arduino.cc/hu/Hacking/PinMapping
http://arduino.cc/en/Reference/PortManipulation

Inline Assembler:

http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended-As [GCC EXTENDED-ASM]

http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html

http://www.nongnu.org/avr-libc/user-manual/inline_asm.html

http://savannah.nongnu.org/download/avr-libc/avr-libc-user-manual-1.8.0.pdf.bz2

http://www.mikrocontroller.net/articles/AVR_Assembler_Makros [ASSEMBLER MACROS]

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial

http://www.lowlevel.eu/wiki/Inline-Assembler_mit_GCC

http://www.rn-wissen.de/index.php/Inline-Assembler_in_avr-gcc

http://www.k2.t.u-tokyo.ac.jp/members/alvaro/courseMaterials/MicroProgramming

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *