mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Verständnisfrage zur Ablage von Variablen beim ARM M3


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Chris J. (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
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

Autor: Jim M. (turboj)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
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.

Autor: John Doe (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
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.

Autor: Chris J. (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
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....

Autor: Cschlumpf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Chris J. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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/

Autor: Chris J. (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
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...

/* 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;

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.