Hallo, ich versuche grad zu verstehen, wie das 32 Bit System sich auf die variablen auswirkt, die ich benutze. Bin sehr erfahren mit der Programmierung des Cortex aber eben nur auf einer höheren Ebene unter Benutzung von RTOS wie ChibiOS usw, wo man sich darum nicht kümmern muss. Wie liegt das RAM vor? Mein kleiner F103 hat 20 KB internes RAM. 20 KB = 20 x 1024 Bytes. Aber bei 32 Bit müssten das also 5120 32 Bit Wörter sein. Oder ist das noch hardwaremässig unterteilt in 8 Bit Bytes? Wenn ich einen Ausdruck wie uint8_t vor eine Variable schreibe, verbraucht der Compiler dann trotzdem 32 Bit für diese Variable und lässt die oberen 24 Bit ungenutzt? Oder erzeugt er Code um 4 uint8_t Variablen in einem 32 Bit RAM Zelle unter zu bringen? Kann man den GCC Compiler veranlassen "sparsam" mit dem internen Ram umzugehen, auch wenn das mehr Code erzeugt? Sorry, vielleicht ist das ja alles ein alter Hut aber ich möchte es trotzdem mal verstehen... Gruss, Christian
Chris J. schrieb: > Aber bei 32 Bit müssten das also 5120 32 Bit Wörter > sein. > Oder ist das noch hardwaremässig unterteilt in 8 Bit Bytes? Letzteres. Wenn man den AdressZähler um eins hochzählt, dann zählt man ein Byte weiter. Der Cortex-M3 kann also als 32-Bitter die Bytes von 4 aufeinanderfolgenen Adressen gleichzeitig in ein Register laden. Chris J. schrieb: > Wenn ich einen Ausdruck wie uint8_t vor eine Variable schreibe, > verbraucht der Compiler dann trotzdem 32 Bit für diese Variable Nein. Allerdings kann der Code dadurch langsamer werden, denn die Reduktion 32->8 Bits kann zusätzliche Instruktionen kosten. Nicht jede Variable landet zwingend im RAM, Schleifenzähler z.B. kann er oft im Register halten. Allerdings muss er für "static" und globale Variablen zwingen RAM reservieren.
Chris J. schrieb: > Sorry, vielleicht ist das ja alles ein alter Hut aber ich möchte es > trotzdem mal verstehen... Man sollte denken, dass sich mittlerweile rumgesprochen hat, wozu die Herstellerdokumentation da ist... Also hier mein Tip: ARM hat sehr gute Literatur zu seinen Controllern, da findest Du Antworten auf Deine Fragen. Klar, ist lästig, ein paar Tausend Seiten durchzugehen. Aber wenn Du es nicht machst, wirst Du immer wieder Probleme bekommen.
Hi, danke für die Info. "Geahnt" habe ich es, allerdings lassen sich auch 32 Bit wie 8 Bit softwaretechnisch verwalten, wenn man nur genügend Aufwand betreibt. Ich schreibe Programme, vielleicht als Relikt aus den 80igern (1kb beim Sinclair ZX) immer noch "platzsparend", obwohl ich bei Code inzwischen mehr auf Lesbarkeit achte, denn das 1BM Flash beim F427 kriege ich eh nie voll, grad mal 80kb und das bei über 10.000 Zeilen....
Das native Datenformat eines C-Compilers ist int. Wenn er mit Bruchstücken davon hantieren muss, resultiert in der Regel Mehraufwand. Und int sind beim ARM 32 bit.
Cschlumpf schrieb: > Wenn er mit Bruchstücken davon hantieren muss, resultiert > in der Regel Mehraufwand. > > Und int sind beim ARM 32 bit. Schon klar. Da ich Daten eines Sensors (8 Bit PIC, compiliert mit CCS Compiler) zu einem ARM (erzeugt mit GCC) per Funk übertrage musste ich die auch packed machen, damit das Datenpaket (ein struct) richtig einsortiert wurde im Zielsystem. Da nützten auch uint8-t nichts, ohne packed_array wurde das nichts.
Chris J. schrieb: > übertrage musste ich > die auch packed machen, damit das Datenpaket (ein struct) Versuche packed in Zukunft zu vermeiden, lies stattdessen mal das folgende und plane die Anordnung der einzelnen Elemente entsprechend: http://www.catb.org/esr/structure-packing/
Bernd K. schrieb: > Versuche packed in Zukunft zu vermeiden, lies stattdessen mal das > folgende und plane die Anordnung der einzelnen Elemente entsprechend: Wenn etwas einfaches funktioniert.. warum es dann kompliziert machen? Ich lese es heute abend mal durch, sieht interessant aus...
1 | /* An den STM32F103 Display Controller adressierter Datensatz */
|
2 | typedef struct { |
3 | uint8_t command; // 1: 0x10 = Datensatz folgend , 0x20 = ..... |
4 | uint8_t nrDataSet; // 1: Datensatznummer (rotierend) |
5 | uint8_t id_data; // 1: Aktuelle Satznummer in History |
6 | uint8_t Feuchte_Now; // 1: Aktuelle Feuchte |
7 | uint16_t Pressure_Now; // 2: Aktueller Druck |
8 | int8_t IntTemp_Now; // 1: Innentemperatur |
9 | int8_t ExtTemperature_Now; // 2: Aktuelle Aussentemperatur (99 = ungültig) |
10 | float h_Pressure; // 4: History Druck[id_data] |
11 | uint8_t h_ExtSensor_Feuchte; // 1: Feuchte außen |
12 | int8_t h_ExtSensor_Temperature; // 1: Temperatur außen |
13 | time_t unix, // 4 Bytes |
14 | timestamp; // 4: Zeitstempel der Messung |
15 | |
16 | /* -------------------------------
|
17 | 31 Bytes */
|
18 | } __attribute__((packed)) stm32f103_data_t; |
Chris J. schrieb: > /* An den STM32F103 Display Controller adressierter Datensatz */ > typedef struct { > uint8_t command; // 1: 0x10 = Datensatz > folgend , 0x20 = ..... > uint8_t nrDataSet; // 1: Datensatznummer > (rotierend) > uint8_t id_data; // 1: Aktuelle Satznummer in > History > uint8_t Feuchte_Now; // 1: Aktuelle Feuchte > uint16_t Pressure_Now; // 2: Aktueller Druck > int8_t IntTemp_Now; // 1: Innentemperatur > int8_t ExtTemperature_Now; // 2: Aktuelle > Aussentemperatur (99 = ungültig) > float h_Pressure; // 4: History Druck[id_data] > uint8_t h_ExtSensor_Feuchte; // 1: Feuchte außen > int8_t h_ExtSensor_Temperature; // 1: Temperatur außen > time_t unix, // 4 Bytes > timestamp; // 4: Zeitstempel der > Messung > > /* ------------------------------- > 31 Bytes */ > } __attribute__((packed)) stm32f103_data_t; Ist alles aligned bis auf den Zeitstempel am Ende, der ist 4 byte lang und würde deshalb von sich aus gerne 2 Byte weiter hinten liegen auf dem nächsten 4er Offset, durch das packed wird er aber nach vorne auf einen krummen Offset gezwungen wodurch der Compiler mehr umständlichen Code beim Zugriff darauf generieren muss. Du könntest den Zeitstempel direkt hinter das float legen (dort wäre er aligned) und die beiden restliche bytes dann dahinter. Dann könntest Du das packed weglassen. PS: Deine byte-Zählung in den Kommentaren entspricht nicht (mehr) den wahren Gegebenheiten. PPS: Um auf alle Fälle sicher zu gehen könntest Du ein statisches assert auf die von Hand ausgerechnete zu erwartete sizeof() des ungepacken structs mit einbauen, so knallt es beim Kompilieren sofort wenn versehentlich was verrutscht ist oder sich auf einem neuen Prozessor andere Alignment-Regeln ergeben (unwahrscheinlich weil strenger als self-aligned so ziemlich nirgends anzutreffen ist und weniger strenge Regeln bei einem lückenlosen struct keine Änderung bewirken würden). PPPS: auch wenn der Timestamp nach vorne gezogen wird hat das struct 2 bytes padding ganz am Ende weil die Gesamtgröße immer durch die Größe des größten Members teilbar sein muß. Bei unvermeidbarem Padding füge ich gerne selbst explizit Paddingbytes ein und benenne sie "reserved_1", "reserved_2", etc., manchmal sind die bei späteren Erweiterungen dann noch nützlich.
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.