Hallo,
ich möchte auf einem F103 Blue Pill Board einen HCT595 mit Bits
befüllen. Mangels freier SPI schiebe ich die Bits einzeln heraus.
Frage: Muss man bei eingeschalteter GCC Optimierung -Os beim Toggeln
eines Portpins einen Delay einlegen? Ich kenne die interne Schaltung des
Cortex nicht, weiss nicht wie Piplines oder Caching da reinfummeln
können, denn das physikalische Setzen eines Pins mit sofortigem
Rücksetzen könnte ja auch verschluckt werden.
Könnte mir da jemand eine sichere Lösung nennen, die aber optimale
Geschwindigkeit bietet? (72 Mhz)
Grüße,
Christian
Überrennen wirst du nichts, keine Sorge. Erwarte aber keine
herausragende Toogle-Frequenz vom F103, denn bei dem hängen die GPIOs an
einem der APB Peripheriebusse. Bei späteren STM32 hängen sie am
flotteren AHB.
Christian J. schrieb:> Frage: Muss man bei eingeschalteter GCC Optimierung -Os beim Toggeln> eines Portpins einen Delay einlegen? [...] 72 MHz
Ja, aber nur weil der Pin sonst nicht hinterher kommt.
Ich würde einfach ein oder zwei __NOP(); einfügen - und mit dem Oszi das
Signal kontrollieren, falls was nicht tut.
Verschluckt wird nix, aber der Pin hat ja nur eine begrenzte Stromstärke
und muss die Eingagskapazität des/der 595 umladen.
Übrigens kommt es auch darauf an wie genau Du die Ports setzt - falls da
ein Funktionsaufruf statt findet, brauchst Du keine Nops mehr einfügen.
Direktes Schreiben der Pinsetz/Pinlösch- Register geht am schnellsten.
Jim M. schrieb:> Verschluckt wird nix, aber der Pin hat ja nur eine begrenzte Stromstärke> und muss die Eingagskapazität des/der 595 umladen.
So krass ist die Eingangskapazität eines nah angebundenen 595 nicht,
dass man sich eigens deshalb Sorgen machen müsste. Die GPIO Pins sind
zudem auf die vorgesehene Frequenz konfigurierbar.
Hallo,
ok. Liege ich hiermit jetzt total falsch? Ein AVR hat mit einem ARM
allerdings gemeinsam und solche Sachen wie oben sind mir zu aufgeblasen.
Man kann auch Schleifen entrollen lassen wenn man will. Und so 10 Mhz
reichen auch, das menschliche Auge kommt da eh nicht mehr mit bei den
LEDs, die am 595 dran sind.
Christian J. schrieb:> Hallo,>> ich möchte auf einem F103 Blue Pill Board einen HCT595 mit Bits> befüllen. Mangels freier SPI schiebe ich die Bits einzeln heraus.
Du kannst auch mehrere ICs an den SPI hängen.
Christian J. schrieb:> /* Schreibt ein 8 Bit Wort in den 74HCT595 */> void Set74HCT595(uint8_t data)> {> for (uint8_t i = 0; i < 8; i++) {> // Datenbit setzen> GPIO_WriteBit(HC595_PORT,HC595_DS,(data & 0x80)); __DMB(); //> Bit anlegen> GPIO_SetBits(HC595_PORT,HC595_SHCP); __DMB(); //> SHCP -> High> GPIO_ResetBits(HC595_PORT,HC595_SHCP); __DMB(); //> SHCP -> LOW> data = data << 1;
Mir kommen da Bedenken bzgl. Beleidigung der Ostfriesen, wenn ich bei
obigem an die Frage denke, wie viele Ostfriesen man zum Reinschrauben
einer Glühbirne braucht.
Geht's vielleicht noch etwas komplizierter?
W.S.
Christian J. schrieb:> for (uint8_t i = 0; i < 8; i++)
Genereller Tip für AVR-Umsteiger: nimm auf ARM Cortex-M keine
8bit-Variablen, wenn dies nicht unumgänglich ist (Strings, große
Structs, Grafiken oder so). Es ist deutlich langsamer, als wenn man mit
32bit arbeitet. Insbesondere Schleifenvariablen sollten immer mit 32bit
realisiert werden.
Entweder, Du nimmst gleich uint32_t, oder wenn Du es richtig sauber
machen willst, dann lautet der korrekte Datentyp "uint_fast8_t".
Nop schrieb:> Entweder, Du nimmst gleich uint32_t, oder wenn Du es richtig sauber> machen willst, dann lautet der korrekte Datentyp "uint_fast8_t".
Richtig sauber? Quatsch mit Soße sowas.
Für normale lokale Variablen einfach int oder long und gut isses. Die
angebrannte Diskussion über uintXYZ_t hatten wir schon - und sie war
komplett albern.
Nein, das Codebeispiel von Christian sieht einfach grauselig aus. Das
ist der Punkt.
1
longm;
2
3
m=0x80;
4
while(m)
5
{clockbit_low();
6
databit(data&m);
7
clockbit_high();
8
m=m>>1;
9
}
und die Funktionen
void clockbit_low(void)
und
void clockbit_high(void)
sowie
void databit(bool b)
kann sich der TO selber schreiben.
Das läuft im Prinzip auf ein __inline void ....
mit GPIOx_BSRR = 1<<bitnummer oder 1<<(bitnummer+16) heraus.
W.S.
Christian J. schrieb:> Könnte mir da jemand eine sichere Lösung nennen, die aber optimale> Geschwindigkeit bietet? (72 Mhz)
Beim STM kannst Du per DMA Daten zwischen SRAM und Peripherie
verschieben.
Du kannst also mit ein paar GPIO's und DMA eine flotte SPI emulieren.
Für die DMA brauchst Du noch einen Trigger, aber irgendein Timer wird
sich noch finden, oder?
Das ist typisch für einen ARM + IP-Cores ->
Hohe mittlere Rechenleistung in der CPU, aber richtig schnell wird das
Embedded Dingens erst mit DMA.
Und wenn der -o3 GCC zu langsam ist, bleibt immer noch die Möglichkeit
Assembler zu schreiben. ;)
Grad nochmal geschaut - einem NXP HCT595 @ 3V3 bei Zimmertemperatur
würde ich nicht mehr als 10..15MHz zumuten. ;)
W.S. schrieb:> Richtig sauber? Quatsch mit Soße sowas.
Es stand im zitierten Text deutlich "uint8_t"; anders als Dir sind dem
Mitposter also die Errungenschaften von C99 vertraut. Nur falsch benutzt
für ARM.
> Für normale lokale Variablen einfach int oder long und gut isses.
Und dann rumheulen, daß die Datentypen überall ne andere Breite haben.
Nimm einfach mal zur Kenntnis, daß der Rest der C-Welt die portablen
Datentypen seit 18 Jahren verstanden hat UND in der Lage ist, damit den
eigenen Code leserlicher zu gestalten.
Nop schrieb:> Nimm einfach mal zur Kenntnis, daß
Nimm du einfach mal zur Kenntnis, daß wir da ganz offensichtlich völlig
konträre Positionen vertreten UND daß die Welt weitaus größer ist als
nur die C99-Welt UND daß ich keine Lust mehr habe, mit all den uint123_t
Leuten darüber zu diskutieren. Sowas wie "uint_fast8_t" ist die Krätze
und auf keinem ARM vonnöten.
Also laß es, wir sollten uns besser um ganz andere Probleme kümmern.
W.S.
Nop schrieb:> Es ist deutlich langsamer, als wenn man mit> 32bit arbeitet. Insbesondere Schleifenvariablen sollten immer mit 32bit> realisiert werden.
Stimmt das wirklich? Denn eine 8 Bit Variable braucht auch nur 8 Bit im
Speicher und habe mal gelernt, dass man immer den kleinsten Datentyp
verwenden soll der geht. Und bei den stdtype.h Typen weiss ich nunmal
wie lang die sind, bei einem int nicht. Ok, der hat hier 32 Bit aber
woanders eben nicht.
Wie managed der Arm denn Variablen, die kleiner als die Busbreite sind?
PS: Danke für den TIP; dass eine SPI auch mehrere Geräte ueber den CS
steuern kann. Völlig übersehen :-)
@W.S.: Ich magh Deine schnoddrige Art nicht aber das lass ich mal aussen
vor. Ich benutze soweit es geht die mitgelieferten Funktionen, wobei es
völlig unerheblich ist wieviel Quelltext die produzieren. Kompiliert und
Optimiert ist die Schleife winzig klein, da der Compiler die Subroutinen
alle wegoptimiert und nur noch registerzugriffe einfügt. Totoptimiert
lässt man sie von 8 runter auf 0 laufen und spart noch ein Compare ein,
hat nur noch einen Zero Flag Test.
DMA ist mir zwar gut vertraut aber hier eher nicht angebracht. Es werden
5 kaskadierte HC595, die viele LEDs dran haben gefüttert und das nur
recht selten. Ist eine Bargraph Anzeige für Spannungen. Und um die 5x8
Bit raus zu trommeln habe ich die Zeit. DMA ist auch recht viel
nachdenken, mache ich gerne bei AD Wandlern, die mir fortlaufend Arrays
vollschreiben, die ich dann gleich auslesen kann.
Mehr als 8 Mhz habe ich auf Lochrasterplatine noch nicht gescheit zum
Laufen gekriegt. Ab 12 Mhz verhaspeln sich die Bits, zb bei einem
Display.
Christian J. schrieb:> Wie managed der Arm denn Variablen, die kleiner als die Busbreite sind?
Nicht nur bei ARM, auch bei x86 sind Typen kleiner als "int" im
Nachteil.
x86-64, gcc 4.7.2, -O2, besonders krass, da der Compiler zwar einen
korrekt auf 32-Bits erweiterten Wert an g1() übergibt, aber bei den
eigenen Parametern von 8-Bit Werten ausgeht und folglich erst einmal
erweitert:
Nop schrieb:> Es ist deutlich langsamer, als wenn man mit> 32bit arbeitet. Insbesondere Schleifenvariablen sollten immer mit 32bit> realisiert werden.
Was ist für Dich deutlich, 1%?
Ich würde die Compilerbauer nicht für Idioten halten, die werden als
Loopzähler natürlich ein ganzes Register nehmen, d.h. keinerlei
merkbaren Geschwindigkeitseinbuße.
Und selbst wenn in einer kleinen Loop von 20 Befehlen noch ein
überzähliges AND 0x000000FF drin sein sollte, merkt das niemand.
Sowas zählt für mich unter Mikrooptimierung, da ist mir die Portabilität
deutlich mehr wert.
Ich bin jetzt auch dabei, in printf/scanf die portablen Formatbezeichner
zu verwenden.
Peter D. schrieb:> Nop schrieb:>> Es ist deutlich langsamer, als wenn man mit>> 32bit arbeitet. Insbesondere Schleifenvariablen sollten immer mit 32bit>> realisiert werden.
.
> Was ist für Dich deutlich, 1%?> Ich würde die Compilerbauer nicht für Idioten halten, die werden als> Loopzähler natürlich ein ganzes Register nehmen, d.h. keinerlei> merkbaren Geschwindigkeitseinbuße.> Und selbst wenn in einer kleinen Loop von 20 Befehlen noch ein> überzähliges AND 0x000000FF drin sein sollte, merkt das niemand.
.
> Sowas zählt für mich unter Mikrooptimierung, da ist mir die Portabilität> deutlich mehr wert.> Ich bin jetzt auch dabei, in printf/scanf die portablen Formatbezeichner> zu verwenden.
Genau, weil sie eh "ein ganzes Register nehmen", macht es keinen Sinn da
ein paar Bits sparen zu wollen.
Aber ich werde mal den GCC fragen, wie er das sieht.
Christian J. schrieb:> @W.S.: Ich magh Deine schnoddrige Art nicht aber das lass ich mal aussen> vor. Ich benutze soweit es geht die mitgelieferten Funktionen, wobei es> völlig unerheblich ist wieviel Quelltext die produzieren.
Nun, da mußt du halt mit zurechtkommen, schließlich muß ich ja auch mit
mir selbst zurechtkommen - ABER: Wieso Nop auf die Idee gekommen ist,
ausgerechnet so ein Ungetüm wie "uint_fast8_t" vorzuschlagen, ist mir
ein Rätsel. Er hat doch ansonsten recht vernünftige Ansichten.
Guck dir mal meinen aus dem Handgelenk geschlenkerten Vorschlag an, da
wirst du sehen, daß es auch ganz ohne Schleifenzähler geht und damit die
ganze Diskussion um "uint_fast8_t" und Konsorten per se völlig
überflüssig ist. Sieht denn sowas Simples kein anderer unter den
Disputanten hier?
Ich sag's mal so: Ein guter Programmierer zeichnet sich nicht dadurch
aus, daß er sämtliche "uint_fast8_t" und Konsorten auswendig kennt,
sondern daß er gute Herangehensweisen und gute Algorithmen draufhat.
Es ist wichtig, den Kern einer Sache schnell und gründlich zu
durchblicken. Das ist nicht nur Erfahrungssache, sondern braucht auch
Kenntnisse von Dingen, die scheinbar außerhalb des Gesichtskreises
liegen. Olle Napoleon soll wohl mal Bewerber auf einen Offiziers-Posten
gefragt haben "Hat er Fortune?" - nee, nicht ob er bislang Schwein
gehabt hat.., eher ob er Durchblick und ein Händchen für's
Richtig-Machen und damit für's Siegen hat. Er brauchte eher nen
Strategen und keinen Beckmesser. Das ist der Punkt.
Angehenden C-Programmierern würde ich deswegen anraten, parallel dazu
ein Mathe-Studium zu belegen, Elektrotechnikern und Informatikern ein
paralleles Physikstudium und Chemikern ein Stück Maschinenbau. Kurzum,
einen größeren eigenen Horizont zu erwerben.
W.S.