Vývojová deska Arduino Uno s mikrokontrolérem ATMega328 je primárně zaměřena na začátečníky, kteří elektronice nebo mikrokontrolérům vůbec nerozumí. Internetový odborníci na slovo vzatí :) se ale různě po diskusích dohadují, že je Arduino nepoužitelné, že neučí začátečníka ty správné návyky™, že je vývojář až příliš odříznut od hardawe a podobně. Dva hlavní argumenty těchto diskutujících jsou — Arduino používá vlastní jazyk a ne standardní C. A že vývojové prostředí je pro pokročilejší věci nepoužitelné.
V tomto článku bych chtěl oba tyto argumenty vyvrátit a dokázat, že Arduino je pouze ATMega328 a že lze Arduino IDE obejít.
Na následujících řádcích se budu odkazovat na nástroje make, avr-gcc, avr-objcopy, avrdude a stty. Předpokládám alespoň základní znalost práce v Unixovém terminálu a znalost jazyka C pro mikrokontroléry Atmel. Pokud nerozumíte co to všechno znamená, pak mám pro vás dobrou zprávu — tento článek ještě číst nemusíte, vystačíte si s Arduino IDE :)
Jak to dělá Arduino IDE
Arduino není nic jiného, že deska s ATMega328 (mluvíme o Arduino Uno). Tento mikrokontrolér má již naprogramovaný bootloader, který umí programovat flash paměť skrz rozhraní UART. Aby bylo možné Arduino programovat pomocí avrdude, obsahuje deska i převodník USB-UART, který je realizován mikrokontrolérem ATMega8U2 (nebo ATMega16U2).
Po připojení k PC se Arduino hlásí jako sériový port, na Unixových systémech většinou /dev/tty.usbmodem*, /dev/tty.usbserial*, /dev/ttyACM* nebo /dev/ttyUSB*. Záleží na operačním systému a verzi Arduina.
Pokud spustíte Arduino IDE a přeložíte libovolný kód, na pozadí se nejdříve spustí překladač avr-gcc. Jakmile chcete kód do Arduina nahrát, na pozadí nejdříve ATMega328 restartuje a pak se spustí avrdude.
Tímto víme vše potřebné, abychom obešli vývojové prostředí a napsali si vlastní makefile a kód přímo v jazyce C.
Kód blink.c
Nejdříve jednoduchý kód, který bude blikat LEDkou na pinu číslo 13. V Arduino IDE by nám stačilo napsat něco takového:
void setup() {
pinMode(13, OUTPUT);
}
void loop() {
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
}
My ale nemáme k dispozici žádné Arduino funkce, vše si musíme napsat sami.
Při pohledu do schématu Una zjistíme, že pin číslo 13 je připojen na PB5. Náš kód bude vypadat třeba takto:
#include <avr/io.h>
#include <util/delay.h>
// Nastaví bit 'b' bajtu 'B' na log. nulu.
#define LOW(B, b) (B &= ~_BV(b))
// Nastaví bit 'b' bajtu 'B' na log. jedničku.
#define HIGH(B, b) (B |= _BV(b))
// Pin 13 je na 5. bitu portu B.
#define P13 (5)
void setup() {
// Všechny piny portu B budou výstupní.
DDRB = 0xFF;
}
/**
* Hlavní smyčka programu
*/
static void loop() {
LOW(PORTB, P13);
_delay_ms(500);
HIGH(PORTB, P13);
_delay_ms(500);
}
int main(void) {
setup();
for (;;)
loop();
return 0;
}
Programování Arduina
Pro překlad .c do .hex použijeme avr-gcc:
$ avr-gcc -g -Os -mmcu=atmega328p -DF_CPU=16000000 -c blink.c $ avr-gcc -g -mmcu=atmega328p -o blink.elf blink.o $ avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex
Nejdříve přeložíme do objektového kódu. Musíme definovat frekvenci krystalu (Arduino používá 16MHz) a cílový mikrokontrolér (ATMega328P). Jelikož v kódu používáme funkci _delay_ms(), musíme kód optimalizovat pomocí přepínače -Os. Pokud bychom tuto optimalizaci nezapli, zmíněná funkce by nebyla přesná a blikání by mělo jinou frekvenci.
Teď již zbývá .hex nahrát do Arduina. To provedeme např.:
$ stty -f /dev/tty.usbmodem441 hupcl $ avrdude -p atmega328p -P /dev/tty.usbmodem441 -c arduino -U flash:w:blink.hex
Prvním příkazem Arduino restartujeme. Přepínač -f funguje pouze pro BSD verzi stty, pokud máte GNU verzi, použijte -F. Pokud z nějakého důvodu nechcete použít stty, lze Arduino restartovat i tímto jednoduchým kódem v Pythonu:
import serial, time
s = serial.Serial('/dev/tty.usbmodem441', 57600)
s.setDTR(True)
time.sleep(1)
s.setDTR(False)
Druhým příkazem se Arduino naprogramuje. Avrdude lze použít i pro přečtení obsahu paměti. V případě, že chcete přečíst celou flash paměť Arduina, můžete použít toto:
$ avrdude -p atmega328p -P /dev/tty.usbmodem441 -c arduino -U flash:r:blink.hex:i
Pokud byste chtěli měnit i fuses a bootloader, již budete potřebovat externí programátor.
Makefile
A takto nějak může vypadat náš Makefile:
MCU = atmega328p
F_CPU = 16000000
FORMAT = ihex
CC = avr-gcc
FLAGS = -std=c99 -g -mmcu=$(MCU)
OBJCOPY = avr-objcopy
FILE = blink
PORT ?= /dev/tty.usbmodem*
STTY = stty
AVRDUDE = avrdude
PROGRAMMER = arduino
programme: $(FILE).hex
$(STTY) -f $(PORT) hupcl
$(AVRDUDE) -p $(MCU) -P $(PORT) -c $(PROGRAMMER) -U flash:w:$(FILE).hex
$(FILE).hex: $(FILE).elf
$(OBJCOPY) -j .text -j .data -O $(FORMAT) $(FILE).elf $(FILE).hex
$(FILE).elf: $(FILE).o
$(CC) $(FLAGS) -o $(FILE).elf $(FILE).o
$(FILE).o: $(FILE).c
$(CC) $(FLAGS) -Os -DF_CPU=$(F_CPU) -c $(FILE).c
clean:
rm -f *.elf *.o *.hex
A to je vše. Teď již pro programování Arduina stačí spustit make:
$ ls blink.c Makefile $ make
Závěr
V tomto článku jsem chtěl připomenout, že Arduino není nic jiného, než ATMega328 a pár součástek okolo. Pokud vám z nějakého důvodu vadí Arduino IDE, není nic jednoduššího, než jej obejít a využívat překladač gcc a avrdude.
