WSL: программирование AVR в виртуальной машине Linux |
![]() |
Добавил(а) microsin |
Здесь мы рассмотрим программирование микроконтроллеров AVR на примере популярной платки Arduino Nano. И будем это делать в виртуальной машине Linux, работающей в среде WSL [1]. Вы можете спросить: зачем такие заморочки, когда под Windows есть куча готовых удобных инструментов для программирования AVR и любых микроконтроллеров? Да, конечно, это так, но вероятно рано или поздно все-таки придется переехать на Linux, и поэтому есть некий смысл выделить время на изучение нового инструментария. Установка WSL хорошо описана как на сайте Microsoft, так и на других ресурсах сети [1]. Однако для доступа из виртуальной машины WSL к последовательным портам tty есть некоторая тонкость. Проблема в том, что WSL существует в двух версиях: WSL1 и WSL2, и команда wsl --install по умолчанию устанавливает WSL2. И эта версия WSL2 по какой-то непонятной причине не позволяет работать с последовательными портами. А как известно, платки Arduino программируются через последовательный порт. Поэтому необходимо установить WSL1 вместо WSL2. [Установка WSL1] Запустите PowerShell с правами администратора. Выполните следующие команды: > wsl --set-default-version 1 Этой командой мы задаем по умолчанию устанавливать WSL1. Далее установите виртуальную машину Ubuntu следующей командой: > wsl --install -d Ubuntu-20.04 Проверьте, что Ubuntu установлена именно под версией WSL1: > wsl --list --verbose NAME STATE VERSION * Ubuntu-20.04 Running 1 Примечание: если у вас уже по какой-то причине установлена виртуальная машина под управлением WSL2, то её нужно сначала удалить командами wsl --shutdown и wsl --unregister имядистрибутива, например wsl --unregister Ubuntu-20.04. >wsl --list --verbose
NAME STATE VERSION
* Ubuntu Running 2
Ubuntu-20.04 Stopped 1
>wsl --unregister Ubuntu
>wsl --list --verbose
NAME STATE VERSION
* Ubuntu-20.04 Running 1
[Подготовка среды разработки в виртуальной машине Linux] Далее все шаги выполняются в командной строке установленной виртуальной машины Ubuntu, если не указано что-то иное (на одном из шагов нам придется перезапустить виртуальную машину командами PowerShell). 1. Обновите пакеты для нашей виртуальной Ubuntu: $ sudo apt-get update $ sudo apt-get dist-upgrade Команда sudo apt-get dist-upgrade займет довольно много времени, и будут периодически выдаваться сообщения о необходимости перезагрузки системы. Поэтому после завершения этой команды надо перезагрузить wsl из командной строки PowerShell (с правами администратора). Для этого сначала выйдите из виртуальной машины: $ logout После этого в командной строке PowerShell выполните команды: > wsl --shutdown > wsl Эти команды перезапустят виртуальную машину. 2. Установите cu, это программа для подключения к последовательным портам. Её можно использовать как монитор последовательного порта. $ sudo apt install cu 3. Теперь нужно установить необходимые для программирования утилиты [2]. $ sudo apt install make $ sudo apt-get install gcc-avr avr-libc uisp avrdude $ sudo apt install dos2unix 4. Подключите платку Arduino Nano к компьютеру через USB. Предположим, Windows обнаружила её как COM4: Тогда этот COM-порт будет виден в WSL как устройство /dev/ttyS4. Примечание: в WSL2 по какой-то причине нумерация несколько другая, это устройство будет видно как /dev/tty4. И, повторюсь, на момент написания статьи (август 2023 года) WSL2 не позволяла получить доступ к этим последовательным портам. Возможно когда-нибудь Microsoft это исправит. [Как программировать] $ mkdir myprojects $ sudo mount -t drvfs M:/work myprojects/ Примечание: команда sudo mount -t drvfs M:/work myprojects/ необязательна. Она выполнена для того, чтобы не загромождать системный диск C:. Этой командой произведено монтирование папки m:\work на другом диске, где у меня размещены проекты, с которыми я работаю. $ mkdir helloworld $ cd helloworld $ nano main.c Введите в редакторе nano текст программы, мигающей светодиодом, из статьи [2]. Примечание: WSL отлично работает с буфером обмена. Поэтому можно просто скопировать текст из статьи [2], и затем вставить его в nano путем нажатия Ctrl+V. //Примечание: чтобы подпрограммы задержки давали корректные значения,
// нужно правильно установить значение макропеременной F_CPU
// в соответствие с используемой тактовой частотой микроконтроллера.
//Например так:
#ifndef F_CPU
#define F_CPU 16000000UL // тактовая частота 16 МГц #endif
//Подключение заголовков, в которых определены порты микроконтроллера,
// и имя подпрограммы задержки:
#include < avr/io.h>
#include < util/delay.h>
//Объявление имени LED для ножки порта, куда подключен светодиод.
//На разных макетных платах светодиод подключен к разным ножкам,
// поэтому раскомментируйте одно из определений ниже в зависимости
// от используемой макетной платы.
//#define LED PB0 //Для платы AVR-USB-MEGA16.
#define LED PB5 //Для плат Arduino Uno, Arduino Nano и metaboard. //#define LED PB7 //Для платы Arduino MEGA 2560.
// Основная функция, где находится главный цикл программы.
int main(void) { //До начала главного цикла всегда делаются предварительные настройки. DDRB = (1 << LED); // настройка порта LED как выхода. // Эквивалентно записи 0b00100000 в регистр DDRB. //Главный бесконечный цикл программы. while(1) { PORTB |= (1 << LED); // зажечь светодиод _delay_ms (5); // задержка на 5 мс PORTB &= ~(1 << LED); // погасить светодиод _delay_ms (50); // задержка на 50 мс } } $ nano Makefile Введите следующий текст Makefile (опять-таки это Makefile из [2]): Важный момент для запуска make: в строках после целей "%.o:", "clean:", "help:", "flash:" и "disasm": символы пробелов нужно заменить на табуляцию. Ниже в тексте символы табуляции показаны символом стрелочки →. MCU = atmega328p F_CPU = 16000000UL OPTIMIZATION = s TARGET = main SRC = $(wildcard *.S) $(wildcard *.c) COMPILER = avr-gcc INC=-I. #COMX=COM4
#COMX=/dev/ttyUSB0
COMX=/dev/ttyS4 CFLAGS = -c -gdwarf-2 -g2 -mmcu=$(MCU) -fshort-enums -fno-inline-small-functions -fpack-struct -Wall \ -fno-strict-aliasing -funsigned-char -funsigned-bitfields -ffunction-sections $(INC) \ -DF_CPU=$(F_CPU) -mrelax -fno-jump-tables -x c -O$(OPTIMIZATION) -std=gnu99 -Wstrict-prototypes \ -MMD -MP #LDFLAGS = -Wl,-u,vfprintf -lprintf_flt
#LDFLAGS = -lm -Wl,-Map=main.map,--cref -Wl,--gc-sections -Wl,--relax -mmcu=$(MCU) \
# -Wl,-u,vfscanf -lscanf_flt -lm -Wl,-u,vfprintf -lprintf_flt
LDFLAGS = -mmcu=$(MCU) AVRDUDE = avrdude -c arduino -P $(COMX) -p m328p -b 57600 all: $(TARGET).elf OBJECTS = $(patsubst %.c, %.o, $(SRC)) HEADERS = $(wildcard *.h) %.o: %.c $(HEADERS) →$(COMPILER) $(CFLAGS) $< -o $@ $(TARGET).elf: $(OBJECTS) →$(COMPILER) $(OBJECTS) -w -mmcu=$(MCU) -o $@ →avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $(TARGET).elf $(TARGET).hex →avr-objcopy -I ihex -O binary $(TARGET).hex $(TARGET).bin #avr-size main.bin →avr-size --mcu=$(MCU) --format=avr $(TARGET).elf clean: →-rm -f *.o *.d *.bin *.hex *.map *.elf help: →@echo "Usage: make create main.hex" →@echo " make help show help" →@echo " make clean remove redundant data" →@echo " make disasm disasm main" →@echo " make flash upload main.hex into flash" →@echo "Current values:" →@echo " TARGET=${TARGET}" →@echo " DEVICE=${MCU}" →@echo " CLOCK=${F_CPU}" →@echo " LFUSE=${LFUSE}" →@echo " HFUSE=${HFUSE}" flash: $(TARGET).elf →$(AVRDUDE) -U flash:w:main.hex:i disasm:$(TARGET).elf →avr-objdump -d $(TARGET).elf Теперь у нас в рабочем каталоге ~/myprojects/helloworld два файла: Makefile и main.c. $ ls Makefile main.c Команда make help выведет подсказку о том, как компилировать: $ make help Usage: make create main.hex
make help show help
make clean remove redundant data
make disasm disasm main
make flash upload main.hex into flash
Current values:
TARGET=main
DEVICE=atmega328p
CLOCK=16000000UL
LFUSE=
HFUSE=
[Прошивка микроконтроллера] Если ваша платка обнаружилась как COM4, то к ней надо будет обращаться через имя /dev/ttyS4. Для начала надо разрешить права доступа к устройству /dev/ttyS4: $ sudo chmod 666 /dev/ttyS4 Программирование: $ avrdude -c arduino -P /dev/ttyS4 -p m328p -b 57600 -U flash:w:main.hex:i Или: $ make flash [Ссылки] 1. Запуск Linux на Windows помощью WSL. |