Hallo zusammen,
seit ein paar Tagen beschäftige ich mich mit den Timern des STM32F103.
Kurze Erläuterung was ich machen will:
Ich habe in einem Array 12 bit, die ich nacheinander auf einem Pin
ausgeben will. Gedacht ist das in etwa so:
So meiner Überlegung nach müsste der Timer jetzt bis zu dem Wert in ARR
zählen und dann das UIF bit im SR setzen. Auf dieses setzen warte ich
mit meiner while((TIM2->SR & 0x1) != 0x1) und mit TIM2->SR = 0 lösche
ich es wieder.
Das funktioniert auch bei einem Wert von ARR = 1 wunderbar, ca alle
500ns schickt er das nächste bit auf die Reise.
Wenn ich jetzt aber den Wert von ARR erhöhe (so bis ca 500) ergeben sich
große Unterschiede(bis zu 100ns) zwischen den einzelnen Wartezeiten. Ab
ca 500 allerdings nicht mehr oder sie fallen auf dem Oszi einfach nicht
mehr auf. Das selbe passiert, wenn ich am PSC einen anderen Wert als 0
anlege.
Nun meine Frage, woran kann das liegen? Habe ich einen Fehler bei den
Registern gemacht? Oder macht mir irgendeine Hardwarekomponente einen
Strich durch die Rechnung? Ich verwende das MCBSTM32E von Keil, ebenso
deren µVision IDE und im Projekt die von Keil gegebene
Initialisierungsroutine/den Initialisierungswizzard.
Hoffe ihr könnt mir helfen :)
Danke und Gruß
Mathias
Also ich komm schon am Anfang nicht mit. Im Array data sind 12 bit und
der Wert des bits soll an Port E ausgegeben werden? Also wenn das bit in
data[0] 0 ist, soll Pin 0 an Port E auch 0 sein, wenn das bit in data[0]
1 ist, soll Pin 0 an Port E auch 1 sein?
Oder sollen 12 byte im Array sein? Würde mehr Sinn machen.
GPRIOE gibt es wohl nicht.
^
Unabhängig davon kannst Du
while((TIM2->SR & 0x1) != 0x1);
einfacher so schreiben:
while(!(TIM2->SR & 0x1));
Und die ganzen Abfragen und Tests lassen sich in einer Schleife, z.B.
for, viel sparsamer machen.
Außerdem: Wenn CR1 = 0 ist, dann läuft der Timer doch sowieso gar nicht
???
Nachmacher schrieb:> Also ich komm schon am Anfang nicht mit. Im Array data sind 12 bit und> der Wert des bits soll an Port E ausgegeben werden? Also wenn das bit in> data[0] 0 ist, soll Pin 0 an Port E auch 0 sein, wenn das bit in data[0]> 1 ist, soll Pin 0 an Port E auch 1 sein?> Oder sollen 12 byte im Array sein? Würde mehr Sinn machen.
Nein war schon so gedacht, data[x]=0 => Pin auf 0, data[x]=1 => Pin auf
1
> GPRIOE gibt es wohl nicht.
stimmt ^^ war ein Tippfehler
> Unabhängig davon kannst Du> while((TIM2->SR & 0x1) != 0x1);> einfacher so schreiben:> while(!(TIM2->SR & 0x1));
Hmm ok danke
> Und die ganzen Abfragen und Tests lassen sich in einer Schleife, z.B.> for, viel sparsamer machen.
Welche Abfragen meinst du?
> Außerdem: Wenn CR1 = 0 ist, dann läuft der Timer doch sowieso gar nicht> ???
Oh stimmt der Timer wird im Code erst aktiviert, dann ist CR1 = 1
Mathias Dubdidu schrieb:> Nein war schon so gedacht, data[x]=0 => Pin auf 0, data[x]=1 => Pin auf> 1
Gut, aber dann wird, sofern das Array wirklich nur jeweils 1 bit enthält
GPIOE->BSRR = data[x];
ausschließlich auf Pin 0 von Port E einen Effekt haben, soll das so
sein?
Mathias Dubdidu schrieb:>> Und die ganzen Abfragen und Tests lassen sich in einer Schleife, z.B.>> for, viel sparsamer machen.>> Welche Abfragen meinst du?
1
GPRIOE->BSRR=data[0];
2
while((TIM2->SR&0x1)!=0x1);
3
TIM2->SR=0;
4
5
GPIOE->BSRR=data[1];
6
while((TIM2->SR&0x1)!=0x1);
7
TIM2->SR=0;
8
9
...usw.
Den Index des Arrays "data" kann man sehr schön in einer for-Schleife
mit "index++" durchlaufen lassen.
Nachmacher schrieb:> Gut, aber dann wird, sofern das Array wirklich nur jeweils 1 bit enthält> GPIOE->BSRR = data[x];> ausschließlich auf Pin 0 von Port E einen Effekt haben, soll das so> sein?
Nein verwendet wird Pin 3, den erreiche ich, indem ich im das BSRR
Register das bit Nr. 19 immer setze und bit nr. 3 setze bzw. lösche
jenachdem ob eine 0 oder 1 kommt. So wird dann quasi gleichzeitig der
Pin gesetzt und gelöscht, wobei das setzen gewinnt. Wie gesagt
funktioniert auch wunderbar.
> Den Index des Arrays "data" kann man sehr schön in einer for-Schleife> mit "index++" durchlaufen lassen.
Ja schon nur Zeitlich ist es doch effektiver, wenn ich es untereinander
schreibe, weil ich dann nicht nach jeder Ausgabe den Sprung zurück habe.
Da es nur die eine Stelle ist, wo das wichtig ist, nehm ich den mehr
schreibaufwand in Kauf.
Mein eigentliches Problem ist, dass ich auf ein setzen des UIF bits
warte bevor ich das nächste Datum sende. Die Interrupts sind aber
disabled.
Auch wenn ich nur schreibe:
1
while(1){
2
GPIOE->BRR=GPIOE_Pin_4;
3
if((TIM3->SR&0x1)!=0){
4
GPIOE->BSRR=GPIOE_Pin_4;
5
TIM3->SR=0;
6
}
7
}
ergeben sich große Untschiede(ca 50-90ns) zwischen den einzelnen
Perioden.
Arbeite ich aber mit der Interruptroutine, bleiben die Abstände alle
schön konstant, wobei ich nicht sehr schnell sein kann, da er sonst
während des Interrupts bereits den nächsten bringt.
Zu gunsten der Geschwindigkeit würde ich auf die Interrupts ganz
verzichten und eben nur das Flag prüfen.
Hat jemand eine Idee, woher die Schwankungen kommen bzw. wie ich sie
vermeide?
Gruß
Für einzeln programmierte Portbitsteuerung mit ridigen Zeitbedingungen
in der erwähnten Grössenordnung sind die STM32 schlicht und einfach die
falsche Plattform. Die STM32 sind weder FPGA noch CPLD, noch haben sie
die enge streng deterministische Kopplung von Core und I/O-Bus mancher
anderer Controller. So kann beispielsweise die eher lose teilweise
gepufferte Entkopplung von Core, Hauptbussen und mehreren sekundären
Peripheriebussen für Jitter sorgen.
Bits seriell äquidistant auszugeben geht mit diesen Anforderungen aber
durchaus, aber man muss weg von der Idee, sie einzeln auf die Ports zu
schreiben, sondern muss Peripheriemodule verwenden, die das von Haus aus
erledigen, wie beispielsweise SPI.
Wenn man dennoch darauf besteht, sowas unter Programmkontrolle
einzelbitweise durchzuführen, dann sollte man auf Plattformen wechseln,
die dafür geeigneter sind. Regelrecht dafür optimiert sind
beispielsweise der Parallax Propeller oder die Typen von XMOS.
Mathias Dubdidu schrieb:> Nein verwendet wird Pin 3, den erreiche ich, indem ich im das BSRR> Register das bit Nr. 19 immer setze und bit nr. 3 setze bzw. lösche> jenachdem ob eine 0 oder 1 kommt.
Das entspricht aber nicht dem von Dir geposteten Code
> GPRIOE->BSRR = data[0];
Das Gleichheitszeichen setzt das Register BSRR auf den Wert von data[0].
Da das Array data[] nur jeweils 1 bit enthält, und wenn data[0] = 1 ist,
steht m.W. bei GPIOE->BSRR = data[0] der Wert GPIOE->BSRR = 1, also das
Register BSRR hat den Wert 1 (was widerum bedeutet, daß BS0 in BSRR
gesetzt ist). Das ergibt laut meinem Datenblatt, daß über das ODR der
Pin 0 des Port E auf 1 gesetzt wird. Wenn data[0] den Wert 0 hat, hat
auch das Register BSRR den Wert 0.
Durch das Gleichheitszeichen wird in diesem Fall eine absolute Zuweisung
mit 0 oder 1 an das Register BSRR gemacht. Hier wird nichts verodert.
Laut erstem Code steht dort GPIOE->BSRR = data[0]; und nicht, wie im
letzten Text, bit 19 in BSRR immer gesetzt wird und bit 3 (welches aus
data[] kommt), damit verodert wird. Der korrekte Code müßte gemäß
letzter Beschreibung also GPIOE->BSRR = 1<<19 | data[0]; lauten.
Ansonsten bitte etwas genauer den Teil der Doku benennen, der etwas
anderes beschreibt.
Ich gehe davon aus, dass er zwecks Beschleunigung der Bitausgabe im
Array die passenden Werte bereits stehen hat. Das Thema BSRR war bereits
geklärt worden. Allerdings in einem anderen Thread, wie ich grad
feststelle.
A. K. schrieb:> Ich gehe davon aus, dass er zwecks Beschleunigung der Bitausgabe im> Array die passenden Werte bereits stehen hat.
Na um so mehr müßte dann doch die Aussage
> Das Gleichheitszeichen setzt das Register BSRR auf den Wert von data[0].
stimmen, wenn im Array bereits passenden Werte komplett drinstehen? Oder
bin ich völlig neben der Spur?
Jetzt wird's zugegebenermassen etwas sophistisch. Denn es gibt
eigentlich überhaupt kein BSRR Register. Auch wenn's im letzten R so
heisst.
Es gibt ein ODR Register, das durch Zugriff auf verschiedene Adressen
auf verschiedene Art manipuliert wird. BSRR ist eine dieser
Funktionsadressen.
Ein Schreibzugriff auf BSRR schreibt also nicht ins "Register" BSRR,
sondern ins ODR, nach den für den Zuriffspfad BSRR geltenden Regeln.
A. K. schrieb:> Jetzt wird's zugegebenermassen etwas sophistisch.
Korrekt. Obwohl ... siehe weiter unten.
>Denn es gibt eigentlich überhaupt kein BSRR Register. Auch wenn's im letzten R so >heisst.
Wie lautet ein viel zitierter Spruch: Das Datenblatt hat immer Recht...
(na ja...). Laut dem Datenblatt gibt es ein Register BSRR. Ob dies ein
Hardwareregister ist oder ein gemapptes, darüber schweigt sich das
Datenblatt (wie meistens) aber aus (was für den Anwender aber auch egal
ist).
> Es gibt ein ODR Register, das durch Zugriff auf verschiedene Adressen> auf verschiedene Art manipuliert wird. BSRR ist eine dieser> Funktionsadressen.Nachmacher schrieb:> ... was widerum bedeutet, daß BS0 in BSRR gesetzt ist). Das ergibt laut> meinem Datenblatt, daß über das ODR der Pin 0 des Port E auf 1 gesetzt wird.
Sag ich doch ...
> Ein Schreibzugriff auf BSRR schreibt also nicht ins "Register" BSRR,> sondern ins ODR, nach den für den Zuriffspfad BSRR geltenden Regeln.
Laut Datenblatt schreibt man in ein Register, s.o..
Sei ehrlich, Du versuchst, Dich da irgendwie rauszuwinden ...
Ist doch nur menschlich; macht doch nichts ...
(obwohl man gelegentlich auch mal seine Fehler eingestehen sollte, und
da ist sowas banales doch eigentlich eine gute Gelegenheit).
Ist echt nicht böse gemeint, Du gibst ja immer gute Antworten hier!
Nachmacher schrieb:> Laut Datenblatt schreibt man in ein Register, s.o..
Tut man, wir sind ja nur unterschiedlicher Ansicht darüber, in welches.
Ich sehe bei sowas automatisch die Hardware dahinter, ich bin so
verdrahtet.
> Das Datenblatt hat immer Recht.
Ich fahre insgesamt ganz gut damit, mich eher an das Verständnis von
Vorgängen als ans Runterbeten von Herstellersprüchen zu halten. Nicht
zuletzt auch beruflich. Führt dazu, dass ich mir die Freiheit rausnehme,
Herstellern und ihren Verkäufern gerne mal zu widersprechen, wenn ich
anderer Ansicht bin.
> Sei ehrlich, Du versuchst, Dich da irgendwie rauszuwinden ...
Nö. War von Anfang an exakt so gemeint wie eben beschrieben. Ehrlich.
Für mich existiert kein Register BSRR, auch wenn sich ST auf den Kopf
stellt und mit den Zehen wackelt. ;-)
> (obwohl man gelegentlich auch mal seine Fehler eingestehen sollte, und
Habe ich selten ein Problem damit. Ich sehe freilich weder bei dir noch
bei mir einen Fehler, nur verschiedene Perspektiven.
A. K. schrieb:>> Das Datenblatt hat immer Recht.>> Ich fahre insgesamt ganz gut damit, mich eher an das Verständnis von> Vorgängen als ans Runterbeten von Herstellersprüchen zu halten. Nicht> zuletzt auch beruflich. Führt dazu, dass ich mir die Freiheit rausnehme,> Herstellern und ihren Verkäufern gerne mal zu widersprechen.
Hatte ich doch auch ironisch gemeint. Man kann bzw. muß sich am
Datenblatt entlang hangeln, aber mitdenken sollte man schon. Den
Schreibern passieren nämlich u.a. copy&paste-Fehler ungefähr genau so
häufig wie, sagen wir einfach mal, anderen auch ...
A. K. schrieb:> Aber wir können uns ja notfalls auf den Begriff eines virtuellen> Registers einigen ;-).
Abgemacht.