Halo Kollegen.
Komme mit Initialisierung einer Struktur nicht weiter.
Mikrokontroller - STM32-F103-Olimex, IDE – Eclipse, Compiler - GCC,
G++
Der Compiler meckert nicht aber die Werte der initialisierten Struktur
sind falsch.
Die Struktur beschreibt einen Zeichensatz (Font) für die Ausgabe am LCD
Display.
1
//Display.h
2
3
#parma //--- wird vom Compiler ignoriert ???
4
5
typedefstruct{
6
constshort*table;// Tabelle mit den Font Daten
7
shortwidth;// Breite des Zeichens (in Pixel)
8
shortheight;// Hoehe des Zeichens (in Pixel)
9
}Font_t;
Anderen Daten und Code sind im „Display.c“ gesammelt um den Fehler zu
lokalisieren.
Die Font Tabelle (*table).
Font_tArial_7x10={//Variable Arial_7x10 erzeugen, Typ Font_t
2
.table=Arial_7x10_Table,// Adresse der ZeichenTabelle zuweisen
3
.width=7,// Schriftbreite setzen
4
.height=10// Schrifthöhe . . .
5
};
Beim Debuggen - kein Wert stimmt: Variable .width sollte = 7 sein,
.height = 10.
---Bild „StructDaten.png“
Tabelle hat eine falsche Adresse.
---Bild „Tabelle.png“.
Man könnte es mit der Tabellenadresse vergeigen, aber 2 anderen Werte
sind doch DIREKT zugewiesen.
Was mache ich falsch?????
Artur schrieb:> #parma //--- wird vom Compiler ignoriert ???
Dem fehlt der Schinken.
Regel#1 hier im Forum und auch anderswo: immer den Original-Quellcode
zeigen.
Regel#2 hier im Forum und auch anderswo: immer den ganzen Quellcode
zeigen.
Stackoverflow, Array out of bounds, oder wie auch immer du die Daten
überschreibst.
Oliver
Entweder dein Startupcode oder Linkerscript ist defekt, oder die
Variable Arial_7x10 wird von einem "wilden Pointer" überschrieben
(Buffer Overflow o.ä.).
Wenn das Programm ganz am Anfang ist (Anfang der main()), sind die Daten
dann richtig? -> Watchpoint drauf setzen und laufen lassen.
Sind die Daten da schon falsch? Breakpoint im Startupcode NACH das " bcc
CopyDataInit" setzen und schauen ob es dann stimmt - wenn ja, Watchpoint
setzen und laufen lassen. Wenn nein, ist was am Startupcode/Linkerscript
kaputt.
Niklas G. schrieb:>> Wenn das Programm ganz am Anfang ist (Anfang der main()), sind die Daten> dann richtig? -> Watchpoint drauf setzen und laufen lassen.>> von Oliver S. (oliverso)>Stackoverflow, Array out of bounds, oder wie auch immer du die Daten>überschreibst.>
Danke für den Tipp.
Hab einen kleine Struct erzeugt und diesen intialisiert an der gleichen
Stelle mit dem alten Struct - auch der neuer Strukt wurde falsch
initialisiert.
Am Anfang des Programms (Anfang der main()) hat alles sauber geklappt.
Muss mal sehen wie ich den Stack checken kann.
Artur schrieb:> Am Anfang des Programms (Anfang der main()) hat alles sauber geklappt.
Die Structs werden nicht durch "Magie" befüllt, das macht der µC schon
schön selber in seinem Startup-Code. Wenn du deinen Breakpoint zu früh
hast, kannst du dem µC zuschauen, wie er der Reihe nach seine globalen
Variablen und Structs initialisiert. Am Anfang von "main" ist er damit
fertig...
Artur schrieb:> Muss mal sehen wie ich den Stack checken kann.
Setze einfach einen Watchpoint auf das struct und lasse das Programm
laufen. Das Programm wird dann genau an der Stelle unterbrechen wo der
fehlerhafte Zugriff ist. Geht blitzschnell.
Warum ist der Font für das Display "Short" (das sind Bytes), und warum
sollte die Struct erst initialisiert werden müssen? Die ist doch wohl
hoffentlich im Flash? Oder ist der Prozessor behindert und kann
Displaydaten nur aus dem RAM lesen?
Jens M. schrieb:> Warum ist der Font für das Display "Short" (das sind Bytes)
Wenn der Font auch breiter werden kann als 8 Pixel, könnte das einen
Sinn haben - aber warum dann ein Datentyp mit Vorzeichen?
Niklas G. schrieb:> Nein, weil kein "const" dran steht kommt es in den RAM und muss erst> kopiert werden.
Soweit mir bekannt wird auch const bei manchen Prozessoren im RAM (oder
gar in Registern) gelagert, weil schneller/kürzer zugreifbar.
Zumindest bei AVRs muss man auch noch PROGMEM angeben, um es sicher ins
Flash zu packen.
Jens M. schrieb:> Soweit mir bekannt wird auch const bei manchen Prozessoren im RAM (oder> gar in Registern) gelagert
Ja, hängt vom Linkerscript ab. Aber beim STM32 wird normalerweise alles
was "const" ist in den Flash gelegt.
Hallo Kollegen.
Hatte in der Woche leider nicht viel Zeit aber immer hin gibt es ein
Ergebniss. . .
So lief es weiter
- die Tabelle(nur 2 Zeilen), die Definition der Struktur und die
Initialisierung --> ganz am Anfang der main() eingetragen -> hat
nicht geholfen
- die Tabelle fest definiert -> statt [] ein [2][10] eingetragen
Erst jetzt wurde der Struct ordentlich initialisiert - alle Werte in
den Variable richtig eingetragen.
- Definition der Struktur aus main() in "Display.h" versetzt -
funktionierte auch.
- komplette Tabelle am Anfang der Main() eingetragen (95 Zeilen).
Compiler hat sich "verschluckt" und ist mit der Meldung "undefined
reference to memcpy'" ausgestiegen.
Der Eintrag #include "string.h" hat nicht geholfen.
Erst eine weitere Ergänzung der Tabellendefinition mit "static" hat mich
weitergebracht
1
"static const unsigned short Arial_7x10_Table[95][10] . . . "
- Die gesamte Tabelle ins "Display.h" verschoben - geht auch :-)
Also mit einer Schrift (Font) könnte man es so belassen.
Wenn man aber 2 - 3 Fonts hat, wird die Header "überladen" wirken.
Geschickter wäre es pro Font eine Separate Datei zu haben - aber genau
das funktioniert noch nicht hinbekommen.
Bin dran :-)))
Artur schrieb:> - komplette Tabelle am Anfang der Main() eingetragen (95 Zeilen).> Compiler hat sich "verschluckt" und ist mit der Meldung "undefined> reference to memcpy'" ausgestiegen.
Spätestens an der Stelle sollte klar sein, daß deine toolchain kaputt
ist.
Oliver
Oliver S. schrieb:> Spätestens an der Stelle sollte klar sein, daß deine toolchain kaputt> ist.
Es ist extrem unwahrscheinlich, dass der GCC bei so etwas simplen
versagt.
Artur schrieb:> So lief es weiter
Du doktorst an den Symptomen rum. Du hast irgendwo einen Buffer Overflow
o.ä. Den findest du so nicht. Der wird dich später anderweitig in den
allerwertesten beißen, du hast so eine Zeitbombe im Code.
Auf die Gefahr mich zu wiederholen: Benutze einen Data Watchpoint. Damit
hast du das eigentliche Problem in 2 Minuten gefunden. Ohne
Rätselraten und Rumprobieren.
Niklas G. schrieb:> Es ist extrem unwahrscheinlich, dass der GCC bei so etwas simplen> versagt.
Es ist extremst unwahrscheinlich, das eine intakte toolchain ein
„undefined reference to memcpy“ auswirft.
Oliver
Oliver S. schrieb:> Es ist extremst unwahrscheinlich, das eine intakte toolchain ein> „undefined> reference to memcpy“ auswirft.
Das ist sogar sehr wahrscheinlich. Intakte toolchains tun das ständig.
Bei fehlerhaftem Code eben. Der hier sehr wahrscheinlich vorliegt. Aber
diesen kennen wir ja nicht.
Artur schrieb:> komplette Tabelle am Anfang der Main() eingetragen (95 Zeilen).
Wenn man die Tabelle als lokale Variable in die main() schreibt MUSS
eine intakte Toolchain diesen Fehler liefern, wenn man versucht von
anderen Stellen aus "direkt" darauf zuzugreifen.
Oliver S. schrieb:>> Spätestens an der Stelle sollte klar sein, daß deine toolchain kaputt> ist.>
Könnte gut sein. Leider hab ich von Einstellungen in "Eclipse" nicht
viel Ahnung. Die IDE wurde mir vor Jahren vom Arbeiskollegen in
Frankfurt eingerichtet. Ich bin "weit weg" aus Frankfurt nach Paderborn
umgezogen und den Kontakt verloren. So programmiere ich immer noch
Hobbymäßig mit der alten Einrichtung / Umgebung.
Leider, sind Programmierer "meiner Klasse"(Über 70 und immer noch in
"C") in meiner Umgebung nicht zu finden. Würde mich tierisch freuen eine
"verwandte Sehle" in der Nähe zu haben.
Könnte aber auch gut sein dass die IDE sehr "mager" eingerichtet ist so
dass die Programme auf mehreren MK laufen werden.
Niklas G. schrieb:> Wenn du dein gesamtes ursprüngliches Programm (das bei dem die> Initialisierung problematisch ist) zeigen würdest, könnte man drauf> schauen.
Da wird es scheinbar mit "mangelnder Beratungsresistenz" immer
schwieriger.
Artur schrieb:> Programmierer "meiner Klasse"(Über 70
Artur schrieb:> So programmiere ich immer noch> Hobbymäßig mit der alten Einrichtung / Umgebung.
.... und stopselt tage- und wochenlang vor sich hin anstatt
sich richtig helfen zu lassen - mit einem kompletten, nach-
vollziehbaren Code den man zur Verfügung stellt.
Artur schrieb:> Die IDE wurde mir vor Jahren vom Arbeiskollegen in> Frankfurt eingerichtet.
PS: Mittlerweile kommt die STM32CubeIDE mit einem simplen Installer. Da
bekommt man mit wenigen Klicks ein aktuelles (!) funktionsfähiges
Gesamtpaket und muss auch nix konfigurieren. Man hat sehr schnell ein
Projekt für den gewünschten Controller angelegt, kann sich grafisch die
Takt- und Pin-Konfiguration zusammenklicken und bekommt den
entsprechenden Code generiert. Das kann sich jeder selbst einrichten.
Niklas G. schrieb:> Man hat sehr schnell ein> Projekt für den gewünschten Controller angelegt, kann sich grafisch die> Takt- und Pin-Konfiguration zusammenklicken
Naja, das ist für einen "Anfänger" schon eine kleine Herausforderung
da es beim "Zusammenklicken" schon einige Sachen zu beachten gibt
die sich als kleine Fallstricke herausstellen können. Aber man
muss ja nicht die graphische Initialisierung wählen sondern kann
sich nach herkömmlicher Art sein Projekt in der CubeIDE zusammen-
stellen - einfach alle Sourcen in ein neues leeres Projekt herein-
kopieren. Das würde sich auch anbieten wenn der TO mal sein
komplettes Projekt posten würde.
Die CubeIDE zu verwenden ist auf jeden Fall empfehlenswert um von
der halbgaren Eclipse-Installation wegzukommen. Ja ich weiss,
Eclipse ist dann immer noch präsent ...
Wastl schrieb:> Niklas G. schrieb:>> Da wird es scheinbar mit "mangelnder Beratungsresistenz" immer> schwieriger.>> Artur schrieb:>> Programmierer "meiner Klasse"(Über 70
Da habt Ihr scheinbar gar nicht so unrecht :-)
Pas Projekt ist inzwischen "etwas" gröser geworden(siehe Bild). Ein Paar
Verzeichnisse fehlen noch. Ich versuche den "Sieben Segment Display" mit
einen "graphischen Display" zu ersetzen.
Würde es helfen die main(), Display.c und die Display.h zur Verfühgung
zu stellen?
Soll ich den Code direkt hier einfügen?
Oder ich kann auch das Projekt komplett mal zippen.
Artur schrieb:> Würde es helfen die main(), Display.c und die Display.h zur Verfühgung> zu stellen?
Und wenn dein Speicherzugriffsfehler woanders liegt?
Artur schrieb:> Oder ich kann auch das Projekt komplett mal zippen.
Ja, oder auf GitHub stellen
Artur schrieb:> Ich versuche den "Sieben Segment Display" mit> einen "graphischen Display" zu ersetzen.
Nein. Sondern:
Du versuchst das "Sieben Segment Display" durch
ein "_graphisches_ Display" zu ersetzen.
Artur schrieb:> komplette Tabelle am Anfang der Main() eingetragen (95 Zeilen).> Compiler hat sich "verschluckt"
Das ist mir im Nachhinen klar: die grosse Struct in Main anzulegen
sprengt die Grösse des Stacks die per default irgendwo festgelegt
wird.
"Grosse" Datenmengen sollte man immer Modul-global oder total
global anlegen, dann belasten sie nicht den Stack.
Hab ich überlesen dass das schon jemand erwähnt hat? Dann
sorry für die Verdoppelung .....
Artur schrieb:> Die gesamte Tabelle ins "Display.h" verschoben
Das ist pöhse, das tut man nicht und es fällt einem irgendwann
auf die Füsse. Daten und Code in *.h Dateien tut man nicht.
Nein das tut man nicht! Bunkt.
Wastl schrieb:> Das ist mir im Nachhinen klar: die grosse Struct in Main anzulegen> sprengt die Grösse des Stacks die per default irgendwo festgelegt> wird.
Naja weil Stack und .data beim Default Setup vom STM32 sich entgegen
wachsen, sollte es effektiv keinen Unterschied machen... Besonders schön
ist es aber wirklich nicht.
Artur schrieb:> weitere Ergänzung der Tabellendefinition mit "static" hat mich> weitergebracht>> "static const unsigned short Arial_7x10_Table[95][10] . . . ">> Die gesamte Tabelle ins "Display.h" verschoben - geht auch :-)
Du hast offenbar keine Ahnung, was Du da tust.
Durch "static" beschränkst Du den Scope für die Tabelle auf die aktuelle
Übersetzungseinheit. Wenn Du dann zusätzlich noch die Tabelle ins
Display.h verschiebst, ist das ein Doppel-Eigentor.
Folge ist nämlich, dass die Tabelle damit für jede Übersetzungseinheit,
in welcher Du Display.h inkludierst, noch einmal neu erzeugt wird. Wenn
also ein Dutzend von C-Sources
1
#include"Display.h"
aufrufen, hast Du auch ein dutzendmal die Tabelle im Speicher - ob Flash
oder auch RAM... siehe oben.
Mit Deinen Aktionen dokterst Du nur an den Symptomen, ohne den
eigentlichen Fehler auszumerzen. Du hast höchstwahrscheinlich einen
Buffer-Overflow für die Variable, die im Source vor Deiner
Array-Definition liegt. (*1)
Beispiel:
1
#include<stdio.h>
2
#include<string.h>
3
4
charbuffer[4];
5
intvariable;
6
7
intmain()
8
{
9
strcpy(buffer,"hello");// Dieser Befehl überschreibt variable
10
11
printf("%d\n",variable);
12
}
(*1) Muss nicht zwingend so sein, je nach Compiler oder Optimierung kann
die Reihenfolge der Variablen im RAM abweichen. Wenn man beide Variablen
in eine Struct packt, dann passierts aber ziemlich sicher.