Forum: Mikrocontroller und Digitale Elektronik STM32 Pin-Toogle!


von Dennis X. (Gast)


Lesenswert?

Hallo Ihr,

hab es soeben mit einem Code zu tun, wo ich es am besten so haben 
möchte, dass eine LED getoogelt wird. Nun hab ich in der StdLib 
geschaut, aber ich kann dort nur ein Bit setzen oder rücksetzen. Wie geh 
ich nun am besten vor?

Hab es dann so versucht, dass ich zuerst auslese und es dann einfach von 
eins subtrahiere.
1
GPIO_WriteBit(GPIOA, GPIO_Pin_2, (BitAction)((1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2))));

Habt Ihr eine andere Idee wie man das elegant lösen könnte? 
Funktionieren tut das jedoch ;-)

Dennis

von Toggle (Gast)


Lesenswert?

In dem Fall wäre wohl eine Zustandsvariable angebracht...
Erspart das Auslesen.

von tip (Gast)


Lesenswert?

Grundsätzlich würde ich von den Funktionen zur Bitmanipulation Abstand 
nehmen und direkte Registerzugriffe nutzen. Also Beispielsweise so:


Setzen:
GPIOA->BSRR = GPIO_Pin_2;

Rücksetzen:
GPIOA->BRR = GPIO_Pin_2;

Vorteil: Wesentlich (Vielfaches) schneller als die Funktionen in deinem 
Beispiel und meines Erachtens genausogut/besser lesbar.

Zusätzlich kannst du noch eine Zustandsvariable einführen um dann zu 
togglen.

von Dennis X. (Gast)


Lesenswert?

Also wäre dann das Führen einer Variable schneller als über die 
Funktionen?
Hmm werde dann mal den Code nach den Tipps von tip ändern.

von tip (Gast)


Lesenswert?

Hast du ein Oszi? Dann kannst du ja mal ausmessen wie lange ein toggle 
braucht.

von Roland H. (batchman)


Lesenswert?

> Habt Ihr eine andere Idee wie man das elegant lösen könnte?
> Funktionieren tut das jedoch ;-)

Via "Register direkt". Variable würde ich mir sparen, welche 
Toggle-Frequenz ist angestrebt?

Einfach mal machen und messen - Register direkt mit/ohne Variable.

tip schrieb:
> Setzen:
> GPIOA->BSRR = GPIO_Pin_2;
>
> Rücksetzen:
> GPIOA->BRR = GPIO_Pin_2;

Welcher stm32 bzw. welche "std periph lib"-Version ist das?

Sieht nach stm32f1 aus, m. W. geht das so nicht mit stm32f4.

Die Konstanten für die Bits im BSSR heißen beim stm32f4 übrigens 
GPIO_BSRR_BS_* und GPIO_BSRR_BR_* - das GPIO_Pin_* kommt aus 
stm32f4xx_gpio.h. Das ist letztlich dasselbe, aber dann wird "Register 
direkt" und "lib" munter durcheinandergewürfelt.

von tip (Gast)


Lesenswert?

Hi Roland,

das Beispiel von mir ist für den stm32F1. Ich weiß ja nicht welchen µC 
der Dennis benutzt.

Ich bin jedoch der Meinung, dass man sich diese Lib-Funktionsaufrufe gar 
nicht erst angewöhnen sollte. Früher oder später kommt dann nämlich der 
Zeitpunkt, wo man merkt, dass das ein x-faches an Zeit in Anspruch 
nimmt. Bei mir war es, als ich eine schnelle Soft-SPI machen wollte.

Mit direktem Registerzugriff meinte ich einen Zugriff, der so direkt 
ist, dass er die minimal mögliche Zeit in Anspruch nimmt. Also nicht 
erst über eine Funktion, welche dann aufgerufen werden muss und die auch 
noch "Bremsen" eingebaut hat. Was für Bremsen das sind, kann man sich ja 
angucken.

lg
tip

von Dennis P. (dennisp)


Lesenswert?

DeinPORT->ODR ^= GPIO_PIN_xx;

von Dennis X. (Gast)


Lesenswert?

Also ich benutze den STM32F103 hab aber im nächsten Projekt auch einen 
415er. Der ist nur um allgemein ein bisschen in die ARM-Welt zu finden.
Wenn ich mal Zeit finde werde ich das mit dem Toogle nachprüfen, lad die 
Ergebnise natürlich hier hoch!

Dennis

von (prx) A. K. (prx)


Lesenswert?

Dennis P. schrieb:

> DeinPORT->ODR ^= GPIO_PIN_xx;

Kann man so machen. Das sollte man aber nur so machen, wenn kein 
einziges Bit dieses Port in einem Interrupt-Handler verändert wird. 
Sicherer ist beispielsweise:

DeinPORT->BSRR = (DeinPORT->ODR ^ GPIO_PIN_xx) | (GPIO_PIN_xx << 16);

von Dennis X. (Gast)


Lesenswert?

A. K. schrieb:
> DeinPORT->BSRR = (DeinPORT->ODR ^ GPIO_PIN_xx) | (GPIO_PIN_xx << 16);

Das wäre dann quasi die perfekte Lösung, wenn ich das richtig verstanden 
habe.

von tip (Gast)


Lesenswert?

> DeinPORT->BSRR = (DeinPORT->ODR ^ GPIO_PIN_xx) | (GPIO_PIN_xx << 16);

Blöde Frage: Über das BSRR-Register kann doch nur gesetzt werden und 
nicht rückgesetzt werden. Korrigier mich wenn ich falsch liege.

lg
tip

von Dennis X. (Gast)


Lesenswert?

tip schrieb:
>> DeinPORT->BSRR = (DeinPORT->ODR ^ GPIO_PIN_xx) | (GPIO_PIN_xx << 16);
>
> Blöde Frage: Über das BSRR-Register kann doch nur gesetzt werden und
> nicht rückgesetzt werden. Korrigier mich wenn ich falsch liege.
>
> lg
> tip

Joa hätt ich jetzt auch gesagt ;-)
1
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
2
{
3
  /* Check the parameters */
4
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
5
  assert_param(IS_GPIO_PIN(GPIO_Pin));
6
  
7
  GPIOx->BSRR = GPIO_Pin;
8
}
9
10
/**
11
  * @brief  Clears the selected data port bits.
12
  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
13
  * @param  GPIO_Pin: specifies the port bits to be written.
14
  *   This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
15
  * @retval None
16
  */
17
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
18
{
19
  /* Check the parameters */
20
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
21
  assert_param(IS_GPIO_PIN(GPIO_Pin));
22
  
23
  GPIOx->BRR = GPIO_Pin;
24
}

von holger (Gast)


Lesenswert?

>Blöde Frage: Über das BSRR-Register kann doch nur gesetzt werden und
>nicht rückgesetzt werden. Korrigier mich wenn ich falsch liege.

Dann schau besser noch mal ins Datenblatt.

von (prx) A. K. (prx)


Lesenswert?

tip schrieb:

> Blöde Frage: Über das BSRR-Register kann doch nur gesetzt werden und
> nicht rückgesetzt werden. Korrigier mich wenn ich falsch liege.

Was meinste warum das "Bit Set/Reset Register" heisst?

Der Charme dieses recht clever gestalteten Registers liegt darin, dass 
man über dessen obere Hälfte definieren kann, welche Bits überhaupt 
verändert werden sollen (der "Reset" Teil), und über die untere Hälfte, 
auf welchen Wert (der "Set" Teil).

von tip (Gast)


Lesenswert?

Danke für den Hinweis! Wieder was dazugelernt.

von Dennis X. (Gast)


Lesenswert?

Warum werden dann aber oben in dem Stück Lib. was ich gepostet hab zwei 
verschiedene angesprochen?!

von tip (Gast)


Lesenswert?

> Warum werden dann aber oben in dem Stück Lib. was ich gepostet hab zwei
> verschiedene angesprochen?!

Die Frage stelle ich mir auch grade und komme sogleich zur Nächsten:

Wozu gibt es überhaupt das BRR-Register, wenn ich doch mit dem BSRR 
-Register auskommen würde?

Oder anders formuliert: Was kann das BRR-Register, was das BSRR-Register 
nicht kann?

lg
tip

von (prx) A. K. (prx)


Lesenswert?

Dennis X. schrieb:

> Warum werden dann aber oben in dem Stück Lib. was ich gepostet hab zwei
> verschiedene angesprochen?!

Weil es beide Register gibt. ;-)

von (prx) A. K. (prx)


Lesenswert?

tip schrieb:

> Oder anders formuliert: Was kann das BRR-Register, was das BSRR-Register
> nicht kann?

Nichts, nur eben rechts statt links. Für Details fragt STM.

von tip (Gast)


Lesenswert?

@ A.K

Danke für die Antwort! Kam mir nur ein bischen komisch vor. Man baut 
doch nicht aus Spaß ein nutzloses zusätzliches Register ein? ^^

von Roland H. (batchman)


Lesenswert?

tip schrieb:
> das Beispiel von mir ist für den stm32F1. Ich weiß ja nicht welchen µC
> der Dennis benutzt.

Ich wollte nur darauf hinweisen, dass es da Unterschiede zwischen den 
stm32-Familien gibt.

stm32f1xx: BRR/BSRR, ebenso in stm32f1xx.h
stm32f4xx: Nur BSRR, aufgeteilt in BSRRL und BSRRH in stm32f4xx.h

> Ich bin jedoch der Meinung, dass man sich diese Lib-Funktionsaufrufe gar
> nicht erst angewöhnen sollte. Früher oder später kommt dann nämlich der
> Zeitpunkt, wo man merkt, dass das ein x-faches an Zeit in Anspruch
> nimmt.

Nee, lass mal stecken, nicht schon wieder ;-)
Bei GPIO ist es m. E. allerdings eindeutig "pro Register".

tip schrieb:
> Man baut
> doch nicht aus Spaß ein nutzloses zusätzliches Register ein?

Sonst hätten wir doch nichts zum diskutieren und spekulieren :-)

Vielleicht hatten die bei STM mal große Pläne, die Ports mit 32 Pins zu 
bestücken (die LPCs machen das so), würde ja auch zum µC passen. Und wg. 
der Pin-Abwärtskompatibilität haben sie es wieder fallen gelassen, beim 
stm32f4 gibt das Ding nicht mehr. Ist aber reine Spekulation.

von Eddy C. (chrisi)


Lesenswert?

A. K. schrieb:
> Sicherer ist beispielsweise:
> DeinPORT->BSRR = (DeinPORT->ODR ^ GPIO_PIN_xx) | (GPIO_PIN_xx << 16);

Sorry für's wiederbeleben :-)

Die obige Anweisung ist pfiffig, danke für die Inspiration. Sie ist aber 
weiterhin nicht Interrupt-save, weil unbetroffene GPIOs ebenfalls 
nochmals explizit gesetzt werden. Ein Interrupt, der zwischen dem Lesen 
von ODR und Schreiben von BSSR zuschlägt, kann zu unerwünschtem 
Verhalten führen.

Eine verbesserte Version erfordert eine zusätzliche UND-Verknüpfung.

DeinPORT->BSRR = ((DeinPORT->ODR ^ GPIO_PIN_xx) & GPIO_PIN_xx) | 
(GPIO_PIN_xx << 16);

BitSet hat gegenüber BitReset eine höhere Priorität, womit man sich ein 
paar Operationen spart.

von batuu (Gast)


Lesenswert?

Eddy Current schrieb:
> BitSet hat gegenüber BitReset eine höhere Priorität, womit man sich ein
> paar Operationen spart.

Ausprobiert, oder steht das irgendwo in einem offiziellen Dokument?

von Uwe Bonnes (Gast)


Lesenswert?

batuu schrieb:
> Ausprobiert, oder steht das irgendwo in einem offiziellen Dokument?

rm0008.pdf, Seite 168.

von batuu (Gast)


Lesenswert?

Uwe Bonnes schrieb:
> batuu schrieb:
>> Ausprobiert, oder steht das irgendwo in einem offiziellen Dokument?
>
> rm0008.pdf, Seite 168.

Danke,
war mir entgangen ...

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.