STM32F4 Alternate Port Functions

Gast #3929273
Lesenswert?

Hallo Leute,

ich wollte mal wieder den UART am STm32F407 in Betrieb nehmen.
Das ganze funktioniert auch.
Ich verwende (für diese einfachen Dinge) keine Treiber, da ich denke, 
dass eine 5 zeilige UART-Initialisierung auch noch mit puren Registern 
erfolgen kann, ohne dass es einem über dsen Kopf wächst :D

Aber nun zu meiner Frage:

Um die Alternate Port functions nutzen zu können muss ich im 
GPIOx->MODER Register die Alternate Function aktivieren. Habe bemerkt, 
dss dies nur mit bereits eingeschalteter GPIO-Clock geht. Ebenfall habe 
ich bemerkt, dass ich die GPIO-Clock einige Takte früher initialisieren 
muss, als das MODER-Register.

Schreibe ich:
1
RCC->AHB1ENR |= RCC_AHB1_ENR_GPIODEN;
2
GPIOD->MODER = 0x12345678; //Beispiel Wert
spo klappt das ganze nicht. Das MODER bleibt auf 0.
Erst wenn eine delay eingefügt wird
1
RCC->AHB1ENR |= RCC_AHB1_ENR_GPIODEN;
2
wait(); //Verzögert um einige takte...
3
GPIOD->MODER = 0x12345678; //Beispiel Wert
funktioniert es.

Hat jemand einen Tipp für mich, wie ich es lösen kann, dass ich die 
Clock einschalte und dann das MODER setze, ohne übermäßg viel Zeit zu 
warten?
Eventuell:
1
RCC->AHB1ENR |= RCC_AHB1_ENR_GPIODEN;
2
while(GPIOD->MODER != 0x12345678)
3
{
4
GPIOD->MODER = 0x12345678;
5
}
???

Vielen Dank...
#3929335
Lesenswert?

In diesem Thread hier (Beitrag "C++ Exceptions mit gcc-arm-none-eabi") 
hatte ich das gleiche Problem und habe ewig gebraucht dies 
festzustellen. Am Ende habe ich herausgefunden, dass es zwei Takte nach 
dem Einschalten der Clock dauert bis die Peripherie aktiv ist. Leider 
konnte ich dazu auch keine Informationen im Datenblatt finden. Man ist 
hier leider auch der Willkür des Compilers ausgeliefert, da man nicht so 
einfach beeinflussen kann wie die generierten Instructions nacher 
angeordnet sind. Möglicherweise braucht man hier auch eine Memory 
Barrier (einfügen einer DMB instruction über __dmb()) zwischen den 
beiden Zeilen damit der Compiler die Zugriffe nicht zu schnell 
hintereinander durchführt. Wobei ich auch hier keine Hinweise im 
Datenblatt gefunden habe, nur das es bei mir mit __dmb(); Aufruf 
funktioniert. Mich würde daher auch interessieren was denn nun die 
tatsächlich beste und richtige Lösung ist.
#3929366
Lesenswert?

adenin schrieb:
> Wenn Du das Zeug nicht schon vorher aktivierst, dann kannst Du ja
> die
> Berechnung des Teilers für die Baudrate als sinnvollen Zeitvertreib
> zwischenschieben.

Bis der Compiler auf die Idee kommt das doch wieder umzuordnen, sodass 
die Berechnung davor oder danach stattfindet. Ich habe gerade doch etwas 
gefunden. Scheinbar handelt es sich um einen Fehler der im Errata sheet 
beschrieben ist 
(http://www.st.com/st-web-ui/static/active/en/resource/technical/document/errata_sheet/DM00037591.pdf). 
Dort der Absatz "2.1.13
Delay after an RCC peripheral clock enabling". Als Workarround werden 
eine bestimmte Anzahl NOPs oder eine DSB memory barrier empfohlen.
Gast #3929380
Lesenswert?

Ok. Vielen Dank.


Werde mir DSB/DMB (noch keine Ahnung => Mal die Assemblerefehle 
anschauen) zu Gemüte führen.

adenin schrieb:
> Wenn Du das Zeug nicht schon vorher aktivierst, dann kannst Du ja die
> Berechnung des Teilers für die Baudrate als sinnvollen Zeitvertreib
> zwischenschieben.

Naja. die Buad hab ich händisch ausgerechnet und einfach den Wert 0x1117 
für 9600 Baud bei 42MHz Pheripherie-Clock. das ist nur eine Zuweisung.
Das Problem daran ist, dass wahrscheinlich die Clock vom U(S)ART 
ebenfalls erst eingeschaltet werden muss, um das register zu schreiben. 
Hab ds noch nicht versucht. Ist das Problem hier ebenfalls vorhanden?
Bzw:
1. Muss die Clock für den U(S)ART aktiviert sein, um die Register zu 
beschreiben?

2. Gibt es hier auch dieses Delay von ein paar Takten? Ich denka ja, 
weil das ja auch erst durch die Bus-Struktur, die ja deutlich langsamer 
getaktet ist als der Kern, muss.
Gast #3929396
Lesenswert?

M. H. schrieb:
> Naja. die Buad hab ich händisch ausgerechnet und einfach den Wert 0x1117
> für 9600 Baud bei 42MHz Pheripherie-Clock. das ist nur eine Zuweisung.
> Das Problem daran ist, dass wahrscheinlich die Clock vom U(S)ART
> ebenfalls erst eingeschaltet werden muss, um das register zu schreiben.
> Hab ds noch nicht versucht. Ist das Problem hier ebenfalls vorhanden?

Ja, das Problem ist hier natürlich auch vorhanden.
Aber ich las das berechenen aus der aktuellen Clock für die USART und 
als Parameter die Baudrate. Da brauch ich mich nicht um selbst um die 
Bautrate kümmern, und die ist dann immer richtig, auch wenn ich bei der 
vergabet der Frequenzen irgendwelchen Mist gemacht habe.
Ist gut fürs debuggen, wenn die CPU sich trotzdem immer meldet. ;)
Gast #3929406
Lesenswert?

Kann mir jemand den Unterschied zwischen DMB und DSB erklären?
1. DMB

DMB acts as a data memory barrier. It ensures
that all explicit memory accesses that
appear, in program order, before the DMB instruction are completed 
before any explicit
memory accesses that appear, in program orde
r, after the DMB instruction. DMB does not
affect the ordering or execution of in
structions that do not access memory.

2. DSB

DSB acts as a special data synchronization memory barrier. Instructions 
that come after the
DSB, in program order, do not execute until the DSB instruction 
completes. The DSB
instruction completes
when all explicit memory a
ccesses before
it complete.
Condition flags
This instruction does not change the flags.
#3929444
Lesenswert?

Ja oder so ähnlich. Wenn ich es richtig verstehe, dann warten beide 
Befehle bis alle Speicherzugriffe vor diesem Befehl abgeschlossen sind. 
Allerdings darf die Ausführung bei DMB schon früher weiter gehen wenn 
keine Speicherzugriffe damit verbunden sind. Diese Definitionen sind 
teilweise ziemlich spitzfindig und man muss sie sehr genau lesen. DSB 
scheint auf jeden Fall strenger zu sein als DMB. Wobei ich in diesem 
Fall eigentlich sagen würde, dass ein DMB ausreichen sollte aber wenn ST 
ein DSB empfiehlt hat das vermutlich seinen Grund.
Gast #3929470
Lesenswert?

Hallo. Ich habe da noch ein ähnliches Problem:

Wenn ich eine Interruptroutine habe, und das Interrupt Flag erst am ende 
lösche, wird die Interruptroutine dannach erneut ausgeführt. Ich muss 
auch hier mehrere takte warten bzw. das Flag am Am Anfang der Routine 
löschen.

Hat das auch damit zu tun?
#3929555
Lesenswert?

Richtig heißt die Funktion nach dem CMSIS Standard: __DSB();
Wobei die CMSIS Variante dem __asm__("dsb") vorzuziehen ist, da man bei 
der CMSIS Version davon ausgehen kann, dass die korrekten Hinweise für 
den Compiler da sind damit die memory barrier an genau der genannten 
Stelle hinzugefügt wird und nicht wegoptimiert oder umsortiert wird.
Gast #3929605
Lesenswert?

Sebastian V. O. schrieb:
> Laut dieser Quelle
> 
(http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHDGBJG.html)
> sind die Zugriffe auf die NVIC Register zumindest mit einer impliziten
> DMB memory barrier versehen. Möglicherweise reicht dies aber nicht aus
> und sorgt für das von dir beobachtete Verhalten.

Die Interrupt Flags liegen nicht in den NVIC-Registern. das sind 
Peripherie Register. Und dieses Falg löst dann im NVIC erst die Reaktion 
aus. Die NVIC Flags löschen sich ja auch selbst bei der Annahme eines 
Interrupts. Nur die Flags des Peripheriemoduls muss man selbst löschen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren