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


von Chris J. (Gast)


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

von Jim M. (turboj)


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.

von John Doe (Gast)


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.

von Chris J. (Gast)


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....

von Cschlumpf (Gast)


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.

von Chris J. (Gast)


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.

von Bernd K. (prof7bit)


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/

von Chris J. (Gast)


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...
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;

von Bernd K. (prof7bit)


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
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.