Unser erstes Programm in C (PI4)
Einführung
In diesem Kurs werden wir die Grundlagen der Programmierung des Raspberry Pi 4 erlernen. Ähnlich wie bei der Programmierung des Raspberry Pi 5, gibt es einige Unterschiede, hauptsächlich bedingt durch die Unterstützung von USB und die umfangreichere Dokumentation für den Raspberry Pi 4. Für diesen Kurs habe ich Material vom Raspberry Pi 5 angepasst, um die Programmierung des Raspberry Pi 4 zu erläutern.
Ein Terminal wurde programmiert, das sich sehr gut zum Debuggen eignet. Dies werden wir in unserem Kurs ebenfalls verwenden.
Ziel unseres ersten Programms
Unser erstes Programm wird eine einfache Endlosschleife enthalten. Dies dient als Basis für weitere Experimente und Versuche. Ich werde erklären, wie ein solches Programm erstellt, kompiliert und ausgeführt wird.
Erstellung des Sourcecodes
Leider kommen wir bei Bare-Metal-Programmierung in C nicht um Assembler herum. Auch wenn das Assemblerprogramm zunächst nicht viel tut, wird es später beispielsweise für die Interrupt-Programmierung benötigt.
Assembler-Code (boot.S)
Öffnen Sie ein Textprogramm und schreiben Sie folgendes erstes Assemblerprogramm:
//
// The first program for RPI4
// 20.02.2025 www.satyria.de
//
.section .init // Ensure the linker places this at the beginning of the kernel image
.globl _start // Generates a global label
_start: // The label _start (entry address)
mov sp, #0x80000 // Create a stack of 512KB (524288 bytes)
b main // Branch to "main"
Speichern Sie die Datei im Standardverzeichnis unter Windows: C:\msys64\home\xxx (wobei xxx in der Regel Ihr Benutzername ist). Unter Linux können Sie die Datei im Home-Verzeichnis speichern. Geben Sie der Datei den Namen boot.S. Die Endung .S kennzeichnet die Datei als Assembler-Sourcecode.
C-Code (main.c)
Nun erstellen wir eine main.c Datei für unser erstes Programm:
//
// main.c
// The first program for RPI4
// 20.02.2025 www.satyria.de
//
int main (void)
{
while (1){}
}
Hier wird eine einfache Endlosschleife erzeugt.
Kompilieren des Programms mit Make
Um unser Programm zu kompilieren, muss zunächst die Programmierumgebung eingerichtet werden. Verwenden Sie hierzu die entsprechenden Anleitungen. Diese funktionieren auch für den Raspberry Pi 4:
Programmierumgebung erstellen (Konsole)
Programmierumgebung erstellen (64-Bit)
Erstellen Sie dann ein Makefile, angepasst für den Raspberry Pi 4:
CSRCS := $(wildcard *.c)
CPPSRCS := $(wildcard *.cpp)
ASRCS := $(wildcard *.S)
COBJS := $(CSRCS:.c=.o)
CPPOBJS := $(CPPSRCS:.cpp=.o)
AOBJS := $(ASRCS:.S=.o)
AllOBJS := $(COBJS) $(CPPOBJS) $(AOBJS)
LOADADDR = 0x80000
GCCFLAGS = -DAARCH=64 -mcpu=cortex-a72 -mlittle-endian -Wall -O0 -ffreestanding \
-nostartfiles -nostdlib -nostdinc -g -I ./include
AFLAGS = -DAARCH=64 -mcpu=cortex-a72 -mlittle-endian -I ./include -O0 -g
CFLAGS = -DAARCH=64 -mcpu=cortex-a72 -mlittle-endian -Wall -fsigned-char -ffreestanding -g \
-I ./include -O0 -fno-exceptions
CPPFLAGS = -fno-exceptions -fno-rtti -nostdinc++ -DAARCH=64 -mcpu=cortex-a72 -mlittle-endian -Wall -fsigned-char \
-ffreestanding -g -I ./include -O0 -mstrict-align -std=c++14 -Wno-aligned-new
all: clean new kernel8.img
%.o: %.S
@echo "as $@"
@aarch64-none-elf-gcc $(AFLAGS) -c $< -o $@
%.o: %.c
@echo "gcc $@"
@aarch64-none-elf-gcc $(CFLAGS) -c $< -o $@
%.o: %.cpp
@echo "g++ $@"
@aarch64-none-elf-g++ $(CPPFLAGS) -c $< -o $@
kernel8.img: $(AllOBJS)
@echo "============================================================================="
@echo "Linking..."
@aarch64-none-elf-ld -o kernel8.elf -Map kernel8.map -nostdlib \
--section-start=.init=$(LOADADDR) --no-warn-rwx-segments \
-g -T linker.ld $(AllOBJS)
aarch64-none-elf-objcopy -O binary kernel8.elf kernel8.img
clean:
/bin/rm -f kernel8.elf kernel8.map *.o *.img > /dev/null 2> /dev/null || true
new:
/bin/clear
Speichern Sie diese Datei unter dem Namen Makefile.
Wenn Sie mehr über den Inhalt erfahren möchten, schauen Sie unter "Arbeiten mit Make und Linker-Script" nach.
Linker-Script (linker.ld)
Erstellen Sie das folgende Linker-Script, welches wir unter Arbeiten mit Make und Linker-Script beschrieben haben:
ENTRY(_start)
SECTIONS
{
.init : {
*(.init)
}
.text : {
*(.text*)
_etext = .;
}
.rodata : {
*(.rodata*)
}
.init_array : {
__init_start = .;
KEEP(*(.init_array*))
__init_end = .;
}
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
}
.eh_frame : {
*(.eh_frame*)
}
.data : {
*(.data*)
}
.bss : {
__bss_start = .;
*(.bss*)
*(COMMON)
__bss_end = .;
}
}
__bss_size = (__bss_end - __bss_start) >> 3;
Speichern Sie diese Datei unter dem Namen linker.ld.
Kompilieren und Ausführen
Nun können wir unser erstes Programm kompilieren:
make
Damit unser Kernel funktionsfähig ist, muss der Kernel auf eine SD-Karte, die in FAT32 formatiert ist, kopiert werden. Zusätzlich benötigt der Raspberry Pi 4 folgende Dateien auf der SD-Karte:
- bootcode.bin
- start.elf
- config.txt
- kernel8.img (Ihr kompiliertes Programm)
Den Source-Code können Sie als ZIP-Datei hier herunterladen.
| < Hauptseite > | Weiter (Lass die LED leuchten in C (PI4)) > |