Forum: Mikrocontroller und Digitale Elektronik STM32Fxxx: Frage zur Initialisierung mit der StdPeriphLib


von Chris J. (Gast)


Lesenswert?

Moin,

ich frickel grad mal wieder Code zusammen für eine SD Karte und benutze 
in meinen Basteloprojekten generell nur Funktion aus der StdPeriphLib. 
Ja, es geht auch mit Registern aber ich versuche es zu vermeiden.

Nun brauche ich eine Umschaltung der SPI Speed für das Init der Karte 
beim Aufstarten.

Normale Init der SPI schaut so aus mit dem InitStruct
1
    SPI_StructInit(&SPI_InitStruct);
2
    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    
3
    SPI_InitStruct.SPI_Mode      = SPI_Mode_Master;
4
    SPI_InitStruct.SPI_DataSize  = SPI_DataSize_8b;
5
    SPI_InitStruct.SPI_CPOL      = SPI_CPOL_Low;
6
    SPI_InitStruct.SPI_CPHA      = SPI_CPHA_1Edge;
7
    SPI_InitStruct.SPI_NSS       = SPI_NSS_Soft;   
8
    SPI_InitStruct.SPI_BaudRatePrescaler = 64;               
9
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
10
    SPI_Init(SPI1, &SPI_InitStruct);

Viel Tipperei. Wenn man jetzt aber nur 1 Parameter umstellen will, wie 
geht das ohne dass die anderen verändert werden? Es gibt keine Funktion 
des aktuellen Struct einzulesen aus CR1. Jeder Aufruf von SPI_Init 
bügelt erst alle Bits auf 0, setzt sie dann neu.

Mir fiel da nichts mehr ein als das hier, mit Registern. Und genau das 
will ich vermeiden, nur die API benutzen, immer.

Haben die bei ST daran nicht gedacht?
1
/* Stellt die SPI auf langsam ein /64 */
2
void FCLK_SLOW()
3
{
4
    SPI1->CR1 &= ~((1 << 3) | (1 << 4) | (1 << 5)); // (BR = Bit 3,4,5) löschen
5
    SPI1->CR1 |= SPI_BaudRatePrescaler_64;
6
}
7
8
/* Stellt die SPI schnell ein /2 */
9
void FCLK_FAST()
10
{
11
    SPI1->CR1 &= ~((1 << 3) | (1 << 4) | (1 << 5)); // (BR = Bit 3,4,5) löschen
12
    SPI1->CR1 |= SPI_BaudRatePrescaler_2;
13
}

von pegel (Gast)


Lesenswert?

Habe schon länger nichts mit StdPeriphLib gemacht, aber war es nicht so 
das:

SPI_StructInit(&SPI_InitStruct);

die aktuellen Werte in SPI_InitStruct einträgt?
Dann braucht man nur:

SPI_InitStruct.SPI_BaudRatePrescaler = 64;

setzen und mit:

SPI_Init(SPI1, &SPI_InitStruct);

neu aktivieren.

von Dr. Sommer (Gast)


Lesenswert?

Chris J. schrieb:
> SPI1->CR1 &= ~((1 << 3) | (1 << 4) | (1 << 5)); // (BR = Bit 3,4,5)
> löschen
>     SPI1->CR1 |= SPI_BaudRatePrescaler_64;

Ist auch falsch; da steht dann zwischendurch was falsches im Register 
(Prescaler 2). Wenn du den stm32fxxx.h Header aus der HAL nutzt, geht 
das so:
1
MODIFY_REG(SPI1->CR1, SPI_CR1_BR, SPI_CR1_BR_0 | SPI_CR1_BR_1);
Mit dem alten Header der mit der SPL kommt geht das so:
1
SPI1->CR1 = (SPI1->CR1 & ~SPI_CR1_BR) | SPI_CR1_BR_0 | SPI_CR1_BR_1;
Das SPI_BaudRatePrescaler_64 ist eine Definition der SPL und hier nur 
zufällig kompatibel mit den Register-Bits; würde ich vermeiden beim 
Zugriff auf die Register.

pegel schrieb:
> Habe schon länger nichts mit StdPeriphLib gemacht, aber war es
> nicht so
> das:
Nö:
1
/**
2
  * @brief  Fills each SPI_InitStruct member with its default value.
3
  * @param  SPI_InitStruct: pointer to a SPI_InitTypeDef structure which will be initialized.
4
  * @retval None
5
  */
6
void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct)
7
{
8
/*--------------- Reset SPI init structure parameters values -----------------*/
9
  /* Initialize the SPI_Direction member */
10
  SPI_InitStruct->SPI_Direction = SPI_Direction_2Lines_FullDuplex;
11
  /* initialize the SPI_Mode member */
12
  SPI_InitStruct->SPI_Mode = SPI_Mode_Slave;
13
  /* initialize the SPI_DataSize member */
14
  SPI_InitStruct->SPI_DataSize = SPI_DataSize_8b;
15
  /* Initialize the SPI_CPOL member */
16
  SPI_InitStruct->SPI_CPOL = SPI_CPOL_Low;
17
  /* Initialize the SPI_CPHA member */
18
  SPI_InitStruct->SPI_CPHA = SPI_CPHA_1Edge;
19
  /* Initialize the SPI_NSS member */
20
  SPI_InitStruct->SPI_NSS = SPI_NSS_Hard;
21
  /* Initialize the SPI_BaudRatePrescaler member */
22
  SPI_InitStruct->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
23
  /* Initialize the SPI_FirstBit member */
24
  SPI_InitStruct->SPI_FirstBit = SPI_FirstBit_MSB;
25
  /* Initialize the SPI_CRCPolynomial member */
26
  SPI_InitStruct->SPI_CRCPolynomial = 7;
27
}

von Jim M. (turboj)


Lesenswert?

Chris J. schrieb:
> Jeder Aufruf von SPI_Init
> bügelt erst alle Bits auf 0, setzt sie dann neu.

Meintest Du nicht eher SPI_StructInit()?

Die eigentlich SPI_Init() ändert den Inhalt der SPI_InitStruct nicht 
(jedenfalls in der Implementation die ich auf Github gefunden habe).

Permanentes Aufheben im Datensegment verbraucht allerdings RAM, den man 
mitunter für was besseres gebrauchen könnte.

von Chris J. (Gast)


Lesenswert?

SPI_InitStruct.SPI_BaudRatePrescaler = 64;
SPI_Init(SPI1, &SPI_InitStruct);

klappt nicht, weil das in den SPI_Init steht:
1
/* Get the SPIx CR1 value */
2
  tmpreg = SPIx->CR1;
3
  /* Clear BIDIMode, BIDIOE, RxONLY, SSM, SSI, LSBFirst, BR, MSTR, CPOL and CPHA bits */
4
  tmpreg &= CR1_CLEAR_Mask;
5
 /* Configure SPIx: direction, NSS management, first transmitted bit, BaudRate prescaler
6
     master/salve mode, CPOL and CPHA */
7
  /* Set BIDImode, BIDIOE and RxONLY bits according to SPI_Direction value */
8
  /* Set SSM, SSI and MSTR bits according to SPI_Mode and SPI_NSS values */
9
  /* Set LSBFirst bit according to SPI_FirstBit value */
10
  /* Set BR bits according to SPI_BaudRatePrescaler value */
11
  /* Set CPOL bit according to SPI_CPOL value */
12
  /* Set CPHA bit according to SPI_CPHA value */
13
  tmpreg |= (uint16_t)((uint32_t)SPI_InitStruct->SPI_Direction | SPI_InitStruct->SPI_Mode |
14
                  SPI_InitStruct->SPI_DataSize | SPI_InitStruct->SPI_CPOL |
15
                  SPI_InitStruct->SPI_CPHA | SPI_InitStruct->SPI_NSS |
16
                  SPI_InitStruct->SPI_BaudRatePrescaler | SPI_InitStruct->SPI_FirstBit);


>>Die eigentlich SPI_Init() ändert den Inhalt der SPI_InitStruct nicht

doch, tut sie wegen SCR1_CLEAR_Mask.

Die Lösung von Dr.Sommer gefällt mir noch am Besten...

von Dr. Sommer (Gast)


Lesenswert?

Wenn schon STM32 kann man auch das SDIO-Interface nehmen, dann ist's 
gleich viel schneller und die Speed Class der Karte kommt zum Tragen 
(wird bei SPI immer als 0 angenommen) :-)

Jim M. schrieb:
> Permanentes Aufheben im Datensegment verbraucht allerdings RAM, den man
> mitunter für was besseres gebrauchen könnte.
Das Gefummel mit dem SPI_InitTypeDef ist eh super ineffizient...

von Chris J. (Gast)


Angehängte Dateien:

Lesenswert?

Dr. Sommer schrieb:
> Wenn schon STM32 kann man auch das SDIO-Interface nehmen

Sag mir nicht sowas Kompliziertes.... bin froh wenn ich dieses Beispiel 
für den F100 von der ChanFat umgeschrieben habe auf meine Schreibweise. 
Denn er benutzt nur Register und Makros, die länger sind als meine 
Lebensgeschichte. Und der STM32F103 hat auch kein SDIo Interface. Bin 
froh, wenn das irgendwie läuft, der Affentanz mit der RTC, usw.

von Nop (Gast)


Lesenswert?

Chris J. schrieb:

> Mir fiel da nichts mehr ein als das hier, mit Registern. Und genau das
> will ich vermeiden, nur die API benutzen, immer.

Die SPL ist nunmal lahm. Davon ab gibt es auch keinen Grund, auf einem 
Microcontrollern Angst vor Registern zu haben; man kapselt das natürlich 
meistens in entsprechende Funktionen.


Dr. Sommer schrieb:
> SPI1->CR1 = (SPI1->CR1 & ~SPI_CR1_BR) | SPI_CR1_BR_0 |
> SPI_CR1_BR_1;

Ich nehm für sowas einen lokalen uint32_t als Schattenregister. 
Einlesen, die Operationen auf dem Schattenregister durchführen, 
zurückschreiben; ich finde das übersichtlicher.

von Dr. Sommer (Gast)


Lesenswert?

Manche STM32F103 haben ein SDIO-Modul. Da gibt's auch Beispiele für wie 
man das mit FatFs kombiniert, ich glaub sogar von ST selbst. Man kann 
das ja auch im 1-Bit-Modus verwenden um Pins/Leitungen zu sparen. Bei 
SPI arbeitet die Karte immer in einem langsamen Legacy-Modus, 
unterstützt nur die alten Befehle, ...

Nop schrieb:
> Ich nehm für sowas einen lokalen uint32_t als Schattenregister.
Ja geht auch. Das Kompilat dürfte identisch sein. Wenn man viele solcher 
Operationen hintereinander hat sind solche 1-Zeiler doch irgendwie 
übersichtlicher. Aber ist Geschmackssache.

von Chris J. (Gast)


Lesenswert?

Nop schrieb:
> Die SPL ist nunmal lahm.

Ähm... schon mal das Kompilat angeschaut? Da wird alles weg optimiert, 
jeder Funktionsaufruf verschwindet, wenn der der Parameter Frame größer 
ist als der Code selbst. Von der SPL bleibt nichts mehr übrig!. Das ist 
genauso effizient wie alles andere. Es geht nur um Lesbarkeit.

von Dr. Sommer (Gast)


Lesenswert?

Es sei denn man ruft die Funktion mehrfach auf so dass LTO nicht mehr 
greift und nicht inlined wird...

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Es sei denn man ruft die Funktion mehrfach auf so dass LTO nicht
> mehr greift und nicht inlined wird...

Das wäre ja beim Init noch hinnehmbar, abgesehen vom Bloat vielleicht, 
aber wirklich böse wird's etwa beim Beackern von GPIOs.

Davon ab verläßt man sich nicht auf die Optimierungen eines bestimmten 
Compilers in einer bestimmten Version in einer bestimmten 
Optimierungsstufe, weil das ein Update später ohne Vorwarnung zerbrechen 
kann.

Beim GCC verbietet sich LTO für embedded übrigens ohnehin, weil man dann 
-fstack-usage nicht mehr funktioniert. Obwohl, die Bastler, die die SPL 
einsetzen, machen ohnehin keine Stackanalyse, insofern ist das bei denen 
auch schon egal.

von Chris J. (Gast)


Lesenswert?

Ich habe mich vor rund 10 Jahren, ca 2008 mal mit dem PIC bis in das 
letzte Bit der MMC Spec 2.0 eingearbeitet und kannte auch die FAT16 sehr 
genau aus "DOS Intern" .... wollte auch sowas wie ne FAT schreiben, den 
Source Code von DOS hatte ich ja "organisiert" aber irgendwann 
aufgegeben. Das soll einfach nur funktionieren, 5-6 API Funktionen und 
fertig. und bei 32 Bytes pro 1 Minute, die weggeschrieben werden sollen 
juckt keine Geschwindigkeit.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Davon ab verläßt man sich nicht auf die Optimierungen eines bestimmten
> Compilers in einer bestimmten Version in einer bestimmten
> Optimierungsstufe,
Naja, dann verzichtet man aber auf eine Menge möglicher Vereinfachungen. 
Man kann sich sehr hilfreiche API's und Funktionen schreiben, welche 
aber von vernünftiger Optimierung abhängig sind. Die üblichen 
Unit/Integerations-Tests sollten eventuell scheiternde Optimierung in 
neuen Compiler-Versionen aufdecken.

Nop schrieb:
> Beim GCC verbietet sich LTO für embedded übrigens ohnehin
Und das obwohl es gerade hier einiges an Programmspeicher sparen kann?

Nop schrieb:
> Obwohl, die Bastler, die die SPL
> einsetzen, machen ohnehin keine Stackanalyse, insofern ist das bei denen
> auch schon egal.
Es gibt auch noch andere Möglichkeiten zur Stackanalyse (die einfachste: 
MPU aktivieren). Außerdem kommt man bei Controllern wie den STM32 eher 
selten an die Stack-Grenze, oder was packst du alles auf den Stack?!

von Chris J. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Und das obwohl es gerade hier einiges an Programmspeicher sparen kann?

Yup... es bläst bei mir den Code fast auf das 1,5 fache auf, wenn ich 
das nicht einschalte.

Und im Übrigen.... die Dinger sind heute so schnell, haben so viel 
Speicher dass es doch piepe ist ob da ein paar Takte mehr oder weniger 
gebraucht werden bei ganz normalen Anwendungen wo keine High Performance 
nötig ist. Heute schreibt man Code mehr leserlich als optimiert. Es ist 
egal, ob eine Routine zweimal im Speicher liegt, auch wenn sie nur 
minimal anders ist.

Davon ab verläßt man sich nicht auf die Optimierungen eines bestimmten
> Compilers in einer bestimmten Version in einer bestimmten
> Optimierungsstufe

Dann kehren wir wieder zurück zu dem Assembler Gestammel wie in Urzeiten 
und brauchen das 10-fache an Zeit um die gleiche Aufgabe zu erledigen. 
Der PC ist das ideale Beispiel wie man eine schnelle Maschine mit JAVA 
und zig anderen Underlays langsam machen kann. Windows 98 rennt bei mir 
so schnell, so schnell kann ich gar nicht gucken wie die Fenster auf 
sind, obwohl es keinen Quad Core unterstützt.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Man kann sich sehr hilfreiche API's und Funktionen schreiben, welche
> aber von vernünftiger Optimierung abhängig sind.

Mache ich im Allgemeinen nicht. Implementiert wird, was auch gebraucht 
wird, und Parametrierung auch nur da, wo nötig. Oder wo es nur um Init 
geht, da kommt es nicht so drauf an.

> Die üblichen
> Unit/Integerations-Tests sollten eventuell scheiternde Optimierung in
> neuen Compiler-Versionen aufdecken.

Wie das, wo doch Optimierung dieselbe Funktionalität beibehalten soll? 
Taktzyklenzähler?

> Und das obwohl es gerade hier einiges an Programmspeicher sparen kann?

Ist nicht so meine Erfahrung. Was natürlich spart, ist das Rauswerfen 
ungenutzer Funktionen, aber dazu braucht es keine LTO. Geht zumindest, 
solange man nichts an Bord hat, was magic sections nutzt.

> Es gibt auch noch andere Möglichkeiten zur Stackanalyse (die einfachste:
> MPU aktivieren).

Stackanalyse über Test funktioniert nicht, weil man nicht garantieren 
kann, daß man dabei tatsächlich den worst case erwischt. Das taugt 
lediglich zur Absicherung, daß man bei der Analyse nichts Wesentliches 
vergessen hat.

> Außerdem kommt man bei Controllern wie den STM32 eher
> selten an die Stack-Grenze

Das kommt drauf an, wie groß man den dimensioniert. Klar kann man den 
unsinnig groß machen, aber dann fehlt das beim normalen Speicher. 
Alternativ benutzt man dann einen zu großen Controller. ^^

von Nop (Gast)


Lesenswert?

Chris J. schrieb:

> Dann kehren wir wieder zurück zu dem Assembler Gestammel wie in Urzeiten
> und brauchen das 10-fache an Zeit um die gleiche Aufgabe zu erledigen.

Reductio ad absurdum ist zwar eine hübsche Stilfigur, aber kein 
Argument.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Mache ich im Allgemeinen nicht. Implementiert wird, was auch gebraucht
> wird, und Parametrierung auch nur da, wo nötig.

Schön für dich ;-) z.B. Metaprogrammierung erfordert typischerweise 
viele verschachtelte Aufrufe; dank Optimierung ist das dann trotzdem 
effizient, beispielsweise hier: Serialisierung. So kann man sich die 
Entwicklungszeit stark verkürzen.

Nop schrieb:
> Wie das, wo doch Optimierung dieselbe Funktionalität beibehalten soll?
> Taktzyklenzähler?
ja, oder HIL-Tests mit entsprechenden Test-Geräten. Sollte für Profis ja 
kein Problem sein. Oder ein schlichtes "diff" auf das Disassembly, oder 
die Größe vergleichen. Wenn da nicht spontan zig neue Instruktionen 
auftauchen, ist es ziemlich unwahrscheinlich dass da was dramatisch 
langsamer wird.

Nop schrieb:
> Ist nicht so meine Erfahrung.
Meine schon... Allein schon dass alle Initialisierungs-Funktionen, die 
typischerweise nur 1x am Anfang der main() aufgerufen werden, zu einer 
einzigen langen Funktion werden, spart einiges. Gilt auch für andere 
verschachtelte Konstrukte.

Nop schrieb:
> Stackanalyse über Test funktioniert nicht, weil man nicht garantieren
> kann, daß man dabei tatsächlich den worst case erwischt.
Sofern man keine Rekursion nutzt (selten bei Embedded), helfen hier 
Coverage-Messungen. Hast du eigentlich eine Quelle dass -fstack-usage 
bei LTO nicht geht? Hab bei Google auf die Schnelle nichts gefunden. Und 
geht das hier auch nicht? http://info.atollic.com/static-stack-analyzer

Ich hatte tatsächlich noch nie einen Stack-Overflow auf einem 
Mikrocontroller.

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Wenn da nicht spontan zig neue Instruktionen
> auftauchen, ist es ziemlich unwahrscheinlich dass da was dramatisch
> langsamer wird.

Es muß auch nicht viel an neuen Instruktionen sein. Recht beliebt sind 
z.B. switch-Konstrukte, die mal zu jump tables optimiert werden und ein 
anderes mal zu if-then-else-Ketten ausarten.

> Sofern man keine Rekursion nutzt (selten bei Embedded), helfen hier
> Coverage-Messungen.

Nein, die helfen nur begrenzt, weil erstens nirgendwo 100% rauskommen, 
etwa wegen Fehlerbehandlung für Hardwarefehler, und weil zweitens nicht 
garantiert ist, daß am tiefsten Punkt dann auch alle möglichen 
Interrupts aufschlagen, und dann auf die ungünstigste Weise 
verschachtelt.

> Hast du eigentlich eine Quelle dass -fstack-usage
> bei LTO nicht geht?

Nein, nur meine eigene Erfahrung. Wenn man -flto macht, enthalten die 
.su-Files nichts Nützliches mehr. Kannste mit der aktuellen GCC-Chain 
für Cortex-M einfach ausprobieren. Dokumentiert ist das nirgends, 
sondern das habe ich nur über trial & error herausbekommen.

> Ich hatte tatsächlich noch nie einen Stack-Overflow auf einem
> Mikrocontroller.

Toyota hatte den (plus noch einiges mehr) mit dem Camry. Dabei sind 
Leute umgekommen.

Kannst Dir ja das hier mal ansehen:
https://embeddedgurus.com/stack-overflow/2009/03/computing-your-stack-size/
https://embeddedgurus.com/state-space/2014/02/are-we-shooting-ourselves-in-the-foot-with-stack-overflow/

Insbesondere auf kleinen Controllern habe ich sowas außerdem schon öfter 
gesehen, weil Leute die Default-Einstellung aus irgendeiner IDE nehmen 
und nie verändern.

Es ist natürlich auch absolut nicht hilfreich, daß die meisten Projekte 
für Cortex-M den Stack ganz nach oben legen, so daß ein Overflow 
nichtmal direkt bemerkbar ist. Dann hat man nämlich nur zuerst den Heap 
kaputt, auf den der Stack zuwächst (und der seinerseits auf den Stack 
zuwächst). Nutzt man keinen Heap, zerschießt man sich stattdessen 
globale Variablen, aber das System kann durchaus noch weiterlaufen.

Lustig kann das übrigens auch und gerade mit Optimierung werden, weil 
das im worst case dazu führt, daß der Stackbedarf der beteiligten 
Funktionen sich addiert, obwohl sie nacheinander ausgeführt werden. 
Inlining sei dank. Das ist dann ein Spaß, wenn's in der Debug-Variante 
geht und im Release nicht mehr.

von Chris J. (Gast)


Lesenswert?

Nop schrieb:
> Es ist natürlich auch absolut nicht hilfreich, daß die meisten Projekte
> für Cortex-M den Stack ganz nach oben legen, so daß ein Overflow
> nichtmal direkt bemerkbar ist.

Ich möchte euch ja nicht stören, aber ein Stack Overflow müsste sich 
durch Analyse ermitteln lassen, da alle Informationen bekannt sind. 
Selbst Interrupts lassen sich als worst-case mit einbauen, wenn man 
einfach annimmt, dass alle gleichzeitig kommen. Solche Tools hatten wir 
damals bei meinem alten AG um Software, die in KKW zum Einsatz kommt zu 
prüfen.  Ich habe damit allerdings selbst nie gearbeitet, war ne andere 
Gruppe.

Und dass Debug läuft und Release nicht mehr ist normal.... damit kämpfe 
ich ständig :-) Vor allem "HardFaultHandler" springt gern mal an im 
Release.

BTW: Was ist denn das für eine zeile im ChanCode? Noch nie gesehen 
sowas...

SPIx_DR;   <<---- Häh?
SPIx_DR = d;

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Es muß auch nicht viel an neuen Instruktionen sein. Recht beliebt sind
> z.B. switch-Konstrukte, die mal zu jump tables optimiert werden und ein
> anderes mal zu if-then-else-Ketten ausarten.
Na, wenn die paar Takte stören kann man die 3 Stellen an denen es derart 
kritisch ist auch nach dem jährlichen Compiler-Update manuell testen. 
Das rechtfertigt nicht den Verzicht auf Optimierung.
Überhaupt, du schaffst es einen Code zu schreiben der derart 
zeitkritische Dinge ohne Optimierung korrekt erledigt, aber durch 
Optimierung eventuell nicht mehr, weswegen du Compiler-Optimierung 
lieber ganz bleiben lässt? Irgendwie widersprüchlich.

Professionelle Profis die sicherheitskritische Dinge tun nutzen GCC und 
-fstack-usage, aber kein anderes statisches Analysetool, und deswegen 
kein LTO? Hmm.

Nop schrieb:
> Lustig kann das übrigens auch und gerade mit Optimierung werden, weil
> das im worst case dazu führt, daß der Stackbedarf der beteiligten
> Funktionen sich addiert
Welcher Optimizer ist denn so schlecht dass er Stack-Plätze für 
nacheinander auftretende Dinge nicht wieder verwendet?

Chris J. schrieb:
> Selbst Interrupts lassen sich als worst-case mit einbauen, wenn man
> einfach annimmt, dass alle gleichzeitig kommen
Ganz genau... Das was der GCC mit -fstack-usage schafft, müssten 
"Profi-Tools" doch problemlos auf Basis des erzeugten Binaries 
hinbekommen. Für nicht sicherheitskritische Hobby-Anwendungen ist 
einfaches Testen oder genaues Hingucken ausreichend.

von Dr. Sommer (Gast)


Lesenswert?

Chris J. schrieb:
> SPIx_DR;   <<---- Häh?
> SPIx_DR = d;

Liest das Datenregister aus und verwirft das Ergebnis. Bei manchen 
(vielen?) Controllern muss man empfangene Bytes aus dem SPI-Controller 
auslesen auch wenn das Ergebnis nicht interessiert, um 
Overflow-Interrupts zu vermeiden. Dort auftretende Compiler-Warnungen 
kann man so los werden:
1
(void) SPIx_DR;

von Chris J. (Gast)


Angehängte Dateien:

Lesenswert?

Chef? Ist das richtig für MMC karten? Lässt sich aus Chan jetzt nicht 
direkt erkennen, er macht da gar nichts....

    SPI_InitStruct.SPI_CPOL      = SPI_CPOL_Low;
    SPI_InitStruct.SPI_CPHA      = SPI_CPHA_1Edge;

Anbei noch die umgeschriebene Chan Diskio auf StdPeriphLib... zumindest 
aus dem Kopf heraus, alles was so zu sehen war. Ohne Tests.

von Nop (Gast)


Lesenswert?

Chris J. schrieb:

> Ich möchte euch ja nicht stören, aber ein Stack Overflow müsste sich
> durch Analyse ermitteln lassen, da alle Informationen bekannt sind.

Läßt er sich auch, sofern man keine datenabhängigen Sachen wie Rekursion 
oder Funktionszeiger benutzt.

Dr. Sommer schrieb:

> Professionelle Profis die sicherheitskritische Dinge tun nutzen GCC und
> -fstack-usage, aber kein anderes statisches Analysetool, und deswegen
> kein LTO? Hmm.

Professionell nutzt man GCC u.a. deswegen nicht, zumal -fstack-usage 
auch nur so halbherzig funktioniert. Kein Vergleich mit dem, was z.B. 
der Keil einem direkt gebrauchsfertig auswift. Beim GCC muß man sich den 
relevanten Calltree selber zusammenfummeln, weil der das nur pro 
Funktion auswirft, und den Call-Overhead muß man sich auch selber 
raussuchen.

Wenn man das bei ein paar Projekten gemacht hat, rechnet die Keil-Lizenz 
sich allein schon für die Zeitersparnis, die bei kommerziellen Projekten 
ja relevant ist.

> Welcher Optimizer ist denn so schlecht dass er Stack-Plätze für
> nacheinander auftretende Dinge nicht wieder verwendet?

Der Punkt ist, daß das für den Compiler bloß Interna sind, die nirgendwo 
garantiert werden. Ob der das jetzt in seiner Scope-Analyse hinbekommt, 
hängt auch davon ab, wie die Funktionen aufgerufen werden.

> Für nicht sicherheitskritische Hobby-Anwendungen ist
> einfaches Testen oder genaues Hingucken ausreichend.

Für Hobbyprojekte sehe ich das deswegen anders, weil einem da kein 
Zeitplan im Nacken sitzt. Da kann man in aller Ruhe auch mit der eher 
umständlichen GCC-Methode manuell arbeiten.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Professionell nutzt man GCC u.a. deswegen nicht, zumal -fstack-usage
> auch nur so halbherzig funktioniert.
Dann stört LTO auch nicht...

Nop schrieb:
> Wenn man das bei ein paar Projekten gemacht hat, rechnet die Keil-Lizenz
> sich allein schon für die Zeitersparnis, die bei kommerziellen Projekten
> ja relevant ist.
Tja, der Keil-Compiler basiert mittlerweile auf Clang/LLVM, was mit dem 
ganzen LTO-Zeug ja erst angefangen hat... :) Somit unterstützt der ja 
sogar C++14, aber C++17 (noch?) nicht.

Nop schrieb:
> Der Punkt ist, daß das für den Compiler bloß Interna sind, die nirgendwo
> garantiert werden.
Die sonstige Funktion des eigenen Programms ist auch nicht garantiert... 
Ausführliche Analysen wie HIL und statische Analyse muss man sowieso 
machen, da kann man auch die Stack-Nutzung und Effizienz mit prüfen.

Nop schrieb:
> Da kann man in aller Ruhe auch mit der eher
> umständlichen GCC-Methode manuell arbeiten.
Oder eben ganz manuell oder mit Stichproben-Tests, und sich über die 
hilfreiche Compiler-Optimierung freuen.

von Chris J. (Gast)


Lesenswert?

Danke erstmal, dass ihr meinen Thread gekapert habt :-(

Zurück zum Thema: Hat von euch schonmal jemand die ChatFat verwendet und 
wie ging er da mit der RTC um? Ich bin grad am durch kompilieren und 
hoffe, dass irgendwann mal eine leere Datei auf der Karte erscheint, 
wenn alles richtig ist was ich aus dem Kopf heraus verändert habe an 
diskio.c.  Braucht man die RTC für die Filenames?

Grumpf... müsste erstmal reichen...

FILINFO Finfo;
FRESULT fr;
FATFS FatFs;
FIL Fil;
DIR Dir;

f_mount(&FatFs,"", 0);
f_open(&Fil,"test.txt",FA_CREATE_ALWAYS);
f_close(&Fil);

von Dr. Sommer (Gast)


Lesenswert?

Wie kommst du überhaupt auf RTC? Was hat FatFs mit einer RTC zu tun? Das 
funktioniert doch auch auf Controllern die überhaupt keine haben.

von Chris J. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Wie kommst du überhaupt auf RTC? Was hat FatFs mit einer RTC zu tun?

Weil ich das einzig verfügbare Beispiel "ffsample" umschreibe und die 
RTC sehr wohl eng verwoben ist in der FAT von Chan. Er widmet dem ganzen 
reichlich Raum. Brauche ich eh, da die Files einen Datumsstempel haben 
sollen. Der ganze Ramsch zur Umwandlung der Unixtime in Normzeit ist 
auch da drin.

1
/*---------------------------------------------------------*/
2
/* User provided RTC function for FatFs module             */
3
/*---------------------------------------------------------*/
4
/* This is a real time clock service to be called back     */
5
/* from FatFs module.                                      */
6
7
#if !FF_FS_NORTC && !FF_FS_READONLY
8
uint32_t get_fattime (void)
9
{
10
  RTCTIME rtc;
11
12
  /* Get local time */
13
  if (!rtc_gettime(&rtc)) return 0;
14
15
  /* Pack date and time into a uint32_t variable */
16
  return    ((uint32_t)(rtc.year - 1980) << 25)
17
      | ((uint32_t)rtc.month << 21)
18
      | ((uint32_t)rtc.mday << 16)
19
      | ((uint32_t)rtc.hour << 11)
20
      | ((uint32_t)rtc.min << 5)
21
      | ((uint32_t)rtc.sec >> 1);
22
}
23
#endif

von Dr. Sommer (Gast)


Lesenswert?

1
#define FF_FS_NORTC    0
2
#define FF_NORTC_MON  1
3
#define FF_NORTC_MDAY  1
4
#define FF_NORTC_YEAR  2017
5
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
6
/  any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
7
/  the timestamp function. All objects modified by FatFs will have a fixed timestamp
8
/  defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
9
/  To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
10
/  added to the project to read current time form real-time clock. FF_NORTC_MON,
11
/  FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
12
/  These options have no effect at read-only configuration (FF_FS_READONLY = 1). */
1
DWORD get_fattime (void);
Das zurückggebene Format ist offensichtlich identisch zu dem, was im 
FAT-Verzeichniseintrag steht. Dazu steht auf Wikipedia:

(5  6  5 Bits für Stunde // Minute // Sekunden)
(7  4  5 Bits für Jahr // Monat // Tag)

Noch Fragen?

von Chris J. (Gast)


Lesenswert?

Nö, schon kapiert..... kompiliert erstmal durch. Trotzdem.... durch 
seine "eigenen Typen", wie UINT, DWORD usw. die man leider verwenden 
muss, damit man nicht dauernd Warnings kriegen will weil "inkompatibel" 
nervt das schon etwas uint8_t etc sind ja nunmal Standard.  GCC erkennt 
nicht, dass DWORD und uint32_t das Gleiche sind, meckert es an. Der 
Aufruf von f_write muss genauso sein, wie im Prpptotypen deklariert:

FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw);  /* 
Write data to the file */

Ich weiss nicht was passiert wenn ich durch globales Ersetzen alle 
Wörter durch die standardisierten ersetze. Das könnte mächtig schief 
gehen, es sind hunderte Stellen, die ersetzt werden müssten.

von Dr. Sommer (Gast)


Lesenswert?

Ja, da sieht man was man davon hat wenn man meint alle Integer-Typen neu 
erfinden zu müssen... Leider ein weit verbreitetes Vorgehen. Hab ich 
besonders gerne beim von Simulink generierten Code. Du kannst die 
integer.h-Datei ja mal rabiat so ändern:
1
/*-------------------------------------------*/
2
/* Integer type definitions for FatFs module */
3
/*-------------------------------------------*/
4
5
#ifndef FF_INTEGER
6
#define FF_INTEGER
7
8
#include <stdint.h>
9
10
typedef int16_t INT;
11
typedef uint16_t UINT;
12
13
typedef uint8_t BYTE;
14
typedef int16_t SHORT;
15
typedef uint16_t WORD;
16
typedef uint16_t WCHAR;
17
18
typedef int32_t LONG;
19
typedef uint32_t DWORD;
20
21
typedef uint64_t QWORD;
22
23
#endif

Besonders lustig ist, dass in ARM-Nomenklatur ja ein "Word" 32bit sind, 
und ein "Doppel-Wort" 64bit...

Chris J. schrieb:
> GCC erkennt
> nicht, dass DWORD und uint32_t das Gleiche sind, meckert es an.
Gut möglich, wenn das eine int und das andere long sind. Laut Standard 
sind Integer-Typen mit gleicher Größe dennoch unterschiedlich.

von Chris J. (Gast)


Lesenswert?

Ich sehe das auch so: Sollte heute abend nicht beim Debug Step die Datei 
auf der Karte sein ist es mit meinen Mitteln hier unmöglich heraus zu 
finden, warum sie es nicht ist, da selbst der LA aus China, den ich hier 
habe es kaum zulässt heraus zu finden, ob der Datenwust richtig ist, der 
allein für die Initialisierung der Karte gesendet werden muss. Beim 
Arduino lief es auf Anhieb, plug &play, hier bin ich sehr skeptisch. 
Dafür habe ich gerad viel zu viel verändert ohne einen einzigen Test 
gemacht zu haben.

>>Du kannst die integer.h-Datei ja mal rabiat so ändern.

Bin dabei sie ganz "abzuschaffen".....

von Dr. Sommer (Gast)


Lesenswert?

Chris J. schrieb:
> Ich sehe das auch so: Sollte heute abend nicht beim Debug Step die Datei
> auf der Karte sein ist es mit meinen Mitteln hier unmöglich heraus zu
> finden
Also ich hab mit einem billigen China-Oszilloskop, einem 
08/15-Kartenleser, einem Windows-PC und einem Hex-Editor(!!) meinen 
eigenen SD-Karten- und FAT32-Treiber für STM32 entwickelt, der schneller 
und besser als FatFs ist. Da brauchts keine Spezial-Hardware für... Hat 
aber auch länger als einen Tag gedauert :o)

Chris J. schrieb:
> Beim
> Arduino lief es auf Anhieb, plug &play, hier bin ich sehr skeptisch.
So ist Arduino konzipiert. Man kann nicht erwarten dass alles so einfach 
wie bei Arduino ist.

von Chris J. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> meinen
> eigenen SD-Karten- und FAT32-Treiber für STM32 entwickelt

Ok... und das ganz ohne Therapiesitzungen nachher? Ich meine nur .... 
meine Freundin meint auch immer ich "spinne" ein wenig, wenn ich 8h 
programmiert habe und diesen Blick drauf habe, der nur geradeaus 
geht.... so nicht mehr von dieser Welt ....

PS: Am Schnellsten sind festverdrahtete ASIC Lösungen, die es schon 
fertig gibt :-) In jedem USB Stick....

von Dr. Sommer (Gast)


Lesenswert?

Chris J. schrieb:
> Ok... und das ganz ohne Therapiesitzungen nachher? Ich meine nur ....

Davon nicht. Die brauch ich nur wegen des grässlichen Korsetts und 
Arbeits-Rhythmus das einem ein Hochschulstudium aufzwingt. Und 8h sind 
doch nix :o) Leute deren Studium zu 80% aus Kaffee Trinken besteht haben 
da wenig Verständnis für...

von Dr. Sommer (Gast)


Lesenswert?

Chris J. schrieb:
> PS: Am Schnellsten sind festverdrahtete ASIC Lösungen, die es schon
> fertig gibt :-) In jedem USB Stick....
Die haben aber keine Speed Class...

von Chris J. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Leute deren Studium zu 80% aus Kaffee Trinken besteht haben
> da wenig Verständnis für...

Meines bestand zu 20% daraus, 30% Verbindungsleben und 50% pauken bis 
Umfallen.... 1995 :-))

Ok, Ende..... Pause..... mal raus gehen..... Schnee angucken....

von Dr. Sommer (Gast)


Lesenswert?

Ingenieure in Verbindungen? Ich dachte das wär mehr was für Juristen...

Der Schnee ist hier schon wieder weg, hier ist Winter nur kalt, dunkel, 
wolkig und nass.

von Chris J. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Ingenieure in Verbindungen? Ich dachte das wär mehr was für Juristen...

Juristen, Mediziner. Gebe auch zu, dass ich da heute nichts mehr mit am 
Hut habe, auch nie wieder da war seit 15 Jahren. Mein Vater war 
Freimaurer höheren Grades, wollte auch dass ich da unbedingt 
mitmache....  in der Loge war der Jüngste 60 und ich damals 28, 
Techno-Fan, fuhr einen getunten Ford Capri II mit fettem Heck-Spoiler, 
passte wunderbar... hicks. Man kann auch ohne diesen Zirkus glücklich 
leben und trotzdem Dipl.Ing. werden.

von Dr. Sommer (Gast)


Lesenswert?

Ach du heilige... Bzgl Trinkfestigkeit gibt sich Ingenieur und 
Verbindungsmitglied wohl nicht viel :-)

Beitrag #5357651 wurde von einem Moderator gelöscht.
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.