Hallo Zusammen,
ich wollte mich mal mit den relativ neuen STM32G0xx MCUs befassen und
ein kleines Test Projekt erstellen. Nun habe ich aber das Problem, dass
ich die Clock nicht zum laufen kriege. Ich verwende einen STM32G031F8P6.
In meinem Code möchte ich den internen Oszillator aktivieren und mit PLL
eine SysCLK von 64MHz einstellen, welche ich dann auch auf dem AHB und
APB Bus haben möchte.
Meine Clock Init funktion sieht wie folgt aus:
Im main.h befinden sich die Headerfiles für die Registernamen:
1
#ifndef MAIN_H_
2
#define MAIN_H_
3
4
#include<stdio.h>
5
#include<stdint.h>
6
7
#include"stm32g0xx.h"
8
9
#include"systick.h"
10
11
#endif /* MAIN_H_ */
Nun ist das Problem, dass das natürlich die Clock nicht läuft, aber auch
das beim Debuggen das Programm ab dieser Zeile abstürtzt mit der
Fehlermeldung "Failed to read registers from target" :
Habe ich im Ablauf einen Fehler oder habe ich noch ein Register
vergessen?
Den korrekten Ablauf habe ich leider nirgends gefunden, sondern habe
versucht, diesen vom Generierten Code des CubeMx zu übernehmen.
STK500-Besitzer schrieb:> STM32CubeMX verwenden.> Da kann man sich auch die Clock-Konfiguration optisch darstellen lassen.
Ich versuche ja den generierten Code zu übernehmen. Das Problem ist, ich
kann die HAL-Library nicht verwenden, da ich zu wenig Speicher auf
diesem kleinen Kontroller habe. Aus diesem Grund möchte ich die Register
direkt ansteuern, da der Code so massiv viel kleiner ist.
Moot S. schrieb:> Aus diesem Grund möchte ich die Register> direkt ansteuern, da der Code so massiv viel kleiner ist.
Dann wirst du wohl die HAL-Funktionen analysieren müssen.
Bzw. das analysieren müssen, was CubeMX ausspuckt.
... und ich bin raus.
Moot S. schrieb:> Das Problem ist, ich> kann die HAL-Library nicht verwenden, da ich zu wenig Speicher auf> diesem kleinen Kontroller habe.
Das gilt mit Sicherheit nicht für die Clock-Configuration.
Auch ansonsten ist HAL nicht so speicherhungrig, wie immer wieder
behauptet.
Mit den LL-HAL-Funktionen wirds dann nochmal deutlich schlanker.
Mir scheint aber, daß du noch (als Anfänger) ganz andere Probleme hast.
Fang mit HAL an!
Optimieren kann man immer noch. (wenn man weis, was man tut)
Die diversen Ausgänge der PLL müssen bei Bedarf einzeln eingeschaltet
werden, hier wohl PLLREN. Ich würde es in Zeile 49 machen, aber evt.
muss es schon in 46 passieren.
Unabhängig davon:
Die Kommentare/#define zu PLLQ und PLLM passen nicht zum Code.
Mit den |= Anweisungen verlässt du dich drauf, dass die Register 0 sind.
Das stimmt selbst nach einem Reset nicht unbedingt, aber das scheint
hier zu passen. Um Bytes zu sparen könntest du konsequenterweise
PWR_CR1_VOS und RCC_CR_HSION weg lassen, das sollte der Power On Default
sein.
Harry L. schrieb:> Mir scheint aber, daß du noch (als Anfänger) ganz andere Probleme hast.> Fang mit HAL an!> Optimieren kann man immer noch. (wenn man weis, was man tut)
Warum wird in diesem Forum eigentlich einem das Lernen verweigert...
Ich will ja verstehen, wie man die Clock einstellt. Im CubeMx ein paar
Settings in einem GUI setzten und dann auf Generieren klicken bringt
mich nicht weiter. Wegen dem verstehe ich trozdem nicht wie man das
Register setzten muss.
STK500-Besitzer schrieb:> Dann wirst du wohl die HAL-Funktionen analysieren müssen.> Bzw. das analysieren müssen, was CubeMX ausspuckt.> ... und ich bin raus.
Das habe ich ja versucht, nur enden die Register zuweisungen in der
HAL-Library in (Übertrieben gesagt) Kryptischen Macros die
wahrscheinlich ein Bit setzten oder löschen
Bauform B. schrieb:> Die diversen Ausgänge der PLL müssen bei Bedarf einzeln eingeschaltet> werden, hier wohl PLLREN. Ich würde es in Zeile 49 machen, aber evt.> muss es schon in 46 passieren.
Aber im Datenblatt steht, man soll PLLR nicht aktivieren, wenn man die
PLL als System Clock verwenden will, was ich ja in meinem Fall möchte.
Bauform B. schrieb:> Die Kommentare/#define zu PLLQ und PLLM passen nicht zum Code.
Sind leichen von einem vorherigen versuch. Schon gelöscht :)
Bauform B. schrieb:> Mit den |= Anweisungen verlässt du dich drauf, dass die Register 0 sind.> Das stimmt selbst nach einem Reset nicht unbedingt, aber das scheint> hier zu passen.
In wie fern kann dies ein Problem sein? mit |= setzte ich es auf 1 wenn
es 0 wäre und wenn es dann schon 1 ist bleibt es doch einfach 1?
pegel schrieb:> Oder die LL Funktionen nutzen.
Wäre grundsätzlich auch eine Möglichkeit, aber ich möchte mich mit der
Registeransteuerung befassen und es verstehen.
Das ist doch Prima.
Mit F3 bei markierter Funktion kannst Du auf Register oder sogar auf
deren Adressen abtauchen. Es gibt am Ende nur Wert ändern oder setzen.
Oder mit der Doku arbeiten ist auch möglich.
Du kannst auch alles mischen.
Dann ist nur der Rahmen von CubeMX vorgegeben.
Moot S. schrieb:> Ich will ja verstehen, wie man die Clock einstellt.
Dann schau dir den Clock Tree im Datenblatt an und setz die paar Bits in
den Registern direkt.
pegel schrieb:> Du kannst auch alles mischen.> Dann ist nur der Rahmen von CubeMX vorgegeben.
Grundsätzlich ist mein Problem nicht, dass ich nicht weiss wie ich ein
Register setzten muss, sondern das ich zu diesem speziellen Kontroller
diese Infos (Reihenfolge und welche Register) nicht finde.
Der G0 basiert ja auf dem Arm Cortex M0+. Wenn ich jetzt aber nach
anderen M0+ suche wie sie z.B. auch in der L0 oder L5 Reihe von ST
eingesetzt werden, stimmen die Register nicht überein. Z.B. gibt es bei
den anderen M0+ im FLASH Register ein Data Cache Ready bit welches es
hier beim G0 einfach nicht gibt, dafür muss man ein Debug Enable bit
setzten, von dem ich nirgendwo lesen konnte wozu es das braucht (Auch
wenn der Name sehr eindeutig ist), wäre doch gut zu wissen wozu das ist.
Cyblord -. schrieb:> Dann schau dir den Clock Tree im Datenblatt an und setz die paar Bits in> den Registern direkt.
Übersehe ich hier was? Ich finde weder im Datenblatt noch spezifisch im
Clock Tree irgend eine Info in welcher Reihenfolge diese Register
gesetzt werden müssen. Ich habe das Referenzdatenblatt mal in den Anhang
gelegt, falls sich das jemand anschauen möchte.
Z.B. oben aus dem Listing:
//LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
//wird zu:
FLASH->ACR |= (FLASH_ACR_LATENCY & LL_FLASH_LATENCY_2);
spart schon 28byte.
Moot S. schrieb:> Bauform B. schrieb:>> Mit den |= Anweisungen verlässt du dich drauf, dass die Register 0 sind.>> Das stimmt selbst nach einem Reset nicht unbedingt, aber das scheint>> hier zu passen.> In wie fern kann dies ein Problem sein? mit |= setzte ich es auf 1 wenn> es 0 wäre und wenn es dann schon 1 ist bleibt es doch einfach 1?
Lustig wird das bei den Mehrbit-Feldern, steht da z. B. 01 drin, man
möchte aber 10 haben, liefert das "|" aber 11 ...
Statt
RCC->CFGR |= RCC_CFGR_SW_1;
while((RCC->CFGR & RCC_CFGR_SWS_1) != RCC_CFGR_SWS_1);
sollte man daher besser
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW_Msk) | RCC_CFGR_SW_1;
while((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1);
schreiben. Dafür sind die ..._Msk gerade da.
Moot S. schrieb:> Der G0 basiert ja auf dem Arm Cortex M0+.
Mag sein, aber der Teil den du gerade programmieren willst befindet sich
außerhalb des ARM Kerns. Alle Infos dazu müssen im Referenzhandbuch
stehen.
https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
Lies dir das ganze Kapitel 5 zweimal durch.
Und du brauchst die LATENCY Bits im FLASH->ACR Register aus Kapitel 3.7.
Drucke dir das Diagramm "Figure 10. Clock tree" aus.
Benutze Cube MX, um die möglichen Einstellungen durch zu spielen. Cube
MX zeigt dir rot an, wenn du eine nicht funktionierende Kombination
hast. Das heißt ja nicht, dass du die HAL samt generiertem Code benutzen
musst. Mache ich auch nicht.
Bei ST ist das leider so, dass man sich die relevanten Infos mühsam
zusammen suchen muss. Die Firma fügt viel weniger Querverweise und
Code-Beispiele ein als Atmel es für die AVR Modelle tat.
Bei manchen Änderungen muss du warten, biss sie vollständig aktiviert
sind. Die PLL braucht z.B. Zeit um sich ein zu schwingen. Erst danach
kann man sie als Taktquelle verwenden. Außerdem kann man die PLL nicht
umkonfigurieren, während sie die CPU antreibt.
Von meinem Beispielcode auf
http://stefanfrings.de/stm32/stm32l0.html#takt kannst du sicher etwas
übernehmen, insbesondere die Reihenfolge der Schritte. Lies die
Kommentare in den gelben Kästchen. Die Register sind anders, aber ich
bin sicher dass die Vorgehensweise auch bei deinem Mikrocontroller
prinzipiell gleich ist.
Moot S. schrieb:> Warum wird in diesem Forum eigentlich einem das Lernen verweigert...
Das passiert doch nicht absichtlich, aber wer als einziges Werkzeug
einen Baseballschläger hat, für den sieht jedes Problem aus wie ein
Robbenbaby
> Bauform B. schrieb:>> Die diversen Ausgänge der PLL müssen bei Bedarf einzeln eingeschaltet>> werden, hier wohl PLLREN. Ich würde es in Zeile 49 machen, aber evt.>> muss es schon in 46 passieren.>> Aber im Datenblatt steht, man soll PLLR nicht aktivieren, wenn man die> PLL als System Clock verwenden will, was ich ja in meinem Fall möchte.
Das scheint mir ein Missverständnis zu sein. Wie sonst soll der PLL-Takt
zur CPU kommen? Ich finde, das ist im Clock Tree eindeutig
eingezeichnet.
RM0444 schreibt
1
5.2.4
2
5. Enable the desired PLL outputs by configuring PLLPEN, PLLQEN,
3
and PLLREN in PLL configuration register (RCC_PLLCFGR).
4
The enable bit of each PLL output clock (PLLPEN, PLLQEN, and PLLREN)
5
can be modified at any time without stopping the PLL. PLLREN cannot
6
be cleared if PLLRCLK is used as system clock.
7
8
5.4.4
9
This bit cannot be written when PLLRCLK output of the PLL is
10
selected for system clock.
In 5.2.4 steht "cannot be cleared", in 5.4.4 "cannot be written". Das
ist aber technisch das gleiche, ohne Takt kann ich kann das Bit nun mal
nicht setzen (sobald ich den abgeschalteten PLLRCLK als SYSCLK wähle,
ist sowieso alles zu spät). Also bleibt praktisch nur clear. "cannot"
(im Gegensatz zu "must not") verstehe ich so, dass man es gerne
probieren darf, aber es geht einfach nicht, die Hardware verhindert es.
Moot S. schrieb:> bersehe ich hier was? Ich finde weder im Datenblatt noch spezifisch im> Clock Tree irgend eine Info in welcher Reihenfolge diese Register> gesetzt werden müssen.
Die Reihenfolge ist nicht in jedem Detail mega kritsch.
Es sollte ja klar sein, dass man Taktquellen erst mal aktiviert, bevor
man sie als Quelle selektiert. Ansonsten gehe ich im Clocktree immer von
der Quelle zum Ziel. Und das klappt auch gut.
Stefan ⛄ F. schrieb:> Lies dir das ganze Kapitel 5 zweimal durch.> Und du brauchst die LATENCY Bits im FLASH->ACR Register aus Kapitel 3.7.>> Drucke dir das Diagramm "Figure 10. Clock tree" aus.>> Benutze Cube MX, um die möglichen Einstellungen durch zu spielen. Cube> MX zeigt dir rot an, wenn du eine nicht funktionierende Kombination> hast. Das heißt ja nicht, dass du die HAL samt generiertem Code benutzen> musst. Mache ich auch nicht.
Ja bin jetzt so vorgegangen und denke es läuft jetzt. Werde es noch
prüfen und dann den Code posten.
Bauform B. schrieb:> Das scheint mir ein Missverständnis zu sein. Wie sonst soll der PLL-Takt> zur CPU kommen?
Ja hab ich mich auch schon gefragt :D
Cyblord -. schrieb:> Es sollte ja klar sein, dass man Taktquellen erst mal aktiviert, bevor> man sie als Quelle selektiert. Ansonsten gehe ich im Clocktree immer von> der Quelle zum Ziel. Und das klappt auch gut.
Ja eigentlich ging ich davon aus, dass man zuerst alles einstellt bevor
man es auswählt. Aber ja etwas neues dazu gelernt.
Markus M. schrieb:> Hier ist mein getesteter Code aus einem Projekt:
Werde ich mal mit meinem Code vergleichen.
sparfux schrieb:> Nicht besonders schoen, aber besonders sparsam.
das spart zwar kein einiges Byte Flash, aber der Quelltext ist schön
kompakt. Bei den aktuellen Festplattenpreisen durchaus ein Vorteil. Aber
was bedeutet RCC_CFGR? Sollte da nicht eine Adresse stehen?
Moot S. schrieb:> Warum wird in diesem Forum eigentlich einem das Lernen verweigert...
Ach nö, es sind bloß diejenigen, die nur mit Cube, HAL usw. zu potte
kommen, eben auch diejenigen, die hier am militantesten und lautesten
auftreten.
Was mich verwundert ist, was du meinst, daß es einen Takt für die CPU
liefert, solange du an dem internen RC-Oszilator herumprogrammierst. Ich
selber habe diesen Chip nicht, aber mir ist klar, daß die CPU zumindest
IRGENDEINEN Takt haben muß, um überhaupt aus dem Reset herauszukommen.
Also folgt logischermaßen, daß einer der internen RC-Oszillatoren
(sofern es mehrere gibt) ab Reset bereits läuft und die CPU mit Takt
versorgt. Was da noch übrig bleibt, wäre das Aktivieren des
Hauptoszillators (der mit dem externen Quarz) sofern gewünscht, das
Einrichten der PLL und wenn diese stabil läuft, dann die ggf. nötigen
Waits einschalten bzw. die Flash-Einstellung anpassen und dann das
Umschalten von der bisherigen Taktquelle auf den Takt von der PLL.
Wahrscheinlich muß man beim Hantieren mit dem Ein-, Aus- und Umschalten
der Taktsignale einige Vorsicht walten lassen, um sich nicht selber
sozusagen das Hochseil unter den Füßen wegzuziehen und abzustürzen. Ich
vermute mal, daß du da an irgendeiner Stelle versehentlich dir selbst
den Takt abgedreht hast.
Ich häng dir mal eine Konfiguration zur Ansicht dran. Ist für einen F103
und nicht für deinen Chip, aber wahrscheinlich hat es da Ähnlichkeiten.
W.S.
W.S. schrieb:> Ach nö, es sind bloß diejenigen, die nur mit Cube, HAL usw. zu potte> kommen, eben auch diejenigen, die hier am militantesten und lautesten> auftreten.
Wundert mich, dass noch keiner gesagt hat "Verwende die Arduino IDE!" :D
W.S. schrieb:> Ich> selber habe diesen Chip nicht, aber mir ist klar, daß die CPU zumindest> IRGENDEINEN Takt haben muß, um überhaupt aus dem Reset herauszukommen.
Ja nach dem Reset läuft der Chip mit einem Grundtakt von 16MHz.
Ich muss eigentlich nur die PLL dazwischen schalten, weil ich eine
SYSCLK von 64MHz haben möchte.
W.S. schrieb:> Ich häng dir mal eine Konfiguration zur Ansicht dran. Ist für einen F103> und nicht für deinen Chip, aber wahrscheinlich hat es da Ähnlichkeiten.
Ein schön dargestellter und Kommentierter Code :O
Ich bin beeindruckt, dass es das noch gibt. Danke ich werde es anschauen
und mit meinem Code vergleichen.
> Ja, Magic Numbers sind immer besonders vielsagend und sehr intuitiv.
Das kommt dir nur so vor. Ausserdem liest das hinterher eh keiner mahr.
Tatsaechlich steht im Quaelltext da noch EIN Kommentar was es tut.
Soll es mal was anderes tun, greife ich zur Referenz und
rechne mir etwas anderes Magisches aus.
Und so viel leserlicher sind die Verund- und Veroderungsorgien
die man hier so liest, auch nicht.
Vermutlich sind die nur von ihren 8 bit Atmels schon so
vorgeschaedigt worden.
Und im Gegensatz zum TO muss ich keinen fragen.
Und fuer "abweichende" Meinungen habe ich mein eigenes "/dev/null".
Das ist noch viel Platz frei.
W.S. schrieb:> Was mich verwundert ist, was du meinst, daß es einen Takt für die CPU> liefert, solange du an dem internen RC-Oszilator herumprogrammierst.> ... Was da noch übrig bleibt, wäre das Aktivieren des> Hauptoszillators (der mit dem externen Quarz) sofern gewünscht, das> Einrichten der PLL und wenn diese stabil läuft, dann die ggf. nötigen> Waits einschalten bzw. die Flash-Einstellung anpassen und dann das> Umschalten von der bisherigen Taktquelle auf den Takt von der PLL.
Liest du eigentlich, bevor du meckerst?
Das hat er doch alles im Eröffnungsbeitrag gemacht, aber irgend etwas
fehlt noch. Wenn du so gar keinen Plan hast, wie du ihm helfen könntest,
dann sei doch einfach still!
W.S. schrieb:> Ich häng dir mal eine Konfiguration zur Ansicht dran. Ist für einen F103
Genial, da ist genau der selben Fehler drin, wenn man dein Beispiel auf
den STM32G031 portiert.
sparfux schrieb:> Und so viel leserlicher sind die Verund- und Veroderungsorgien> die man hier so liest, auch nicht.
Das ist nur eine Frage der Gewöhnung. Früher hatte ich an solchen
Stellen oft Binärzahlen verwendet, mittlerweile nicht mehr.
Mein Ausbilder mochte Oktalzahlen, da hat sieht er die Bits gleich vor
seinem inneren Auge, meinte er. Mit Okalzahlen bin ich nie warm
geworden.
Stefan ⛄ F. schrieb:> Genial, da ist genau der selben Fehler drin, wenn man dein Beispiel auf> den STM32G031 portiert.
Deine Ratschläge sind wie immer besonders hilfreich.
So ungemein ausführlich dargestellt.
W.S.
W.S. schrieb:> Deine Ratschläge sind wie immer besonders hilfreich.> So ungemein ausführlich dargestellt.
Was fehlt hat Baumann B schon geschrieben, und zwar lange bevor du hier
mit deinen unpassenden Kommentaren aufgetaucht bist.
Markus M. schrieb:> Ich bevorzuge mittlerweile die Makros zum Modifizieren der Register.
Die Makros setzten die Register sicher richtig, aber kann mir jemand
erklären was diese Makros genau machen?
Moot S. schrieb:> Die Makros setzten die Register sicher richtig, aber kann mir jemand> erklären was diese Makros genau machen?> #define SET_BIT(REG, BIT) ((REG) |= (BIT))
Nun, das steht doch da:
Reg = Reg | Bit;
Aber das ist wie immer bei solchen Dingen eine gefährliche Sache, denn
man muß genau nachschauen, wie 'Bit' definiert ist.
Wenn da steht
#define MeinBit (1<<NeZahl)
dann geht das Ganze.
Aber wenn da steht
#define MeinBit Nezahl
dann geht das ganze Kunstwerk in die Hose.
Obendrein ist so ein Gehampel nicht immer das Sinnvollste, denn gerade
bei den Portpins mancher µC gibt es spezielle Setz- und Lösch-Register,
die das stupide Verfahren 'Lesen, Verändern, Zurückschreiben' unnötig
machen. Oftmals ist das auch grundsätzlich nötig, wenn beim Lesen der
Momentanzustand der Pins gelesen wird, aber beim Schreiben die Daten in
die Ausgangsregister kommen. Gerade beim I2C mit seinen OC-Ausgängen
gibt sowas dann Probleme.
W.S.
Genau, MODIFY_REG ist eigentlich der sinnvoll(st)e Makro, die anderen
sind eher kosmetisch.
MODFIY_REG macht folgendes:
- Liest den aktuellen Wert aus dem Register REG
- Maskiert alle Bits die in CLEARMASK angegeben sind (setzt sie auf "0")
- Setzt die Bits die in SETMASK angegeben sind
- Schreibt das ganze zurück in das Register
Der Makro ist dafür gedacht wenn mehrere Bits in einem Register eine
gemeinsame Funktion haben, z.B. einen Teiler definieren. Dann sollte man
sich nicht darauf verlassen, dass der Default-Wert "0" ist, sondern
dafür sorgen, dass die Bits auch explizit auf "0" gesetzt werden die
nicht auf "1" gesetzt werden sollen. Genau das macht der Makro.
Steve schrieb:> Cyblord -. schrieb:>> Dann schau dir den Clock Tree im Datenblatt an und setz die paar Bits in>> den Registern direkt.>> Das hat er doch gemacht.
Hat er? Les ich so nicht raus.
Und dann sollte man es natürlich noch richtig machen. Ich meine gerade
als Anfänger muss man auch nicht extrem viel Ändern. Vielleicht die
Taktquelle und dazu nen Prescaler und nen Multiplexer. Und dann hat man
den Systemtakt mal angepasst. Alles andere ist sowieso für
Fortgeschrittene.
Moot S. schrieb:> Ich finde weder im Datenblatt noch spezifisch im> Clock Tree irgend eine Info in welcher Reihenfolge diese Register> gesetzt werden müssen.
Das ist mir bei den Datenblättern der STM32 auch recht früh unangenehm
aufgefallen. Die Infos sind schon da, aber gut zwischen den Zeilen
versteckt.
Schön wären Hinweise wie "Wenn du hier X machst, musst du vorher in
Register Y dies und das setzen". Bei ST fehlen diese Querverweise
häufig. Man muss beim Lesen von X schon im Kopf wissen, dass es da noch
etwas relevantes bei Y gibt.
Cyblord -. schrieb:>> Das hat er doch gemacht.> Hat er? Les ich so nicht raus.
Schau dir seinen Quelltext im Eröffnungsbeitrag an. Da setzt er die Bits
selber.
Markus M. schrieb:> MODFIY_REG macht folgendes:
Danke für die ausführliche Erklärung!
W.S. schrieb:> dann geht das ganze Kunstwerk in die Hose.
Ja das habe ich in zwischen verstanden und werde es auch nicht mehr so
machen.
Steve schrieb:> Das hat er doch gemacht.
Der Fehler war die Reihen folge. Nun Funktioniert mein Code. Sieht nun
so aus:
Moot S. schrieb:> // Wait until HSI is stable> while(!READ_BIT(RCC->CR, RCC_CR_HSIRDY_Msk));
Ist das wirklich nötig? Ich habe schon ganz viele Code-Beispiele ohne
diese Warteschleife gesehen und ehrlich gesagt frage ich mich, was einen
R/C Oszillator davon abhalten könnte, sofort bereit zu werden.
Stefan ⛄ F. schrieb:> Moot S. schrieb:>> // Wait until HSI is stable>> while(!READ_BIT(RCC->CR, RCC_CR_HSIRDY_Msk));>> Ist das wirklich nötig? Ich habe schon ganz viele Code-Beispiele ohne> diese Warteschleife gesehen und ehrlich gesagt frage ich mich, was einen> R/C Oszillator davon abhalten könnte, sofort bereit zu werden.
Natürlich ist das unnötig, denn nach Reset lauft die CPU automatisch mit
HSI, und was bei Reset abläuft (Option Bytes laden etc.) dauert
insbesondere nach Power-Up so lange, dass der HSI garantiert da stabil
läuft. Um diesen Code auszuführen, muss ja schon der CPU-Takt laufen ...
Henne- und Ei-Problem.
A. B. schrieb:> nach Reset lauft die CPU automatisch mit HSI
OK, aber was ist wenn die CPU gerade extern getaktet wird und ich (warum
auch immer) auf den HSI zurück schalten will?
...ich hatte diese Codesquenz entweder in einem Beispiel von ST selbst
oder in einer der Libaries gesehen. Deswegen hatte ich es so übernommen.
Natürlich decken die Libraries auch den Fall ab, wo man ggfs. in die
andere Richtung umschaltet, also z.B. vom externen Takt auf HSI,
insofern ist dass evtl. der Grund für die Existenz.
Ich denke aber gerade bei diesen grundlegenden Initialisierungen, die
wahrscheinlich genau einmal beim Booten durchlaufen werden, sollte man
auf maximale Stabilität setzen, und da tun die paar Bytes nun wirklich
nicht weh.
A. B. schrieb:> Stefan ⛄ F. schrieb:>> Moot S. schrieb:>>> // Wait until HSI is stable>>> while(!READ_BIT(RCC->CR, RCC_CR_HSIRDY_Msk));>>>> Ist das wirklich nötig? Ich habe schon ganz viele Code-Beispiele ohne>> diese Warteschleife gesehen und ehrlich gesagt frage ich mich, was einen>> R/C Oszillator davon abhalten könnte, sofort bereit zu werden.>> Natürlich ist das unnötig, denn nach Reset lauft die CPU automatisch> mit HSI
nicht jede, manche starten mit dem MSI. In manchen Low Power
Betriebsarten wird auf einen anderen Oszillator umgeschaltet oder der
Takt komplett abgeschaltet. Wenn es dann irgendwann weiter geht, ist das
wie ein Reset, nur ein wenig anders... Eine lib, die für verschiedene
Chips und alle Betriebsarten funktionieren soll, wird zwangsläufig
"überflüssige" Befehle enthalten.
Die HSI-Warteschleife ist nötig, wenn man den HSI gerade eingeschaltet
hat, aber auch nur dann. So alleine, wie in der letzten
systick_config(), finde ich sie fragwürdig.
Markus M. schrieb:> ...ich hatte diese Codesquenz ... in einem Beispiel von ST ...> gesehen. Deswegen hatte ich es so übernommen.
Geht mir ebenso. Trotzdem wollte ich die Zeile mal hinterfragen, wo wir
gerade beim Thema sind.