Logo

Beispiel: Kompilierung eines C-Quelltextes für den ATmega328p®

Im folgenden Beispiel wird das Blink-Programm für den ATmega328p in ein HEX-File übersetzt, das mit einem Hardware-Programmer auf den Chip geschrieben werden kann.

Zunächst muss der zu übersetzende Quellcode JW_Arduino_Blink_01.c in einem eigenen Ordner untergebracht werden.

#define F_CPU 16000000UL

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{	
	DDRB |= 0b00100000;		// Interne LED an PB5
    while (1) 
    {
		PORTB |= 0b00100000;	// PB5 an
		_delay_ms(2000);
		PORTB &= ~0b00100000;	// PB5 aus
		_delay_ms(1000);
    }
}

Compilieren

Der Quellcode wird nun zunächst in eine Objektcode-Datei mit der Endung *.o übersetzt. Dazu wechselt man in den Ordner mit dem Quellcode. In der Kommandozeile macht man folgende Eingabe:

> avr-gcc JW_Arduino_Blink_01.c -c -o blink.o -Os -g -mmcu=atmega328p -I /usr/avr/sys-root/include

Dabei werden folgende Angaben bzw. Optionen für das Kommando avr-gcc benötigt:

Kommando: avr-gcc
Dateiname: JW_Arduino_Blink_01.c
Option: -c    Compile
Option: -o    Output: Dateiname
Option: -O    Optimierung: s (für geringen Platzbedarf)
Option: -g    erzeugt Debug Infos
Option: -m    Maschinencode: mcu=atmega328p (für ATmega328p)
Option: -I    Pfad zum include Verzeichnis mit den Libraries

Linken

Nun muss vom Linker aus der Objektcode-Datei (Endung: *.o) die AVR-Ausgabedatei (Endung: *.elf) erstellt werden. Dies geschieht mit folgendem Kommandozeilen-Befehl:

> avr-gcc blink.o -o blink.elf -mmcu=atmega328p

Die verwendeten Optionen werden oben beschrieben.

Formatierung

Die AVR-Ausgabedatei (Endung: *.elf) muss nun noch in eine HEX-File (Endung: *.hex) gewandelt werden.

> avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex

Achtung! Der Buchstabe für die Option -O wird groß geschrieben.

Man hat nun ein HEX-File, das man mit einem Hardware-Programmiergerät auf den Mikrocontroller hochladen kann.

Mit einem Trick lässt sich ein Arduino-Board, das mit einem ATmega328p bestückt ist, auch ohne ein Hardware-Programmiergerät mit C-Quelltext programmieren. Dazu muss der Quelltext als HEX-File vorliegen.

Automatisierung der Compilierung mit einem Makefile

Die oben aufgeführten Schritte lassen sich in Linux mit Hilfe des make Tools bequem automatisieren. Dazu muss ein makefile erstellt werden, das im selben Ordner wie der Programmcode liegt.

# Makefile zum direkten Programmieren eines Arduino UNO Boards
 
TARGET=main
MCU=atmega328p
SOURCES=main.c

#Pfad zum include-Verzeichnis (muss nicht immer angegeben werden)
PATH_TO_INCLUDE=-I /usr/avr/sys-root/include

PROGRAMMER=arduino
#auskommentieren für automatische Wahl
PORT=-P/dev/ttyACM0
BAUD=-b115200

#Ab hier nichts verändern, außer man weiß was man tut :-))
OBJECTS=$(SOURCES:.c=.o)
CFLAGS=-c -Os
LDFLAGS=

all: hex eeprom

hex: $(TARGET).hex

eeprom: $(TARGET)_eeprom.hex

$(TARGET).hex: $(TARGET).elf
	avr-objcopy -O ihex -j .data -j .text $(TARGET).elf $(TARGET).hex

$(TARGET)_eeprom.hex: $(TARGET).elf
	avr-objcopy -O ihex -j .eeprom --change-section-lma .eeprom=1 $(TARGET).elf $(TARGET)_eeprom.hex

$(TARGET).elf: $(OBJECTS)
	avr-gcc $(LDFLAGS) -mmcu=$(MCU) $(OBJECTS) -o $(TARGET).elf

.c.o:
	avr-gcc $(CFLAGS) -mmcu=$(MCU) $< -o $@ -g $(PATH_TO_INCLUDE)

size:
	avr-size --mcu=$(MCU) -C $(TARGET).elf

program:
	avrdude -p$(MCU) $(PORT) $(BAUD) -v -c$(PROGRAMMER) -Uflash:w:$(TARGET).hex:a

# Zusätzliche Optionen für das Löschen von temporären Dateien
	
#clean_tmp:
#	rm -rf *.o
#	rm -rf *.elf

#clean:
#	rm -rf *.o
#	rm -rf *.elf
#	rm -rf *.hex

Beispiel für ein Makefile zum direkten Programmieren eines Arduino UNO Boards mit der gcc-Toolchain.

Nun muss man nur noch das Kommando make in die Konsole tippen. Schon hat man das gewünschte HEX-File.

Mit dem Kommando make program kann das HEX-File auf ein angeschlossenes Arduino UNO Board hochgeladen werden.