Forum: Mikrocontroller und Digitale Elektronik STM32F103 Timer


von Mathias D. (darkfirefighter)


Lesenswert?

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:
1
Ausgabe -> warte auf Timer -> Ausgabe -> warte auf Timer -> Ausgabe -> usw.

Umgesetzt habe ich das folgendermaßen:
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.

Meine Timer Register sehen so aus:
1
PSC = 0
2
ARR = 1
3
CR1 = 0
4
CR2 = 0
5
SMCR = 0
6
CCMR1 = 0
7
CCMR2 = 0
8
CCER = 0
9
CCR1-4 = 0
10
DIER = 0

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

von Nachmacher (Gast)


Lesenswert?

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

von Mathias D. (darkfirefighter)


Lesenswert?

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

von Nachmacher (Gast)


Lesenswert?

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.

von Mathias D. (darkfirefighter)


Lesenswert?

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.

von Mathias D. (darkfirefighter)


Lesenswert?

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ß

von (prx) A. K. (prx)


Lesenswert?

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.

von Nachmacher (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

Nachmacher schrieb:

> Das Gleichheitszeichen setzt das Register BSRR auf den Wert von data[0].

Nein. Doku lesen.

von Nachmacher (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Nachmacher (Gast)


Lesenswert?

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?

von (prx) A. K. (prx)


Lesenswert?

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.

von Nachmacher (Gast)


Lesenswert?

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!

von (prx) A. K. (prx)


Lesenswert?

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.

von Nachmacher (Gast)


Lesenswert?

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.

von Nachmacher (Gast)


Lesenswert?

P.S.: Immer dieses nachträgliche rumeditiere ...

von (prx) A. K. (prx)


Lesenswert?

Yep, das ist ein notorischer Fehler von mir. ;-)

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.