Ich bin am Aufsetzen (für meine "Gesamtsystem") eines Setups für einen
LPC11Cx4 Controller.
Hier habe ich u.a. die Zuweisungen der Registernamen und Registerbits zu
ihren Adressen (mühselig) zusammengepfriemelt und es funktioniert bis
hierher auch recht ordentlich.
Allerdings habe ich sprichwörtlich jetzt einen Fehler im System:
Die Funktion
rand()
aus libc will nicht so richtig!
Diese ruft wohl __aeabi_lmul auf und diese Funktion wird nicht gefunden
(leider).
Mir eigentlich schleierhaft, weil ich dieselbe libc (genauso wie libgcc
und libm) für STM32F0 verwendet (allerdings mit libopencm3) und dort
funktioniert alles.
Die Fehlermeldung des Compiler / Linkers ist:
rand.c:(.text.rand+0x10): undefined reference to `__aeabi_lmul'
4
../lib/makefile.mk:49: recipe for target 'all' failed
5
make: *** [all] Error 1
Die Datei makefile.mk wird von Makefile inkludiert (damit ich den
funktionalen Teil nicht immer neu schreiben muss).
Im makefile.mk habe ich (natürlich... und wider besseren Wissens)
folgendes versucht:
Dadurch ist zwar der Fehler des Linkers weg, aber natürlich findet er
die Funktion dennoch nicht und rand() liefert immer denselben Wert.
Natürlich habe ich auch die libc_nano des arm-none-eabi-gcc ausprobiert,
mit demselben Ergebnis, als ob ich --start-group mit angebe: Der Fehler
im Compiler ist weg, rand() funktioniert denoch nicht !
Was kann ich tun ?
Ralph S. schrieb:> Dadurch ist zwar der Fehler des Linkers weg, aber natürlich findet er> die Funktion dennoch nicht und rand() liefert immer denselben Wert.
srand() aufgerufen...? Was heißt "findet die Funktion dennoch nicht"?
Sagt dir der Mikrocontroller "Ich finde die Funktion nicht"? Warum
linkst du mit "ld" und nicht mit "gcc"?
Programmierer schrieb:> srand() aufgerufen...?
Hab ich mit und ohne vorherigen Aufruf gemacht, gleiches Ergebnis.
Programmierer schrieb:> linkst du mit "ld" und nicht mit "gcc"?
Weil ld das Linkerprogramm ist ?!?
Ich hab mit beiden gelinkt, mit gcc und mit ld... das gleiche!
Programmierer schrieb:> Sagt dir der Mikrocontroller "Ich finde die Funktion nicht"?
Auf seine Art und Weise tut er das, weil er wohl irgendwas aus dem
Speicher nimmt, nur nicht das was er soll.
Ich nehme mir mal den Assembleroutput vor
Ralph S. schrieb:> Hab ich mit und ohne vorherigen Aufruf gemacht, gleiches Ergebnis.
Und auch hoffentlich jeweils was unterschiedliches an srand() übergeben?
rand() liefert Pseudo -Zufallszahlen, die direkt von dem an srand()
übergebenen Wert (seed) erzeugt werden! Wenn du srand() mit einem fixen
Wert aufrufst, kommt bei rand() immer die gleiche Folge raus.
Ralph S. schrieb:> Weil ld das Linkerprogramm ist ?!?>> Ich hab mit beiden gelinkt, mit gcc und mit ld... das gleiche!
Normalerweise linkt man mit "gcc", welcher intern "ld" aufruft und dabei
automatisch mit der libc und der libgcc linkt, sodass man die nicht mehr
angeben muss. Für C++ linkt man mit "g++" welches dann auch die
libstdc++ einbindet.
Ralph S. schrieb:> Auf seine Art und Weise tut er das, weil er wohl irgendwas aus dem> Speicher nimmt, nur nicht das was er soll.
Kann eigentlich nicht. Der Linker produziert kein (statisches) Programm
mit fehlenden Funktionen. Ich tippe darauf, dass alles richtig
funktioniert und du lediglich srand()/rand() nicht korrekt verwendest...
Ralph S. schrieb:> Ich nehme mir mal den Assembleroutput vor
Auch eine gute Idee.
PS: In C++ gibt es die <random> Library, welche verschiedene
Zufallszahlengeneratoren mit unterschiedlichen Eigenschaften bietet, was
flexibler als rand() ist.
Programmierer schrieb:> Und auch hoffentlich jeweils was unterschiedliches an srand() übergeben?> rand() liefert Pseudo -Zufallszahlen, die direkt von dem an srand()> übergebenen Wert (seed) erzeugt werden! Wenn du srand() mit einem fixen> Wert aufrufst, kommt bei rand() immer die gleiche Folge raus.
Weiß ich ...
Programmierer schrieb:> Normalerweise linkt man mit "gcc", welcher intern "ld" aufruft und dabei> automatisch mit der libc und der libgcc linkt, sodass man die nicht mehr> angeben muss. Für C++ linkt man mit "g++" welches dann auch die> libstdc++ einbindet.
Weiß ich auch, g++ ist hier uninteressant weil plain C ist.
Programmierer schrieb:> Kann eigentlich nicht. Der Linker produziert kein (statisches) Programm> mit fehlenden Funktionen. Ich tippe darauf, dass alles richtig> funktioniert und du lediglich srand()/rand() nicht korrekt verwendest...
Ganz sicher funktioniert NICHT alles korrekt, aber für dich jetzt:
Natürlich habe ich auch CC als Linker versucht:
Das hier produziert 150 mal den Zahlenwert : 4976
Lasse ich den obigen Code auf AVR laufen (mit der der Toolchain
zugehörigen libc) oder auf einem STM32 (in Verbindung mit libopencm3)
oder auf einem MSP430 generiert das obige Programmschnipsel 150
unterschiedliche Zahlenwerte (die logischerweise beim Programmstart
immer die gleiche Zahlenfolge hat).
Da das Setup für diesen LPC von mir händisch eingerichtet ist, ist
sicherlich im Setup ein Fehler und nicht im C-Code an sich (sonst würde
er nicht auf unterschiedlichen Systemen laufen) ... ein Test auf der
Konsole erspare ich mir, weil ich mir sicher bin, dass es dort auch
funktioniert.
Irgendetwas stimmt nicht mit dem Aufruf von rand / lmul ... und
natürlich bin ich mit dem Assembleroutput noch nicht durch.
Programmierer schrieb:> In C++ gibt es die <random> Library, welche verschiedene> Zufallszahlengeneratoren mit unterschiedlichen Eigenschaften bietet
Na ja, ich möchte hier aber kein C++ haben. Auf größeren Controllern
bisweilen (sehr) gerne, hier aber nicht !
Ralph S. schrieb:> srand(2020);> for (x= 0; x < 150; x++)> {> z= rand();> z= z % 0x7fff;> if ((x % 20) == 0) printf("\n\r");> printf("%d ",(int16_t) z);> }
Kannst du vielleicht einen einfacheren Code ausprobieren? Ich blick
gerade nicht ganz durch was du mit diesem Modulo und dem Cast machen
willst. Wie wärs mit:
1
for(intx=0;x<150;++x){
2
intz=rand();
3
if((x%20)==0)printf("\r\n");
4
printf("%d ",z);
5
}
\n\r ist auch kurios... Nicht dass das dein Terminal-Programm
durcheinander bringt ;-)
Ralph S. schrieb:> Ganz sicher funktioniert NICHT alles korrekt, aber für dich jetzt:
Nicht gleich so aggressiv.
Ralph S. schrieb:> Na ja, ich möchte hier aber kein C++ haben. Auf größeren Controllern> bisweilen (sehr) gerne, hier aber nicht !
Ist auf einem Cortex-M0 überhaupt kein Problem, aber egal.
Ralph S. schrieb:> Irgendetwas stimmt nicht mit dem Aufruf von rand / lmul ... und> natürlich bin ich mit dem Assembleroutput noch nicht durch.
Wenn du den Assembler-Output eines Minimal-Programms mit rand() und
srand() zeigst (mit zugehörigem C-Code oder gleich ganzem Projekt) kann
man sich den ansehen.
Deinem Linker-Script mangelt es übrigens dramatisch an
Alignment-Anweisungen (besonders wichtig für den M0, da der gar kein
Unaligned kann). Probier mal:
1
MEMORY
2
{
3
flash : org = 0x00000000, len = 32k
4
ram : org = 0x10000000, len = 4k
5
}
6
7
SECTIONS
8
{
9
. = ORIGIN(flash);
10
.text :
11
{
12
. = ALIGN(4);
13
KEEP(*(.vectors)); /* The interrupt vectors */
14
. = ALIGN(4);
15
*(.text);
16
*(.text*);
17
. = ALIGN(4);
18
} >flash
19
20
. = ORIGIN(ram);
21
.data (NOLOAD) :
22
{
23
. = ALIGN(4);
24
INIT_DATA_VALUES = LOADADDR(.data);
25
INIT_DATA_START = .;
26
*(.data);
27
*(.data*);
28
. = ALIGN(4);
29
INIT_DATA_END = .;
30
} >ram AT>flash
31
32
.bss (NOLOAD) :
33
{
34
. = ALIGN(4);
35
BSS_START = .;
36
*(.bss);
37
*(.bss*);
38
. = ALIGN(4);
39
BSS_END = .;
40
} > ram
41
}
So kannst du den Startup-Code auch beschleunigen indem du immer
4-Byte-Werte überträgst.
Außerdem solltest du die Symbole mit einem Unterstrich beginnen, denn
z.B. "INIT_DATA_VALUES" ist ein gültiger C-Bezeichner und kann somit mit
normalen C-Symbolen kollidieren; wenn du da z.B. "_INIT_DATA_VALUES"
draus machst kann das nicht passieren, weil so ein Bezeichner in C
reserviert ist.
Ich denke, du haust hier was durcheinander. "__aeabi_lmul" und ähnlich
benamte Funktionen sind Teil des Compilers und dienen dazu, komplexere
Funktionen zu implementieren, üblicherweise welche, die die CPU nicht
direkt kann (hier z.B. eine 64-bit-Multiplikation). Diese befinden sich
im libgcc[1] - das libc hat damit nichts zu tun.
Dein Problem wird genauso auch bei z.B.:
1
longlonga,b;
2
3
longlongfoo(){returna*b;}
4
5
intmain(intargc,char**argv)
6
{
7
returnfoo();
8
}
auftreten.
[1] Das libgcc ist compiler- und mcpu/march/mabi-abhängig - jede Version
des Compilers hat für jede unterstützte CPU/Architektur/ABI ein eigenes
libgcc; bei Crosscompilern muß man darauf achten, dass das richtige
genommen wird! Der gcc-Frontend macht das normalerweise richtig, beim
direkten ld-Aufruf muß man sich evtl selbst darum kümmern.
Programmierer schrieb:> Kannst du vielleicht einen einfacheren Code ausprobieren? Ich blick> gerade nicht ganz durch was du mit diesem Modulo und dem Cast machen> willst.
Das printf ist eine eigene Implementierung... und das verwendete
Terminal ist ein modifiziertes picocom.
\n\r trennt im Terminal die newline und das carriage return
So kann ich mit einfachsten Mitteln im Terminal beispielsweise mit
printf(" %.2f V \r", volt);
sorgen, dass der Cursor nur an den Anfang der Zeile springt und das
Terminal NICHT scrollt. Somit kann ich eine einfache Ausgabe an immer
der gleichen Stelle im Terminal machen
\n\r ist demnach eine neue Zeile und ein carriage return (MS-DOS,
Windows-Style)
Programmierer schrieb:> was du mit diesem Modulo und dem Cast machen> willst
den Cast mache ich, weil meine Implementierung von printf nur
16-Bitwerte akzeptiert... der Modulo soll eben nur Zahlen von 0 bis
32767 generieren.
Programmierer schrieb:> Nicht gleich so aggressiv.
Entschuldigung !
foobar schrieb:> 1] Das libgcc ist compiler- und mcpu/march/mabi-abhängig - jede Version> des Compilers hat für jede unterstützte CPU/Architektur/ABI ein eigenes> libgcc; bei Crosscompilern muß man darauf achten, dass das richtige> genommen wird!
Ich weiß nicht, wie oft ich das jetzt schon kontrolliert habe, ob das
die richtigen sind.
foobar schrieb:> Dein Problem wird genauso auch bei z.B.:long long a,b;>> long long foo() { return a*b; }>> int main(int argc, char **argv)> {> return foo();> }> auftreten.
stimmt, tut es.
Programmierer schrieb:> Deinem Linker-Script mangelt es übrigens dramatisch an> Alignment-Anweisungen (besonders wichtig für den M0, da der gar kein> Unaligned kann). Probier mal:
ich werde es ausprobieren
foobar schrieb:> Diese befinden sich> im libgcc[1]
Das werde ich mir jetzt noch einmal sehr viel deutlicher ansehen ... und
nicht die libc... (allerdings habe ich die was weiß ich schon wie oft
kontrolliert, ob das auch die des Compilers ist).