[Перевод] Низкоуровневое программирование микроконтроллеров tinyAVR 0-series
Вы — 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, который предложил следующую схему подключения для загрузки прошивки на микроконтроллер.
Схема подключения микроконтроллера
▍Проектирование платы для ATtiny406
Мы создали минималистичную коммутационную плату для ATtiny406. На эту плату можно подать питание в 5В от USB. Кроме того, можно подать на неё более низкое напряжение в 3,3В, воспользовавшись для этого выделенными VCC/GND-пинами. На плате нашлось место для кнопки и светодиода. Для проведения экспериментов мы решили встроить в плату резистор на 4,7 кОм, необходимый для использования протокола UPDI (это — резистор R2). В результате у нас получилась следующая схема платы.
Схема платы
▍Готовая плата
Готовая коммутационная плата оказалась весьма компактной, она хорошо стала на маленькую макетную плату. Схемы платы можно найти здесь.
Коммутационная плата, установленная на макетную плату
Для программирования ATtiny406 к плате, с использованием имеющихся на ней контактов, подключается USB-to-Serial-кабель.
Схема подключения кабеля
Программная часть проекта
▍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, что слегка раздражает.
Загрузка компилятора
После загрузки необходимых материалов, представленных в виде архива, мы распаковали этот архив в отдельную папку. Путь к директории 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.
Загрузка 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 в своих проектах?