[Перевод] Низкоуровневое программирование микроконтроллеров tinyAVR 0-series

z7t9cnbslpkyxa8rph5idszhuko.jpeg

Вы — 8-битный или 32-битный программист? Мы, в компании OMZLO, сосредоточили основные усилия на новых 32-битных ARM Cortex-чипах (STM32 и SAMD), которые, в сравнении с более старыми 8-битными микроконтроллерами (Micro Controller Unit, MCU) обычно предлагают больше RAM, более высокую производительность, поддержку большего количества периферийных устройств. И всё это — за ту же, или за более низкую цену. Но 8-битные MCU ещё не утратили своей актуальности. В частности, компания Microchip выпустила новую серию чипов, «tinyAVR 0-series», которые, в сравнении с AVR-чипами, выпущенными ранее, дают возможность работать с более современной периферией. Новые чипы, при этом, отличаются весьма привлекательной ценой. Возникает такое ощущение, что эти чипы отлично подойдут для разработки простых устройств, которым не нужны те возможности, что предлагают более новые 32-битные MCU. 8-битные микроконтроллеры, кроме того, значительно легче программировать, что приводит к увеличению скорости разработки программной части устройств, создаваемых на их основе.

Благодаря успеху Arduino UNO в интернете можно найти множество руководств, разъясняющих особенности программирования 8-битных микроконтроллеров ATmega328 и их собратьев вроде ATtiny85. Речь идёт о прямом доступе к регистрам без использования языка программирования, используемого для Arduino, и без применения IDE, созданных производителями чипов, вроде Atmel Studio. Чтобы в этом убедиться — просто поищите в Google по словам «atmega328 blinky». Для программирования микроконтроллеров вам понадобится лишь C-компилятор для AVR, текстовой редактор, avrdude и AVR-программатор. На некоторых ресурсах даже можно найти руководства, посвящённые тому, как, пользуясь универсальными макетными платами, «завести» ATmega328. Правда, если говорить о более новых чипах tinyAVR 0-series, по ним найти информацию такого рода непросто.
Конечно, Microchip предлагает все необходимые инструменты для программирования новых tinyAVR, представленные в виде IDE, рассчитанной исключительно на Windows. Для некоторых из новых чипов существуют «ядра Arduino». Благодаря этому такие чипы можно программировать с использованием IDE Arduino. Но, опять же, если некто предпочитает писать код для микроконтроллеров в «низкоуровневом» стиле, используя свой любимый текстовой редактор, Makefile и компилятор C, то он сможет найти очень мало информации о таком подходе к работе с tinyAVR.

В этом материале мы расскажем о том, как, с нуля, применяя простейшие инструменты, создать прошивку blinky для ATtiny406. Большинство того, о чём пойдёт речь, справедливо и для других MCU tinyAVR. Это руководство рассчитано на тех, кто пользуется macOS и Linux, но нашими советами, с небольшими изменениями, смогут воспользоваться и те, кто работает в среде Windows.

Аппаратная часть проекта


▍Исследование ATtiny406


Мы решили поэкспериментировать с ATtiny406, рассчитывая на то, что в будущем этот микроконтроллер придёт на смену ATtiny45, который в настоящее время используется в PiWatcher — в нашей разработке, которая позволяет, при возникновении такой необходимости, полностью выключить или перезагрузить Raspberry Pi. У ATtiny406 имеется 4 Кб флеш-памяти, 256 байт RAM, микрочип может работать на частоте 20 МГц без внешнего источника тактовых сигналов.

Одним из главных различий между новыми MCU tinyAVR и более старыми, широко известными чипами, вроде ATtiny85, является то, что более новые чипы используют протокол программирования UPDI. Для его работы нужно всего 3 пина, а для работы протокола ISP, используемого старыми чипами, нужно 6 пинов.

После непродолжительного изучения вопроса мы узнали, что программировать tinyAVR по UPDI можно, воспользовавшись простым USB-to-Serial-кабелем и резистором. Мы выяснили это благодаря Python-инструменту pyupdi, который предложил следующую схему подключения для загрузки прошивки на микроконтроллер.

48d2a6715104323020d2a8570adb9ba4.png


Схема подключения микроконтроллера

▍Проектирование платы для ATtiny406


Мы создали минималистичную коммутационную плату для ATtiny406. На эту плату можно подать питание в 5В от USB. Кроме того, можно подать на неё более низкое напряжение в 3,3В, воспользовавшись для этого выделенными VCC/GND-пинами. На плате нашлось место для кнопки и светодиода. Для проведения экспериментов мы решили встроить в плату резистор на 4,7 кОм, необходимый для использования протокола UPDI (это — резистор R2). В результате у нас получилась следующая схема платы.

58e4ee987b11842f73d224e7db6e932b.png


Схема платы

▍Готовая плата


Готовая коммутационная плата оказалась весьма компактной, она хорошо стала на маленькую макетную плату. Схемы платы можно найти здесь.

1fd4663875da9b251603069c16a5293b.jpg


Коммутационная плата, установленная на макетную плату

Для программирования ATtiny406 к плате, с использованием имеющихся на ней контактов, подключается USB-to-Serial-кабель.

6509543a5463c03c66e5dd9ff04bccea.png


Схема подключения кабеля

Программная часть проекта


▍pyupdi


Мы установили pyupdi, следуя инструкциям из репозитория проекта.

USB-to-Serial-кабель был подключён к плате с использованием четырёх UPDI-контактов. Наш USB-to-Serial-конвертер был виден в macOS как файл /dev/tty.usbserial-FTF5HUAV.

Для того чтобы убедиться в том, что программатор распознаёт ATtiny406, можно выполнить команду, напоминающую следующую, отредактировав путь к файлу:

pyupdi -d tiny406 -c /dev/tty.usbserial-FTF5HUAV -i


Если всё настроено правильно, то выполнение подобной команды должно привести к выводу примерно таких данных:

Device info: {'family': 'tinyAVR', 'nvm': 'P:0', 'ocd': 'D:0', 'osc': '3', 'device_id': '1E9225', 'device_rev': '0.1'}


▍C-компилятор


Оказалось, что обычный компилятор avr-gcc, который можно установить на macOS, используя Homebrew, не позволяет задать ATtiny406 в виде цели компиляции. Поэтому мы решили установить avr-gcc, предоставляемый компанией Microchip. Для загрузки компилятора надо создать учётную запись на сайте Microchip, что слегка раздражает.

b775b4a31dc945e486900e213bbc232f.png


Загрузка компилятора

После загрузки необходимых материалов, представленных в виде архива, мы распаковали этот архив в отдельную папку. Путь к директории bin, которая окажется в этой папке, нужно добавить в PATH. Это, в дальнейшем, облегчит работу. Если исходить из предположения о том, что компилятор хранится в папке $HOME/Src/avr8-gnu-toolchain-darwin_x86_64, то отредактировать PATH можно, добавив следующую команду в файл .bash_profile:

export PATH=$PATH:$HOME/Src/avr8-gnu-toolchain-darwin_x86_64/bin/


Самые новые MCU ATtiny не поддерживаются компилятором avr-gcc от Microchip без дополнительных настроек. Для обеспечения их поддержки нужно загрузить ATtiny Device Pack.

58085a3d5a7d420f4d3829a651b3fc5d.png


Загрузка ATtiny Device Pack

Мы, в результате, загрузили пакет Atmel.ATtiny_DFP.1.6.326.atpack (этот файл может называться иначе, в состав его имени может входить другой номер версии). Хотя расширением файла является .atpack, это, на самом деле, обычный .zip-архив. Мы поменяли его расширение на .zip и извлекли содержимое пакета в папку $HOME/Src/Atmel.ATtiny_DFP.1.6.326, то есть — туда же, где уже имелись файлы компилятора.

▍Написание программы на C


Мы написали следующую программу, которая, с частотой в 1 Гц, мигает светодиодом, подключённым к выходу B5 на нашей плате для ATtiny.

#include 
#include 

int main() {
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); // установлено в 20МГц (предполагается, что фьюз 0x02 установлен в 2)

    PORTB.DIRSET = (1<<5);
    for (;;) {
        PORTB.OUTSET = (1<<5);
        _delay_ms(500);
        PORTB.OUTCLR = (1<<5);
        _delay_ms(500);
    }
}


Этот код очень похож на программу, мигающую светодиодом, написанную для привычных микроконтроллеров AVR. Первым заметным изменением является использование структур для доступа к регистрам MCU. Например, вместо обращения к PORTB выполняется обращение к PORTB.DIRSET.

Ещё одно изменение представлено кодом настройки частоты (_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0)). Новый ATtiny406 после перезагрузки работает на частоте 3,33 МГц, что соответствует базовой частоте в 20 МГц, которую разделили на 6. Для того чтобы чип работал бы на полной скорости в 20 МГц, мы очищаем регистр CLKCTRL.MCLKCTRLB. Так как этот регистр должен быть защищён от случайных изменений, на ATtiny406 для его модификации необходимо применить особую программную конструкцию. К счастью, решение этой задачи облегчает макрос _PROTECTED_WRITE. Подробности об этом можно почитать здесь.

Если сравнить этот код с тем, который пишут для STM32 или для SAMD21, то он окажется гораздо проще.

▍Файл Makefile


Тут мы пользуемся следующей структурой директорий:

  • src/Atmel.ATtiny_DFP.1.6.326/ — путь к Microchip Device Pack.
  • src/attiny406-test/ — папка, в которой, в файле main.c, хранится вышеприведённый код.


Компиляцию кода, находясь в директории attiny406-test/, можно выполнить следующей командой:

avr-gcc -mmcu=attiny406 -B ../Atmel.ATtiny_DFP.1.6.326/gcc/dev/attiny406/ -O3 -I ../Atmel.ATtiny_DFP.1.6.326/include/ -DF_CPU=20000000L -o attiny406-test.elf main.c


Флаг -O позволяет выполнить оптимизацию, необходимую для успешной работы вызовов функции _delay_ms(). То же самое относится и к переменной -DF_CPU, содержимое которой отражает ожидаемую частоту чипа. Остальные параметры содержат сведения о расположении файлов для ATtiny406, которые мы ранее скачали и извлекли из архива Device Pack.

Для загрузки прошивки на MCU нужно преобразовать то, что получилось в формат Intel HEX. После этого надо воспользоваться pyupdi. Мы создали простой Makefile, автоматизирующий решение этих задач:

OBJS=main.o
ELF=$(notdir $(CURDIR)).elf  
HEX=$(notdir $(CURDIR)).hex
F_CPU=20000000L

CFLAGS=-mmcu=attiny406 -B ../Atmel.ATtiny_DFP.1.6.326/gcc/dev/attiny406/ -O3
CFLAGS+=-I ../Atmel.ATtiny_DFP.1.6.326/include/ -DF_CPU=$(F_CPU)
LDFLAGS=-mmcu=attiny406 -B ../Atmel.ATtiny_DFP.1.6.326/gcc/dev/attiny406/
CC=avr-gcc
LD=avr-gcc

all:    $(HEX)  

$(ELF): $(OBJS)
                $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

$(HEX): $(ELF)
                avr-objcopy -O ihex -R .eeprom $< $@

flash:  $(HEX)
                pyupdi -d tiny406 -c /dev/tty.usbserial-FTF5HUAV -f attiny406-test.hex

read-fuses:
                pyupdi -d tiny406 -c /dev/tty.usbserial-FTF5HUAV -fr

clean:
                rm -rf $(OBJS) $(ELF) $(HEX)


Для компиляции кода достаточно выполнить команду make. Загрузка кода на микроконтроллер выполняется командой make flash. Представленный нами Makefile может быть, при необходимости, доработан.

Итоги


Программировать новые TinyAVR так же просто, как и MCU предыдущих поколений. Главное — подобрать правильные инструменты. Если у вас есть советы по программированию AVRTiny, поделитесь ими с нами в Twitter или в комментариях ниже.

Планируете ли вы пользоваться новыми TinyAVR в своих проектах?

oug5kh6sjydt9llengsiebnp40w.png

3piw1j3wd_cgmzq9sefgferaumu.png

© Habrahabr.ru