Forum: Mikrocontroller und Digitale Elektronik Problem mit STM32F103 und RAM-Größe


von Tim K. (timkl94)


Lesenswert?

Hallo Leute,

ich habe momentan das Problem, dass der RAM-Speicher für die Firmware 
für meinen STM32 nicht ausreicht.
Von der TrueStudio IDE bekomme ich die Meldung 'RAM overflowed by 24 
bytes'.

Kann mir jemand weiterhelfen, wie ich evtl. genügend RAM einsparen kann?

von Sebastian R. (sebastian_r569)


Lesenswert?

Ist viel serielle Kommunikation drin?

Es gibt für den STM32 sicherlich so etwas wie PROGMEM, mit dem konstante 
Strings nicht im RAM sondern im Flash gespeichert werden. Das wäre ein 
Anfang, mal in die Richtung zu schauen.

Generell Konstanten ausm RAM ins Flash holen.

von hfhd (Gast)


Lesenswert?

strings einfach mit
1
const char *string = "string im flash"

ablegen

von Rainer B. (katastrophenheinz)


Lesenswert?

Hi,
Guck mal ins .map-file, an welcher Stelle wieviel RAM verbraten wird. 
Ansonsten, wie schon gesagt, zur Compilezeit konstante Zeichenketten 
bzw. konstante Arrays mit 'const' aus dem RAM ins Flash verschieben.

Beitrag #6005334 wurde von einem Moderator gelöscht.
von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Tim K. schrieb:

> Kann mir jemand weiterhelfen, wie ich evtl. genügend RAM einsparen kann?

Zuerst einmal ins map file und linker script gucken, wofür Du das RAM 
verwendest. Wahrscheinlich fällt Dir da schon etwas auf...

von Guest (Gast)


Lesenswert?

Hast du vielleicht auch alles als "int" angelegt das sind beim STM32 32 
Bit. Ich glaube kaum das du bei all deinen Variablen so eine große 
Variable brauchts. Bei denen wo weniger reicht kannst du auch folgende 
Typen benutzen:

uint8_t / int8_t
uint16_t / int16_t
uint32_t / int32_t

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Guest schrieb:
> uint8_t

Bremst den STM32 unter Umständen arg aus.

Der TO sollte erstmal schauen, was er mit Compiler-Optionen erreichen 
kann. Da helfen zum Beispiel entsprechende Optimierung-Flags wie zum 
Beispiel -Os. Auch FLTO (in Verbindung mit gcc) kann einiges an 
RAM-Bedarf optimieren.

Natürlich ist es sinnvoll, String-Konstanten auch als solche zu 
definieren, das wurde oben ja schon genannt.

Wenn man den Soure-Code nicht kennt, wird es schwierig, zielführende 
Ratschläge zu geben. Vielleicht kann der TO ja Teile davon posten, wo er 
meint, dass hier besonders viel RAM verbraten wird.

von Tim K. (timkl94)


Angehängte Dateien:

Lesenswert?

Eine Optimierung der Compiler-Einstellung hat bei mir nicht geholfen.

Die Firmware habe ich mit der MotorControl Workbench von ST für ein 
Steval-Spin3202 Eval-Board erzeugt. Der Speicher ist bei der Firmware 
schon ziemlich am Limit.

Ich habe jetzt noch einen Programmteil für einen Poti aus einem 
Beispiel-Projekt in der main hinzugefügt. Dafür reicht der Speicher 
jetzt aber nicht mehr aus.

von abe (Gast)


Lesenswert?

Bitte lass uns doch nicht im Regen stehn.

Dein geposteter Quellcode ist unvollständig, die Definition von 
POT_BUF_SIZE fehlt zum Beispiel.

Wie schon geschrieben wurde: lies dir das map File vom Compiler durch.

von Tim K. (timkl94)


Angehängte Dateien:

Lesenswert?

Hier ist noch die zugehörige main.h

von Hermann G. (df2ds)


Lesenswert?

Leider etwas offtopic, aber die Abbruchbedingung der Schleife sieht auch 
merkwürdig aus:
1
void PotentiometerInit(void)
2
{
3
 uint16_t initval = (uint16_t) (((uint32_t) INITIAL_SPEED_IN_RPM / (uint32_t) MAXIMUM_SPEED_IN_RPM) * 0XFFFF);
4
5
 for(pot_buf_index = 0; pot_buf_index >= POT_BUF_SIZE; pot_buf_index++) // <--- wirklich >= ???

von Rainer B. (katastrophenheinz)


Lesenswert?

Hi,

das .MAP-File bitte auch noch.

von Peter D. (peda)


Lesenswert?

Mit dem main.c kann man nichts anfangen, das ist ja nur einen Ansammlung 
schwarzer Kisten.
Daß eine Motorsteuernung satte 20kB an RAM gulpt, ist schon recht 
strange.
Das map-File sollte die Ursache verraten.

Vielleicht ist auch die Compilerversion nur eine Demo mit limitiertem 
RAM.

von Tim K. (timkl94)


Angehängte Dateien:

Lesenswert?

Hier ist das map-File.

von Rainer B. (katastrophenheinz)


Lesenswert?

Heapsize auf 0 ( dyn. Allokation mit 'new' kommt nicht vor, oder ? )
und/oder Stacksie dezent verringern ( z.b. auf 768 ) sollten dich erst 
einmal unter die 4k-Grenze bringen.

von Johannes S. (Gast)


Lesenswert?

der Motorcontroller ist doch nicht der F103 sondern der L0 irgendwas, 
der hat scheinbar nur 4 kB Ram, und das wird aufgebraucht.
es geht wohl um diesen: 
Beitrag "Problem mit ST-Board zur BLDC-Ansteuerung"
https://www.st.com/en/microcontrollers-microprocessors/stm32f031c6.html

von Tim K. (timkl94)


Lesenswert?

Rainer B. schrieb:
> Heapsize auf 0 ( dyn. Allokation mit 'new' kommt nicht vor, oder ?
> )
> und/oder Stacksie dezent verringern ( z.b. auf 768 ) sollten dich erst
> einmal unter die 4k-Grenze bringen.

Kannst du mir das genauer erklären?

von Rainer B. (katastrophenheinz)


Lesenswert?

Irgendwo in deiner Toolchain ( TrueStudio IDE ? ) sollte es 
Einstellungen geben, in diesen Einstellungen sollten diese zwei 
Parameter HEAPSIZE und STACKSIZE auftauchen. Die sind gegenwärtig mit 
128 ( oder 0x80 ) bzw. 1024 ( oder 0x400 ) belegt. Ändere HEAPSIZE auf 0 
und/oder STACKSIZE auf 768 ( 0x300 ) Evtl. heißen diese beiden 
Einstellungen in deiner IDE nicht genau so, aber ähnlich.

HEAPSIZE=0 setzt jedoch voraus, dass keine dyn. Speicherallokatio mit 
'new' gemacht wird. In deinem main.c hab ich keine gesehen, daher gehe 
ich davon aus, dass das funzt. Guck sicherheitshalber nochmal, ob im 
restlichen Quellcode auch kein 'new' vorkommt.

STACKSIZE: 1k erscheint mir ziemlich hoch, probier mal weniger. Wenn das 
Programm dann unvermittelt und unvermutet abstürzt, wieder  hochsetzten.

Sollte deine Toolchain die Einstellungen für HEAPSIZE und STACKSIZE 
nicht kennen, dann guck mal nach einem File mit der Extension .ld. Da 
könnte HEAPSIZE und STACKSIZE auch definiert sein.

Außerdem musst du noch den Fehler beheben, den Herrmann G. oben 
angemerkt hat.

EDIT: Diese Einstellungen könnten auch in irgendwelchen 
'Projekteinstellungen' oder 'Buildeinstellungen' versteckt sein, ich 
kenn TureStudio IDE leider nicht.

: Bearbeitet durch User
von Johannes S. (Gast)


Lesenswert?

Dazu kommt das der gcc den M0 grob vernachlässigt und deutlich 
schlechter optimiert als bei >= M3. Der Keil Compiler holt da mehr raus, 
bis 32k Codesize lief der auch in der kostenlosen Testversion.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Man könnte auch die HAL wegschmeissen und das vernünftig zu Fuss machen. 
Allein die ganzen HAL Init Strukturen brauchen unnötigen Stack, den man 
sparen könnte.
Will man unbedingt die HAL verwenden könnte man die Init structs ggf. 
auch "const" machen (wenn die HAL das mag) und statisch initialisieren - 
falls darüber keine Parameter zurückgeliefert werden.

Was allein hier schon verbraten wird in den unterschiedlichen Funktionen 
muss alles auf dem Stack vorgehalten werden. Warscheinlich existieren 
einige auch global:
1
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
2
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
3
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
4
5
ADC_ChannelConfTypeDef sConfig = {0};
6
7
TIM_MasterConfigTypeDef sMasterConfig = {0};
8
TIM_OC_InitTypeDef sConfigOC = {0};
9
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
10
11
usw...

: Bearbeitet durch User
von (Gast)


Lesenswert?

Random .. schrieb:
> muss alles auf dem Stack vorgehalten werden. Warscheinlich existieren
> einige auch global:RCC_OscInitTypeDef RCC_OscInitStruct = {0};
> RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
> RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
>
> ADC_ChannelConfTypeDef sConfig = {0};
>
> TIM_MasterConfigTypeDef sMasterConfig = {0};
> TIM_OC_InitTypeDef sConfigOC = {0};
> TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
>
> usw...

Das ist ephemer und verschwindet wieder, die 1k Stack kann man während 
der Initialisierung ja getrost ausnutzen. "const" wird nichts bringen.

Dubios vom RAM Verbrauch her finde ich
1
.data.pUSART   0x00000000200005e0      0x13c Application/User/mc_config.o
2
                0x00000000200005e0                pUSART

und
1
COMMON         0x0000000020000778      0x22c Application/User/main.o
2
                0x0000000020000778                hdma_tim1_ch4_trig_com
3
                0x00000000200007bc                PotentiometerConv
4
                0x00000000200007c8                htim3
5
                0x0000000020000808                huart1
6
                0x0000000020000878                htim1
7
                0x00000000200008b8                hdma_tim3_ch4_up
8
                0x00000000200008fc                PotentiometerHandle
9
                0x0000000020000900                hdma_adc
10
                0x0000000020000944                hadc
11
                0x0000000020000990                pot_buf

immerhin 872 byte insgesamt.

von Tim K. (timkl94)


Lesenswert?

Rainer B. schrieb:
> Außerdem musst du noch den Fehler beheben, den Herrmann G. oben
> angemerkt hat.

Mir ist noch nicht klar, wo da genau der Fehler liegt?

von Tim K. (timkl94)


Lesenswert?

Okay ich habe es gecheckt.

von Dieter (Gast)


Lesenswert?

Frank M. schrieb:
> Bremst den STM32 unter Umständen arg aus.

Warum sollte das den STM ausbremsen. Soweit mir bekannt ist können die 
in Byte Blöcken auf den Speicher zugreifen. Hab mit dem F1 noch nicht 
wirklich was gemacht aber F2,3,4,7 und H7 machen das Problemlos

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Dieter schrieb:
> Soweit mir bekannt ist können die in Byte Blöcken auf den Speicher
> zugreifen.

Ja, können Sie, indem sie auf 4 Byte alignen, 4 Bytes einlesen und 3 
Bytes davon durch Maskierung wieder verwerfen - stark vereinfacht 
ausgedrückt. Beim Speichern kann das ebenso übel aussehen, wenn nicht 
der Compiler durch Alignment für "3-Byte-Löcher" zwischen den 
Variablen/Structelementen sorgt, um das Problem abzumildern. Packed 
Structs mit ungünstigem Alignment bringen den STM32 dann mal richtig ins 
Schwitzen. Das gilt übrigens nicht nur für den STM32F1xx, sondern 
eigentlich für alle STM32.

Es gibt auch hier im Forum diverse Tests mit Benchmarks, die klar 
zeigen, dass die Geschwindigkeit bei Verwendung von uint8_t statt 
uint_fast8_t (welches für STM32 identisch zu uint32_t ist) richtig in 
den Keller geht. Bei uint16_t ist der Geschwindigkeitseinbruch übrigens 
wesentlich weniger spürbar.

: Bearbeitet durch Moderator
von hfhd (Gast)


Lesenswert?

bei den größeren M4/M7 mit cache ist das stark situaionsabhängig.
er liest dann zwar schnell die 4bytes ein
beim speichern rudert er aber stark umher

zumal man hier darauf achten muss das der cache 32byte aligned ist

Habe mir angewöhnt packed structs zu vermeiden und nutze fast nur noch 
uint_32/int

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

hfhd schrieb:
> bei den größeren M4/M7 mit cache ist das stark situaionsabhängig. er
> liest dann zwar schnell die 4bytes ein beim speichern rudert er aber
> stark umher

Deshalb schrieb ich ja ursprünglich "Bremst den STM32 unter Umständen 
arg aus."

> Habe mir angewöhnt packed structs zu vermeiden und nutze fast nur noch
> uint_32/int

Dito. Ich verwende aber auch gern uint_fast8_t bzw. uint_fast16_t, um 
auszudrücken, dass hier eigentlich eine 8-Bit-Variable beabsichtigt ist 
bzw. reichen würde, aber aus Performance-Gründen darauf verzichtet wird. 
Das macht übrigens dann den Code portabler, wenn er für verschiedenste 
Zielplattformen geschrieben ist, wie zum Beispiel IRMP, welches 
unter anderem auf AVRs (8-Bit) und auch STM32 (32-Bit) und noch vielen 
anderen µCs läuft.

Hier wird dann vom Compiler immer die optimale Speichergröße verwendet. 
Man muss dabei aber höllisch aufpassen, hier keine Überläufe der 
möglichen Wertebereiche zu produzieren. Während in einem uint_fast8_t 
auf einem STM32 durchaus der Wert 256 gespeichert werden kann, ist dies 
bei einem AVR dann durch Überlauf gleich 0.

von hfhd (Gast)


Lesenswert?

vielleicht ist das auch der grund meines kompilerproblems...

V4.9.3 alles funktioniert und das schnell

Alle Versionen darüber verursachen bei bestimmten Programmteilen einen 
langsameren Ablauf.

Ich nutze lwIP... und hier sind ja auch packed structs dabei.
Ich habe das Problem das die TCP Verbindung dann langsamer ist

Wenn jemand einen Tip hat ... sehr gern^^

von Gnorm (Gast)


Lesenswert?

Und andere, wie z.B. LPC, haben das Problem nicht?
Oder M0,M3,Mx abhaengig?
Wie kann man das testen?

von hfhd (Gast)


Lesenswert?

Gnorm schrieb:
> Wie kann man das testen?

ASM listing anschauen

von Gnorm (Gast)


Lesenswert?

Danke. Also einmal mit 8 bit und einmal mit 32 bit und das vergleichen?

von W.S. (Gast)


Lesenswert?

Frank M. schrieb:
> Dito. Ich verwende aber auch gern uint_fast8_t bzw. uint_fast16_t, um
> auszudrücken, dass hier eigentlich eine 8-Bit-Variable beabsichtigt ist
> bzw. reichen würde..
> ...
> Man muss dabei aber höllisch aufpassen, hier keine Überläufe der
> möglichen Wertebereiche zu produzieren.

Tja. Und wo bleibt da der proklamierte Vorteil dieser Alias-Bezeichner?

Ich sehe da nur eines: daß nämlich mit diesem Workaround namens 
"uint_irgendwas" mehr Probleme aufgerissen werden (insbesondere die 
vielgelobte Portabilität), als man zu stopfen beabsichtigt hatte.

Frank M. schrieb:
> Packed
> Structs mit ungünstigem Alignment bringen den STM32 dann mal richtig ins
> Schwitzen. Das gilt übrigens nicht nur für den STM32F1xx, sondern
> eigentlich für alle STM32.

Ach nö. Sowas geht nur dann in die Hose, wenn man gedankenlos so einen 
Struct konzipiert. Es ist wie immer: Wenn der Programmierer nicht 
nachdenkt, dann schreibt er eben auch einen schlechten Code. Wer 
nachdenkt und die Manuals gelesen hat, der weiß, ob man der 
Zielplattform überhaupt unaligned Daten zumuten kann und ob man sich das 
bei Plattformen, die sowas abkönnen, auch leisten kann/will.


ABER: Das Problem des TO liegt ganz woanders.
Lies mal:
  RCC_OscInitStruct.OscillatorType = ...
  RCC_OscInitStruct.HSIState = ...
usw.

Nun, kommt so langsam die Erleuchtung?

Der TO benutzt diesen Krempel von ST und pflastert sich damit ruckzuck 
alle Ressourcen zu, die sein Chip beinhaltet. Wenn man schon mit seinen 
Ressourcen ein wenig haushalten muß, dann verbietet sich sowas wie die 
ST-Lib, printf und anderes Zeug quasi wie von selbst. Genau DAS ist 
hier der Generalfehler. Wenn ich lesen muß "Von der TrueStudio IDE 
bekomme ich die Meldung 'RAM overflowed by 24 bytes'. Kann mir jemand 
weiterhelfen," dann sagt mir mein Inneres: der Junge ist für seinen Job 
zu klein.

W.S.

von Bernd K. (prof7bit)


Lesenswert?

W.S. schrieb:
> Wenn man schon mit seinen
> Ressourcen ein wenig haushalten muß, dann verbietet sich sowas wie die
> ST-Lib, printf und anderes Zeug quasi wie von selbst. Genau DAS ist
> hier der Generalfehler.

In dem Fall ist der Generalfehler überhaupt STM32 oder kompatible zu 
benutzen anstatt lieber einen den man in völlig tiefenentspanntem 
Zustand über die Register direkt programmieren kann während das Auge 
wohlgefällig über die grüne Wiese wandert und die Vögel zwitschern so 
wie das zum Beispiel bei Kinetis der Fall ist und nicht wie bei STM32 wo 
man allein beim Gedanken daran schon einen Herzinfarkt erleidet! Das ist 
der Gerelalfehler, wenn es überhaupt sowas gibt dann ist es das!

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Tja. Und wo bleibt da der proklamierte Vorteil dieser Alias-Bezeichner?

Dass ich den Source nicht mit #ifdefs zukleistern muss, um portabel zu 
bleiben. Überläufe zu missachten ist ein eklatanter Fehler des 
Programmierers. Man sollte also seine eigene Unfähigkeit nicht mit so 
einer Ausrede "uint_fast8_t ist schuld!" verdecken.

> Ich sehe da nur eines: daß nämlich mit diesem Workaround namens
> "uint_irgendwas" mehr Probleme aufgerissen werden (insbesondere die
> vielgelobte Portabilität), als man zu stopfen beabsichtigt hatte.

Unsinn, Du hast schon desöfteren gezeigt, dass Du von Programmieren 
keine Ahnung hast, daher würde ich an Deiner Stelle nicht so großkotzig 
daherkommen.

Mit Portabilität hast Du auch nichts am Hut. Deine Programme laufen 
immer nur genau auf einem Prozessortypen. Das ist easy.

> Frank M. schrieb:
> Packed
> Structs mit ungünstigem Alignment bringen den STM32 dann mal richtig ins
> Schwitzen. Das gilt übrigens nicht nur für den STM32F1xx, sondern
> eigentlich für alle STM32.
>
> Ach nö. Sowas geht nur dann in die Hose, wenn man gedankenlos so einen
> Struct konzipiert.

Hallo? Lies meinen Satz nochmal: "Structs mit ungünstigem Alignment 
...".  Das ist genau damit gemeint, nämlich dass der Programmierer nicht 
aufgepasst hat. Du wiederholst hier nur noch mal schwülstig meine 
Aussage.

Also: Mal wieder viel Wind um nichts. Alles schon durchgekaut. 
Hauptsache, W.S. hat sich mal wieder gemeldet.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Gnorm schrieb:
> Wie kann man das testen?

Zum Beispiel so (Pseudocode):
1
#include <stdint.h>
2
...
3
    volatile uint8_t i, j, k, l;
4
5
    led_an ();
6
7
    for (i = 0; i < 255; i++)
8
    {
9
        for (j = 0; j < 255; j++)
10
        {
11
            for (k = 0; k < 255; k++)
12
            {
13
                for (l = 0; l < 255; l++)
14
                {
15
                }
16
            }
17
        }
18
    }
19
20
    led_aus ();
21
...

Wichtig ist das volatile, sonst optimiert der Compiler die Schleifen 
weg. Dann die Zeit stoppen, wie lange die LED leuchtet.

Anschließend die Zeile
1
    volatile uint8_t i, j, k, l;

durch
1
    volatile uint_fast8_t i, j, k, l;

ersetzen und nochmal die Zeit stoppen.

von Gnorm (Gast)


Lesenswert?

Danke. Und dann das Ganze noch mal mit 32 bit, um die "Referenz" zu 
haben?

von Nop (Gast)


Lesenswert?

Frank M. schrieb:
> Packed
> Structs mit ungünstigem Alignment bringen den STM32 dann mal richtig ins
> Schwitzen.

Normalerweise entwirft man seine structs deswegen ja von der Sortierung 
der Datentypen von groß nach klein oder umgedreht. Dann sorgt der 
Compiler selber dafür, daß alles richtig aligned wird.


W.S. schrieb:

> Tja. Und wo bleibt da der proklamierte Vorteil dieser Alias-Bezeichner?

Beispielsweise für Schleifenzähler, die vom Wertebereich her klein 
bleiben, aber je nach Plattform in 32 bit durchaus schneller sein können 
als in 8 bit.

Verwendet man das in structs, muß man natürlich sauber programmieren, 
anstatt sich auf implizite Datengrößen und Offsets zu verlassen. Das ist 
aber ohnehin best practice.

von Nop (Gast)


Lesenswert?

Gnorm schrieb:
> Danke. Und dann das Ganze noch mal mit 32 bit, um die "Referenz"
> zu haben?

nimmste uint32_t.

von Bernd K. (prof7bit)


Lesenswert?

Nop schrieb:
> Normalerweise entwirft man seine structs deswegen ja von der Sortierung
> der Datentypen von groß nach klein oder umgedreht. Dann sorgt der
> Compiler selber dafür, daß alles richtig aligned wird.

Es wird immer alles richtig aligned solange man kein packed verwendet. 
Dann werden halt hier und da unsichtbare Paddingbytes eingefügt.

Jedoch kann man auch so vorgehen (man muss nicht stur von groß nach 
klein):

int64 immer an 8er Offset plazieren
int32 immer an 4er Offset plazieren
int16 immer an 2er Offset Plazieren
int8 an beliebiger Stelle

Also zum Beispiel 2 einzelne Bytes, dann ein int16, dann ein int32, dann 
vielleicht wieder 2 einzelne Bytes, dann wieder ein int16, etc... wie 
mit den Bauklötzchen früher, ist ganz einfach...

Dann ist es auch ohne packed genauso kompakt und es entsteht kein 
Padding. Dazu braucht man nur 8 Finger um zu zählen und ein bisschen 
Grundrechnen.

Vgl: ESR: "The Lost Art Of Structure Packing"

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Frank M. schrieb:
> Bremst den STM32 unter Umständen arg aus.

Diese Umstände muß man aber schon mit der Lupe suchen.
Z.B. bei einer Struct, die UART-Daten, ADC-Daten oder Tastendrücke 
aufsammelt, wird man keinen merkbaren Laufzeitunterschied feststellen.
Es müssen schon Routinen sein, die exzessiv auf die Struktur zugreifen, 
z.B. DSP-Funktionen (Audio- oder Bildverarbeitung).

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Nop schrieb:
> Normalerweise entwirft man seine structs deswegen ja von der Sortierung
> der Datentypen von groß nach klein oder umgedreht. Dann sorgt der
> Compiler selber dafür, daß alles richtig aligned wird.

Eben. Und daher benutzt man packed-Structs nur, wenn man explizit gegen 
das Alignment verstoßen will. Es ist Quatsch, eine bereits manuell 
ausgerichtete Struct noch mit dem Attribut "packed" zu versehen. Das ist 
doppelt gemoppelt und bringt nichts.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Diese Umstände muß man aber schon mit der Lupe suchen.

Teste einfach mal die obigen vier for-Schleifen - einmal mit uint8_t und 
einmal mit uint32_t (oder uint_fast8_t).

> Z.B. bei einer Struct, die UART-Daten, ADC-Daten oder Tastendrücke
> aufsammelt, wird man keinen merkbaren Laufzeitunterschied feststellen.

Ich habe anfangs auch gar nicht von Structs gesprochen. Das, was Du da 
von mir zitiert hast, bezog sich auf die allgemeine Verwendung von 
8-Bit-Variablen - egal wo.

von Nop (Gast)


Lesenswert?

Frank M. schrieb:
> Es ist Quatsch, eine bereits manuell
> ausgerichtete Struct noch mit dem Attribut "packed" zu versehen.

Naja man kann sich ein bißchen Verschnitt sparen. 32, 16 und 8 bit sind 
64 bit normal und 56 bit packed.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Nop schrieb:
> Naja man kann sich ein bißchen Verschnitt sparen.

Betonung liegt auf "bißchen" - nämlich am Ende :-)

Beim Zugriff auf den letzten uint8_t müssen dann aber wieder 3 Bytes vom 
STM32 ausmaskiert werden - auch nicht so dolle.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich habe das Programm mal auf zwei STM32F4xx laufen lassen:
1
    volatile uint8_t i, j, k, l;
2
3
    led_an ();
4
5
    for (i = 0; i < 255; i++)
6
    {
7
        for (j = 0; j < 255; j++)
8
        {
9
            for (k = 0; k < 255; k++)
10
            {
11
                for (l = 0; l < 60; l++)
12
                {
13
                }
14
            }
15
        }
16
    }
17
18
    led_aus ();

Die Variable l habe ich nur bis 60 laufen lassen, damit ich nicht so 
lange warten muss.

Getestet auf einem STM32F401RE mit 84 MHz:
uint8_t: 160 sec
uint_fast8_t: 134 sec

-> Einbruch der Geschwindigkeit um 20% bei Verwendung von uint8_t.

Getestet auf einem STM32F407VET6 mit 168MHz:
uint8_t: 83 sec
uint_fast8_t: 77 sec

-> Einbruch der Geschwindigkeit um 8% bei Verwendung von uint8_t.

Warum der Unterschied beim STM32F407 geringer ist, ist mir schleierhaft.

(Edit: Vermutlich liegts an der höheren Zahl der Waitstates bei 168MHz, 
die das Ergebnis relativieren).

Aber Geschwindigkeitseinbußen im 2-stelligen Prozentbereich muss man 
nicht haben. Hier sprechen wir noch nichtmals über Alignment, sondern 
nur über die Verwendung von 8-Bit-Variablen. Natürlich wurden dabei auch 
die 4 lokalen uint8_t-Variablen vom Compiler aligned.

P.S.
Gestoppt wurde das mit einem Timer, nicht mit der Hand ;-)
Eingebaut wurde das aus Faulheit in eine bestehende Anwendung, bei der 
die Timer-ISR auch noch andere Dinge erledigen musste, wie zum Beispiel 
IRMP und andere Aufgaben. Bei einer nackten Timer-ISR würde das 
Egebnis sogar noch etwas krasser ausfallen.

: Bearbeitet durch Moderator
von Peter D. (peda)


Lesenswert?

Frank M. schrieb:
> Bei einer nackten Timer-ISR würde das
> Egebnis sogar noch etwas krasser ausfallen.

Der Timerinterrupt wird selber <0,1% verbrauchen, d.h. 20% mehr von 0,1% 
merkt niemand.
Man muß nicht überall die Gespenster unterm Bett suchen, d.h. 
Mikrooptimierung betreiben.

von W.S. (Gast)


Lesenswert?

Bernd K. schrieb:
> In dem Fall ist der Generalfehler überhaupt STM32 oder kompatible zu
> benutzen anstatt...

Ach, sieh das mal nicht gar so pessimistisch.

Aber so im Kern kristallisiert sich schon dabei heraus, daß ST mit 
seinem Marketing zwar offensichtlichen Erfolg hatte, aber auf lange 
Sicht ist es ein Tiefschlag gegen das Niveau der existierenden 
Ingenieure. Stell dir mal vor, wenn es in 10 Jahren nur noch Ingenieure 
gibt, die nichts anderes können als XYZ_InitStruct's zu befüllen.



Frank M. schrieb:
> Dass ich den Source nicht mit #ifdefs zukleistern muss,
und:
Frank M. schrieb:
> Unsinn, Du hast schon desöfteren gezeigt, dass Du von Programmieren
> keine Ahnung hast

Zunächst mal herzlichen Dank für die Blumen.

Oh mann, ich wollte ja nicht unbedingt auf dein hier mal 
veröffentlichtes Projekt zurückkommen. Aber da du es ja selbst 
ansprichst: Ja, du bist in selbigem so ziemlich ertrunken in einer Flut 
von #ifdef's. Das zeigt, wieviel Ahnung du vom Programmieren hast, so 
daß du von oben herab auf Leute wie mich herabsehen kannst. Und dabei 
hast du nicht einmal alle üblichen STM32Fxxx mit deinen #ifdef's 
erfassen können. Geschweige denn Cortex-M Chips von anderen Herstellern 
oder gar 32 Bit Controller, die zufälligerweise mal keine Cortex-M sind.

Nein, in einer sauberen Quelle braucht eigentlich fast NIE ein #ifdef 
enthalten zu sein. Ausnahmen sind sowas wie void __irq XYZhandler(void), 
wenn irgend ein Compiler sowas wie __irq nicht versteht. Man macht das 
so, daß man sauber zwischen den Ebenen trennt, also plattformabhängiges 
Zeugs in plattformspezifische Lowlevel-treiber und schon hat man direkt 
oberhalb dieser Ebene keine (oder zumeist keine) Plattformabhängigkeit 
mehr drin.

So herum geht das - du großer Programmierer.


Peter D. schrieb:
> Diese Umstände muß man aber schon mit der Lupe suchen.

Ja, Peter. Auf diese Dinge trifft man nur gezwungenermaßen, z.B. wenn 
man vorgegebene Strukturen wie Header in irgendwelchen üblichen 
Dateiformaten oder Directory-Strukturen behandeln MUSS. Big- versus 
Little-Endian oder FAT12 zum Beispiel oder SOL-Audio oder eben sowas.

Für alles, was man sich selber aussucht, trifft das nicht wirklich zu. 
Der TO hat aber eher das mentale Problem, daß er offenbar auf die STM32 
festgenagelt ist, ebenso auf die Verwendung von Cube und Konsorten und 
insgesamt sich etwas vorgenommen hat, wofür er noch ein bissel zu klein 
ist.


W.S.

von Nop (Gast)


Lesenswert?

Peter D. schrieb:
> Frank M. schrieb:
>> Bei einer nackten Timer-ISR würde das
>> Egebnis sogar noch etwas krasser ausfallen.
>
> Der Timerinterrupt wird selber <0,1% verbrauchen, d.h. 20% mehr von 0,1%
> merkt niemand.

So habe ich das nicht verstanden. Die Benchmark-Schleife lief 
offensichtlich im Hauptprogramm, aber der Timer zum Stoppen hat außer 
dem Stoppen noch andere Sachen gemacht. D.h. das Hauptprogramm hat 
nichtmal die volle Rechenzeit bekommen, d.h. der Unterschied war etwas 
kleiner als eigentlich möglich.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Nop schrieb:
> Die Benchmark-Schleife lief offensichtlich im Hauptprogramm, aber der
> Timer zum Stoppen hat außer dem Stoppen noch andere Sachen gemacht

So ist es. Natürlich lief die Benchmark-Schleife im Hauptprogramm.

von Elektrickser (Gast)


Lesenswert?

Frank M. schrieb:
> Unsinn, Du hast schon desöfteren gezeigt, dass Du von Programmieren
> keine Ahnung hast, daher würde ich an Deiner Stelle nicht so großkotzig
> daherkommen.

> Du wiederholst hier nur noch mal schwülstig meine
> Aussage.

> Also: Mal wieder viel Wind um nichts. Alles schon durchgekaut.
> Hauptsache, W.S. hat sich mal wieder gemeldet.

Interessante und souveräne Art der Moderation.

Du bekommst hiermit die Auszeichnung "Moderator des Monats".

https://de.wikipedia.org/wiki/Moderator_(Gespr%C3%A4chsleiter)

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Nene das macht Frank M. schon ganz gut.
W.S. fällt hier desöfteren durch Dummschwätzigkeit auf ;)

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Gnorm schrieb:
> Oder M0,M3,Mx abhaengig?

Jo, das ist recht stark davon welcher core eingesetzt wird (und weniger 
davon welcher Hersteller den verbaut hat).
Zum einen sind die unterstützten Befehle durchaus unterschiedlich, 
gerade bei Div/Mul.
https://en.wikipedia.org/wiki/ARM_Cortex-M#Instruction_sets

Und bei den Speicherzugriffen gibt es auch Unterschiede. Z.B.:

Cortex-M0 & Cortex-M0+
3.3.4. Address alignment
An aligned access is an operation where a word-aligned address is used 
for a word, or multiple word access, or where a halfword-aligned address 
is used for a halfword access. Byte accesses are always aligned.
There is no support for unaligned accesses on the Cortex-M0+ processor. 
Any attempt to perform an unaligned memory access operation results in a 
HardFault exception.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/BABFAIGG.html
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0662b/BABFAIGG.html

Cortex-M3
3.3.5. Address alignment
An aligned access is an operation where a word-aligned address is used 
for a word, dual word, or multiple word access, or where a 
halfword-aligned address is used for a halfword access. Byte accesses 
are always aligned.
The Cortex-M3 processor supports unaligned access only for the following 
instructions:
LDR, LDRT, LDRH, LDRHT, LDRSH, LDRSHT, STR, STRT, STRH, STRHT.
All other load and store instructions generate a UsageFault exception if 
they perform an unaligned access, and therefore their accesses must be 
address aligned. For more information about UsageFaults see Fault 
handling.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABFAIGG.html

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.