Forum: Mikrocontroller und Digitale Elektronik Raspberry PI Makefile Problem


von Manfred B. (fredl0511)


Angehängte Dateien:

Lesenswert?

Hallo,

habe ein Problem mit der Einbindung von *.S Dateien in mein Raspberry Pi 
C-Projekt. (gcc Compiler).

Ich möchte Versuchen den System Timer zu verwenden (Interrupt Auslösung 
alle paar ms) wie im folgenden Projekt gemacht wurde:

Die Assembler Datein stammen aus: 
https://github.com/dwelch67/raspberrypi/tree/master/blinker07

kleiner Auszug:

extern void PUT32 ( unsigned int, unsigned int );
extern unsigned int GET32 ( unsigned int );
.
.
.
ra=GET32(GPFSEL1);

Ich muss nun die Funktionen GET32 und PUT32 aufrufen welche anscheinend 
in einem Assembler File vorliegen. Ich habe leider keinen Plan wie ich 
z.B. die Datei vectors.S (dort kommt GET32 und PUT32 vor) in mein 
Makefile einbinden muss.

Mein Makefile sieht momentan so aus:

CC=gcc
CFLAGS=-I.
LDFLAGS  = -L/usr/local/lib
INCLUDE  = -I/usr/local/include
AS       = nasm
ASFLAGS  = -f coff

DEPS = uVGA2.h wiringPi.h wiringSerial.h
OBJ = test.o uVGA2.o wiringPi.o wiringSerial.o
LIBS+=-lwiringPi -lpthread -lrt -lbcm2835

%.o: %.c $(DEPS)
  $(CC) -c -o $@ $< $(CFLAGS)


%.o: %.S start.S vectors.S
  $(AS) $(ASFLAGS) $<


test: $(OBJ)
  $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

#Cleanup
.PHONY: clean

clean:
  rm -f *.o *~ core *~


Was muss ich im Makefile nun noch dazuschreiben um diese Assembler Files 
mit kompilieren zu können???? Bin dankbar für Tipps!

lg
Manfred

von Lukas K. (carrotindustries)


Lesenswert?

Seh' dir doch mal das Makefile in dem von dir verlinkten Repo an:
1
vectors.o : vectors.s
2
    $(ARMGNU)-as vectors.s -o vectors.o

Deine Makefile wird allerding so nur funktionieren wenn du entweder
a) Auf dem Raspberry pi kompilierst
b) der GCC in $path der gcc für ARM ist

Besser wäre es, in der Makefile direkt den GCC für ARM 
(arm-unknown-linux-gnueabi-gcc) anzugeben.

Manfred Brunni schrieb:
> Was muss ich im Makefile nun noch dazuschreiben um diese Assembler Files
> mit kompilieren zu können????
Assembler-Quellen werden nicht kompliert, sie werden assembliert. Dazu 
brauchst du einen Assembler (as, bzw arm-unknown-linux-gnueabi-as) 
Dieser erzeugt dir eine Objektdatei, welche vom Linker mit den vom 
Compiler erzeugten Objektdateien zum ausführbaren BLOB verknüselt 
werden.

von Manfred B. (fredl0511)


Lesenswert?

Hallo Lukas,

danke für deine Antwort jedoch kann ich dir leider nicht wirklich folgen 
da meine Kenntnisse da leider zu gering sind. :-/

Ich programmiere momentan am PI direkt, also wird auch alles dort 
kompiliert.

das obere Makefile funktioniert ja auch für die ganze C-Files und Header 
files welche ich zusätzlich verwende, aber was muss ich nun zusätzlich 
im makefile für die *.S Dateien eingeben damit diese dann assembliert 
und dem Linker übergeben werden?

lg
manfred

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Ist das *.s nicht case sensitive bei Unixoiden ?

von Manfred B. (fredl0511)


Lesenswert?

hallo joachim,

ja das stimmt wahrscheinlich, hab irgendwo gelesen, dass die endung .S 
statt klein .s lauten muss. hab ich abgeändert, auch im makefile.

lg manfred

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Manfred Brunni schrieb:
> $(AS) $(ASFLAGS) $<

Was soll eigentlich die leere Pipe ?
Kommen Fehlermeldungen ?

von Manfred B. (fredl0511)


Lesenswert?

Nein, Fehlermeldungen werden keine angezeigt. Außer natürlich ich 
verwende die GET32 oder PUT32 funktion, dann regnet es undefined 
reference to GET32 ..

was passiert da eigentlich im dem schnipsel auf dem Auszug der 
vectors.S:

.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

könnte man da auch direkt im C-Code mittels inline assembler eine 
funktions schreiben die dann den inhalt eines bestimmten registers 
übergibt.

verstehe irgendwie den Weg von extern unsigned int GET32 ( unsigned int 
) zu der schlussendlichen GET32 Funktion nicht. wo und wie übergibt die 
GET32 Funktionen den Registerwert? Sorry hab keine asm Kenntnisse.

lg
manfred

von Lukas K. (carrotindustries)


Lesenswert?

Joachim Drechsel schrieb:
> Manfred Brunni schrieb:
>> $(AS) $(ASFLAGS) $<
>
> Was soll eigentlich die leere Pipe ?
> Kommen Fehlermeldungen ?

Makefiles sind keine Shellskripte.
http://www.ijon.de/comp/tutorials/makefile.html#pattern
>$<  die erste Abhängigkeit

Wenn ich die READMEs im git richtig verstanden hab, ist das 
baremetal-Programmierung ohne OS drunter, willst du das wirklich?

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Manfred Brunni schrieb:
> Sorry hab keine asm Kenntnisse.

Ja - bleed. Und ich habe auf dem RPi das alles noch nicht probiert ;)

Fakt ist, der Linker findet die Funktion aus irgendeinem Grund
nicht. Wenn diese in einem Quellfile definiert ist sollte das klärbar
sein.

von Lukas K. (carrotindustries)


Lesenswert?

BTW: ich habe hier auch ein Raspbberry pi, wenn du hier ein 
vollständiges Beispiel posten würdest, kann das zur Fehlersuche 
beitragen.

von Manfred B. (fredl0511)


Lesenswert?

Lukas K. schrieb:
> Wenn ich die READMEs im git richtig verstanden hab, ist das
> baremetal-Programmierung ohne OS drunter, willst du das wirklich?

was genau meinst du damit? Probleme mit Linux?

Es werden ja nicht alle Timer benötigt, Timer 1 soll ja frei sein. Es 
wäre halt fein wenn man z.B. System Timer Compare 1 (Seite 172 im 
Broadcom Manual) benutzen kann damit dieser im Hintergrund unabhängig 
nach einem Match einen Interrupt auslöst oder einfach nur das zugehörige 
Flag zum Abruf bereit stellt.

Zum Spielen würde es ja schon mal ausreichen wenn man in einem main 
Programm die GET32 und PUT32 Befehle ausführen kann um z.B. folgende 
Funktion vom ersten Link zu testen.

if(1)
{
    //use the counter match and the counter match flag in the counter
    //status register

    interval=0x00100000;
    rx=GET32(CLO);
    rx+=interval;
    PUT32(C1,rx);
    PUT32(CS,2);
    for(rb=0;rb<4;rb++)
    {
        while(1)
        {
            ra=GET32(CS);
            if(ra&2) break;
        }
        rx+=interval;
        PUT32(C1,rx);
        PUT32(CS,2);

        PUT32(GPCLR0,1<<16); //led on

        while(1)
        {
            ra=GET32(CS);
            if(ra&2) break;
        }
        rx+=interval;
        PUT32(C1,rx);
        PUT32(CS,2);

        PUT32(GPSET0,1<<16); //led off
    }
}

https://github.com/dwelch67/raspberrypi/blob/master/blinker07/blinker07.c

Kann auch sein, das ein solches Vorhaben im Verbindung mit Linux drauf 
als OS sowieso zum Vergessen ist. Mir geht eben Flexibilität wie man sie 
bei einem standard µC ohne OS hat ein wenig ab. (Zugriff auf die ganze 
Peripherie etc. auf Low Level Ebene halt).

Lg Manfred

von Lukas K. (carrotindustries)


Lesenswert?

Manfred Brunni schrieb:
> Kann auch sein, das ein solches Vorhaben im Verbindung mit Linux drauf
> als OS sowieso zum Vergessen ist. Mir geht eben Flexibilität wie man sie
> bei einem standard µC ohne OS hat ein wenig ab. (Zugriff auf die ganze
> Peripherie etc. auf Low Level Ebene halt).
>
> Lg Manfred

Du hast praktisch zwei möglichkeiten deine Programme auf den Raspberry 
pi zum laufen zu bringen
a) Beliebige Linux-Distro: Dann unterscheidet sich das Raspberry pi bis 
auf andere CPU, vergleichsweise geringen Performance und das 
Vorhandensein diverser Hardware-Einheiten nicht übermäßig von einen 
generischen Linux-Rechner. Mit allen üblichen Einschränkungen eines 
Betriebssystemns wie keinem direkten Hardware-Zugriff.

b)Baremetal, also ohne Betriebssystem: Du gibst dem Bootloader statt dem 
Linux-Kernel dein eigenes BLOB mit auf den Weg. Vorteil: du kannst nach 
belieben in der Hardware rumstochern, kein Kernel und niemand hindert 
dich daran. Nachteil: du musst  praktisch alles "von Hand zu Fuß" 
machen, UART, Grafikausgabe, einfach alles

Ich persönlich würde von b) deutlich Abstand nehmen. Wenn meine 
Anwendung für den Raspberry Pi timingkritische Teile enthält, flansche 
ich entweder einen µC an oder schreibe, wenn mir danach ist ein 
Kernelmodul.

Wie üblich daher die Frage: WAS willst du erreichen, nicht was für 
Ansätze hast du bereits unternommen.

von Lukas K. (carrotindustries)


Lesenswert?

WO liegt nun eigentlich so genau dein Problem?

Ich hab mir mal das git-repo geklont, den blinker07 auf dem PC 
cross-compiliert (direkt aufm raspi bauen geht genauso): meinen 
cross-Compiler (ich war faul und hab den bereits gebauten von 
http://archlinuxarm.org/developers/distcc-cross-compiling genommen) in 
$PATH geworfen, in der Makefile das Präfix angepasst 
(arm-unknown-linux-gnueabi) mit make gebaut, die blinker07.bin auf die 
Boot-Partition der SD-Karte kopiert, in der config.txt
1
kernel=blinker07.bin
 eingetragen, die SD-Karte eingeworfen und die LED-Blinkt wie sie es 
sollte.

von Manfred B. (fredl0511)


Lesenswert?

Hallo Lukas,

vielen Dank für deine Tipps. Eine direkte zeitkritische Anwendung habe 
ich momentan (noch) nicht, bin noch bezüglich Raspberry Pi am Anfang und 
möchte mich langsam herantasten was so alles möglich ist und wie weit 
man die Peripherie ansteuern kann.

Nach deinem Posting bin ich nun aufgeklärter. Ich dachte mir, ich kann 
von Linux aus auf z.B. Timer Compare Register zugreifen und den Inhalt 
so direkt manipulieren.

Ich wusste nicht, dass das die blink07 Programm statt dem Linux auf die 
SD Karte muss also dort gar kein Linux als OS läuft.

vom µC Programmieren ist man eben gewohnt z.B. einen Background Timer zu 
starten der z.B. alle 100ms überläuft und in seiner ISR eine Variable 
hochzählt, irgendwas abfragt etc. also nicht vom eigentlichem 
Hauptprogramm abhängig ist (Polling)

Ich habe das am PI nun so gelöst, dass ich aus der time.h 
timespec.tv_nsec verwende (System Timer in nano Sek.) und in einem 
Thread (verwende dafür die Funktion "piThreadCreate" aus "wiringPi.h") 
der parallel zum Hauptprogramm abläuft, abfrage ob bereits 100ms 
vergangen sind. somit habe ich einen einergermaßen brauchbaren 100ms 
takt.

Ist zwar kein direkter Interrupt aber was anderes als Threads zu 
erzeugen (also quasi Polling) welche die Multitaskingfähigkeit von einem 
OS ausnützt, bleibt ja nicht übrig oder, aber gut mit 700MHz Systemtakt 
geht das ja schon recht flott :-)

Lg
Manfred

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.