Am Anfang war die LED…

Raspberry Pi

Den Anfang mache ich (mal wieder ;) ) mit der guten alten LED. In diesem Artikel geht es darum eine LED zu aktivieren und sie blinken zu lassen. Für ein besseres Verständnis ist es ratsam das BCM2835 Peripherie Datenblatt zur Hand zu haben (Link), da für die Lösung der Aufgabenstellung einige Registeradressen benötigt werden.
Es kann außerdem nicht schaden, wenn ihr zusätzlich das ARM Befehlsdatenblatt offen habt. In diesem Dokument sind alle verfügbaren ARM Befehlscodes vermerkt (Link).

Ok los geht´s…

-> Die Ordnerstruktur:

Für die spätere Kompilierung wird ein Makefile benötigt, welches der Cross Compiler verwendet.
Der Einfachheit halber habe ich diesen Ordner runter geladen und ihn als Ausgangsverzeichnis verwendet.
In diesem Ordner findet ihr einen Unterordner mit Namen source. Hier werden alle Assemblerfiles abgelegt. Dieser Ordnerinhalt wird nachher durch das Tool make des Cross Compilers kompiliert und zu einem Kernelimage zusammen gebaut.
Genauere Informationen hierzu stehen in der Datei Makefile, welche wir uns mal anschauen.
Diese Datei kann z.B. mit Programmer´s Notepad geöffnet werden. Wirklich wichtig sind für uns nur die ersten paar Punkte, da ich (noch) nicht so tief in den Aufbau eines Make-Files einsteigen will:

ARM_LED(1)

Der erste Punkt gibt den verwendeten Compiler an. In diesem Fall ist es der Compiler arm-none-eabi für eine sogenannte bare Metall Programmierung. Als bare Metall Programmierung wird das Programmieren ohne Betriebssystem bezeichnet. Man startet ohne jegliche Software und Schnittstellen und  baut sich alles selber zusammen.
Der zweite und der dritte Punkt gibt das Verzeichnis für die kompilierten Objekte bzw. Sourcefiles an. Dabei wird das Verzeichnis des Makefiles als Ausgangspunkt verwendet.
Im vierten Punkt legt man den Namen des erzeugen Kernelimages fest. Der Name sollte immer kernel.img heißen!
Die nächsten beiden Punkte geben die Dateinamen des Listingfiles und des Mapfiles an und interessieren uns nicht wirklich.
Und der letzte Punkt gibt den verwendeten Linker an. Der Linker sorgt dafür, dass alle verwendeten Programmteile zu einem ausführbaren Programm zusammen gesetzt werden.
Am besten ihr verändert keinen der Punkte, dann gibt es auch keine Probleme ;)

-> Eine LED einschalten:

Nun beginnen wir mit dem ersten Programm. Hierfür legen wir im Programmer´s Notepad eine neue Assemblerdatei  an und speichern sie unter main.s:

ARM_LED(2)

Ziel ist es, dass wir eine LED an GPIO 24 aktivieren. Die LED wird dabei so angeschlossen:

ARM_LED(3)

Jetzt geht der spaßige Teil los!
Wir müssen uns das Datenblatt der BCM2835 Peripherie zu Gemüte führen. Auf S. 89 beginnt die Sektion über die GPIO, welche wir benötigen und auf S.90 ist die Registerübersicht.
Zu aller erst stellen wir den GPIO als Ausgang ein. Dies wird über die Register GPFSELn gemacht. Wenn man das Datenblatt etwas weiter ließt, sieht man ab S. 92 das die GPIO unterteilt sind. Register 0 deckt die GPIO 0 – 9 ab, Register 1 die GPIO 10 – 19, usw.
Da wir den GPIO 24 ansteuern wollten, benötigen wir dem entsprechend Register 2. Ok, also wieder zurück scrollen auf Seite 90 für die Registerübersicht. Dort sehen wir das Register GPFSEL2 bei der Adresse 0x7E200008 anfängt. Dieses Register müssen wir also beschreiben.
Schauen wir uns das Register auf Seite 93 mal genauer an. Dort steht eine genaue Auflistung der Unterteilung des Registers für GPIO 29. Um unseren GPIO 24 als Ausgang einstellen zu können, müssen wir also in den Bereich FSEL24 den Wert 001 rein schreiben.
Aber Vorsicht! Es kann nur das ganze Register beschrieben werden. Bei dem Raspberry Pi sind alle Register 32 Bit groß, sprich wir müssen folgenden Wert schreiben:

ARM_LED(4)

Gut damit wäre alles wichtige gesagt oder? Nein, noch nicht ganz. Das Thema Registeradressen ist noch ein bisschen komplizierter. Wir haben ja eben gesehen, dass in der Tabelle stand, dass das Register die Adresse 0x7E200008 hat. Leider trifft das nur in dem Fall zu, dass wir ein Betriebssystem verwenden. Ohne Betriebssystem sind wir an die physikalischen Adressen des Chips gebunden.
Eine Übersicht dazu findet sich auf S. 5 im Datenblatt:

ARM_LED(5)

Für uns ist der eingekreiste Bereich interessant. Unsere Adresse lautet somit also nicht 0x7E200008 sondern 0x20200008 (das FE wird zu 20).
Nun sind aber alle Komponenten vorhanden. Verpacken wir das ganze mal in einen Code.
Die ersten drei Zeilen müssen immer gleich bleiben. Sie dienen quasi als Einstigspunkt für den Prozessor:

Im nächsten Schritt speichere ich die Basisadresse bzw. die Anfangsadresse des GPIO Controllers. Diese lautet 0x20200000 und ist in der Tabelle auf S. 90 zu finden (das Umrechnen der Adresse nicht vergessen!). Die Adresse wird im Register r0 gespeichert:

Mit den nächsten beiden Schritten speichere ich das Bit um den GPIO 240 als Ausgang zu deklarieren. Hierfür speichere ich eine 1 in einem Register und schiebe die 1 um 12 Stellen nach links.

Eine andere Möglichkeit wäre, den Wert als Hexadezimalzahl abzuspeichern. Ist beides gleichbedeutend, nur die eine Variante ist besser zu lesen als die andere.
Jetzt wird der Wert in das entsprechende GPFSEL Register geschrieben.
Hierfür wird dieser Befehl verwendet:

Dieser Befehl macht nichts anderes als den Wert von Register r1 zu der in Register r0 und um den Wert 8 erhöhte Adresse zu kopieren.
Der nächste Schritt besteht darin, den Ausgang auf Low zu setzen. Der Chip verfügt für diesen Fall über ein GPIO Pin Output Clear Register (GPCLRn), welches nur zum zurück setzen des GPIO da ist. Jedes Register deckt bis zu 32 GPIO ab, wobei jedes Bit für den jeweiligen GPIO steht (Register 0 Bit 0 -> GPIO 0,
Register 0 Bit 1 -> GPIO 1, etc).
Um den GPIO 24 zu löschen müssen wir laut dem Datenblatt also Bit 24 des Registers GPCLR0 setzen.
Also die Schritte von eben wiederholen:

Es muss jetzt allerdings der Adressoffset auf 40 und die Anzahl an Shifts auf 24 geändert werden.
Als letztes fügen wir noch eine Endlosschleife ein, damit das Raspberry was zu tun hat und keine Fehler produziert:

Mein Template-Verzeichnis habe ich umbenannt und ist bei

C:\Users\Daniel\Desktop\Raspberry Pi ARM\LED(1)

zu finden. Jetzt wird die Datei in

C:\Users\Daniel\Desktop\Raspberry Pi ARM\LED(1)\source

als main.s gespeichert und dann eine Konsole geöffnet. In der Konsole müsst ihr nun in das Verzeichnis des Projektes wechseln:

ARM_LED(6)

Um den Kompiliervorgang zu starten, gebt ihr make ein und drückt auf Enter. Wenn folgende Meldung erscheint, war der Vorgang erfolgreich:

ARM_LED(7)

In dem Projektverzeichnis sind nun einige Dateien erzeigt worden:

ARM_LED(8)

Alles was ihr jetzt noch benötigt ist eine SD-Karte mit einem bereits installierten Betriebssystem. Diese Karte steckt ihr in den Kartenleser eures Computers und ersetzt die vorhandene Datei kernel.img durch die von euch erzeugte Datei kernel.img. Danach entfernt ihr die Karte, steckt sie in euer Raspberry Pi und gebt Strom drauf.
Jetzt sollte die angeschlossene LED leuchten.

 

Dokumentation:

  • Quellcode
    -> LED

 

-> Zurück zu Raspberry Pi Assembler

24 thoughts on “Am Anfang war die LED…
  1. C:\Users\patrick\Desktop\template\template>make
    arm-none-eabi-ld –no-undefined -Map kernel.map -o build/output.elf -T kernel.l
    d
    process_begin: CreateProcess(NULL, arm-none-eabi-ld –no-undefined -Map kernel.m
    ap -o build/output.elf -T kernel.ld, …) failed.
    make (e=2): Das System kann die angegebene Datei nicht finden.
    make: *** [build/output.elf] Error 2

    was funktioniert denn hier nicht? die led.asm datei ist im source ordner ??
    Danke

  2. Hallo Daniel,

    vielen Dank für die wirklich schnelle Antwort und entschuldige bitte, dass ich schon wieder störe. Aller Anfang ist schwer. Beim Compiilieren erhalte ich folgende Fehlermeldungen:
    C:\ASM>make
    MAKE Version 5.2 Copyright (c) 1987, 1998 Inprise Corp.
    ld –no-undefined -Map kernel.map -o build/output.elf -T kernel.ld
    Der Befehl „ld“ ist entweder falsch geschrieben oder konnte nicht gefunden werden.
    objcopy build/output.elf -O binary kernel.img
    Der Befehl „objcopy“ ist entweder falsch geschrieben oder konnte nicht gefunden werden.
    objdump -d build/output.elf > kernel.list
    Der Befehl „objdump“ ist entweder falsch geschrieben oder konnte nicht gefunden werden.

    Ich habe die 3 Tools mehrmals neu installiert und habe dabei nie eine Fehlermeldung erhalten. Was habe ich falsch gemacht? Im Ordner ASM liegen 3 Dateien und der Ordner source mit der Datei main.s .

      • Hi Daniel,

        das ging ja extrem schnell – Danke!

        make – version wird beantwortet mit „Incorrect command line argument: – version“ und ca. 20 Optionen zur Syntax.
        Die zweite Antwort lautet:
        arm-none-eabi-gcc: error: unrecognized command line option ‚-version‘
        arm-none-eabi-gcc: fatal error: no input files
        compilation terminated.

        Gruß
        Bernd

          • Hi Daniel,

            zur 1. Abfrage:
            MAKE Version 5.2 Copyright (c) 1987, 1998 Inprise Corp.
            Incorrect command line argument: –version
            und dann wieder die 20 Optionen
            zur 2. Abfrage:
            arm-none-eabi-gcc (GCC) 4.7.2
            Copyright (C) 2012 Free Software Foundation, Inc.
            This is free software; see the source for copying conditions. There is NO waranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

            Grüße
            Bernd

        • Bitte die Windows Enviroment Variable PATH anschauen! Damit das „richtige“ make benutzt wird, muss das richtige make Verzeichnis am Anfang stehen.

  3. Hi Daniel,

    meine letzte Frage: An welcher Stelle erkennst Du was? Lasse Dir Zeit! Wichtig ist für mich nur das Ergebnis, dass ich den Cross Compiler nutzen kann.

    MfG
    Bernd

    • Hallo Bernd,

      ich habe es gerade noch mal getestet.
      Du installierst die Tools (als Admin und mit den Defaultpfaden) und lädst dir mein Beispielprogramm runter.
      Das entpackst du z.B. bei dir auf dem Desktop und löscht die Dateien „kernel.img“, „kernel.list“, „kernel.ld“ und den Inhalt von „build“.
      Anschließend öffnest du eine neue Konsole (wenn du die bei der Installation der Tools offen hattest, musst du die einmal schließen, damit die PATH-Variable neu geladen wird) und wechselst in das Verzeichnis des Beispielprogrammes.
      Dort tippst du dann „make“ ein und dann sollte es funktionieren.

      Probier das mal bitte so und wenn es nicht klappt einfach noch mal melden (wenn du einen Linux Rechner hast, kannst du es auch damit machen…da ist es einfacher als mit Windows…).

      Gruß
      Daniel

      • Hallo Daniel,

        habe alle 3 Tools nochmals als Admin in die Defaultpfade installiert. Dein Beispielprogramm in meinem Arbeitsordner entpackt, die 3 Kernel-Dateien gelöscht und auch die 2 Dateien im build ordner gelöscht. Die Windowseingabeaufforderung geöffnet, den Pfad zu meinem Arbeitsordner eingestellt und make eingetippt. Das Ergebnis ist:
        MAKE Version 5.2 Copyright (c) 1987,1998 Inprise Corp.
        Fatal: ‚kernel.ld‘ does not exist – don’t know how to make it
        Kopiere ich nun zusätzlich kernel.ld in meinen Arbeitsordner erscheint wieder die Fehlermeldung mit falsch geschrieben oder nicht gefunden.
        Vielleicht liegt’s an meinem System. Habe leider nur Win7 Ultimate 32bit. Oder es liegen noch alte Fragmente von den vorherigen Installationsversuchen im System. Werde heute Abend mal meinen XP-Laptop aktivieren. Es sieht aber eher nach einem Versionsproblem aus oder mir fehlt noch ein Tool.
        Warum geht’s bei Dir und bei mir nicht?

        Grüße
        Bernd

        • Hallo Bernd,

          tut mir leid das du so viele Probleme hast :(
          Das ist natürlich schwer zu erkennen woran es liegt und ich kann dir auch nicht sagen warum es bei mir funktioniert.
          Aber das sieht mir nach einem Problem mit dem Linkerskript aus.
          Hast du eventuell Leerzeichen oder Sonderzeichen im Dateipfad drin? Weil das kann schon mal gerne Probleme verursachen.

          Wie gesagt….so ein Cross Compiler unter Windows ist ein Krampf schlechthin. Mittlerweile nutze ich ein Ubunu für den Cross Compile Vorgang, da es dafür zahlreiche Anleitungen gibt und es auch einfacher funktioniert wie ich finde…

          Gruß
          Daniel

          • Hallo Daniel,
            nur zur Rückmeldung:
            Auch unter XP habe ich die gleichen Fehlermeldungen. Nur bei der Installation von MinGW mußte ich ein paar Fragen mehr beantworten. Gerade hab ich nochmals alles deinstalliert und neu angefangen. In der Konsole bei der MinGW Inst. fällt mir ein Abschnitt auf, der vielleicht die Ursache ist:
            c:\msys\1.0\postinstall>..\bin\sh.exe pi.sh
            AllocationBase 0x0, BaseAddress 0x715B0000, RegionSize 0xB0000, State 0x10000
            C:\msys\1.0\bin\sh.exe: *** Couldn’t reserve space for cygwin’s heap, Win32 error 0
            C:\msys\1.0\postinstall>pause
            Drücken Sie eine beliebige Taste . . .

            Mein Arbeitspfag lautet: C:\asm. Der sollte also auch keine Probleme machen. Vielleicht fällt Dir zur Fehlermeldung noch was ein.
            Vielen Dank für Deine Bemühungen

            Gruß
            Bernd

          • Hey Bernd,

            mmh mir fällt leider auch nichts mehr ein :(
            Was spricht den gegen eine VM (z.B. mit VirtualBox) und einem Ubuntu als OS? Dann kannst du den Cross Compiler unter Linux nutzen…da kann ich dir mehr mit helfen und das funktioniert sehr oft auch viel besser.

            Gruß
            Daniel

  4. Hallo Daniel,

    tolle Seite, habe schon cross compiled und muß noch das led-image am Raspi ausprobieren. Installationen haben super geklappt. Großes Lob für die Beschreibung ein Crossentwicklungssystem unter Windows für ARM zu installieren.

    Zwei kleine Fehler sind mir aufgefallen in Deiner Beschreibung und einen Vorschlag hätte ich noch.
    1. Im Text: müssen wir also in den Bereich FSEL24 den Wert 010 rein schreiben.
    Korrektur: der richtige Wert müsste 001 sein.
    2. Im Text: Um den GPIO 24 zu löschen müssen wir laut dem Datenblatt also Bit 24 des Registers GPCLR1 setzen.
    Korrektur: Registers GPCLR0 setzen

    Vorschlag:
    3. Im Text: Jetzt wird die Datei gespeichert und dann eine Konsole geöffnet. In der Konsole müsst ihr nun in das Verzeichnis des Projektes wechseln:

    Noch einmal Danke für die tolle Anleitung
    bachitoph

    Vorschlag: Mein Template-Verzeichnis habe ich umbenannt und ist bei C:\Users\Daniel\Desktop\Raspberry Pi ARM\LED(1) zu finden. Jetzt wird die Datei in C:\Users\Daniel\Desktop\Raspberry Pi ARM\LED(1)\source als main.s gespeichert und dann eine Konsole geöffnet. In der Konsole müsst ihr nun in das Verzeichnis des Projektes wechseln:

    • Hallo Bachitoph,

      danke für die Anmerkungen :)
      Die Fehler habe ich alle ausgebessert!

      Viel Erfolg weiterhin mit Assembler ;)

      Gruß
      Daniel

  5. Hallo Daniel,

    ich habe dein Tutorial seit mehr als 3 Stunden offen und versuche das nachzuvollziehen. Meiner Meinung nach sieht alles gut aus. Nur leider kriege ich meinen Raspberry v2 nicht dzau die LED zum leuchten zu bringen.
    Benutze normal Raspian und habe die Kernel7.img und die Kernel datei ersetzt geht das damit?

      • Hallo Daniel,

        danke für die HIlfe, mit einem Raspberry 1 habe ich es hinbekommen. Und habe schon erste Erweiterungen vorgenommen, an meinem Betriebssystem.

        7asper

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Time limit is exhausted. Please reload CAPTCHA.