Forum: Mikrocontroller und Digitale Elektronik Problem mit Clock Configuration beim STM32G031


You were forwarded to this site from EmbDev.net. Back to EmbDev.net
von Moot S. (mootseeker)


Lesenswert?

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:
1
#include "main.h"
2
3
#define PLLQ ( 2 )
4
#define PLLP ( 0 )
5
#define PLLN ( 8 )
6
#define PLLM ( 1 )
7
#define PLLR ( 2 )
8
9
//...........................................................................................................
10
/**
11
  * @brief  System Clock Configuration
12
  *         The system Clock is configured as follow :
13
  *            System Clock source            = PLL (HSI)
14
  *            SYSCLK(Hz)                     = 64000000
15
  *            HCLK(Hz)                       = 64000000
16
  *            AHB Prescaler                  = 1
17
  *            APB Prescaler                  = 1
18
  *            HSI Frequency(Hz)              = 16000000
19
  *            PLL_M                          = 1
20
  *            PLL_N                          = 8
21
  *            PLL_R                          = 2
22
  *            VDD(V)                         = 3.3
23
  *            Main regulator output voltage  = Scale1 mode
24
  *            Flash Latency(WS)              = 2
25
  * @param  None
26
  * @retval None
27
  */
28
void systick_config( void )
29
{
30
31
  RCC->CR |= RCC_CR_HSION;       //Set HSI On
32
  while(!(RCC->CR & RCC_CR_HSIRDY));   //Wait until HSI is ready
33
34
  RCC->APBENR1 |= RCC_APBENR1_PWREN; //Set the power enable clock
35
36
  PWR->CR1 |= PWR_CR1_VOS; //Set Volatge Scaling range 1
37
38
  /* Configure the FLASH PREFETCH and the LATENCY Related Settings */
39
  FLASH->ACR |= FLASH_ACR_DBG_SWEN | FLASH_ACR_ICEN | FLASH_ACR_PRFTEN | FLASH_ACR_LATENCY_2;
40
41
  RCC->PLLCFGR |= RCC_PLLCFGR_PLLR_0 | RCC_PLLCFGR_PLLQ_0 | RCC_PLLCFGR_PLLP_0 | RCC_PLLCFGR_PLLN_3 | RCC_PLLCFGR_PLLM_0;
42
  RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSI;
43
44
  RCC->CFGR |= RCC_CFGR_HPRE_0;
45
  RCC->CFGR |= RCC_CFGR_PPRE_0;
46
47
  RCC->CR |= RCC_CR_PLLON;
48
  while(!(RCC->CR & RCC_CR_PLLRDY));
49
50
  RCC->CFGR |= RCC_CFGR_SW_1;
51
  while((RCC->CFGR & RCC_CFGR_SWS_1) != RCC_CFGR_SWS_1);
52
}

Zur Vollständigkeit sieht meine Main Funktion wie folgt aus:
1
#include "main.h"
2
3
//...........................................................................................................
4
/**
5
  * @brief  The application entry point.
6
  * @retval int
7
  */
8
int main(void)
9
{
10
  // Init MCU clock
11
  systick_config( );
12
13
    /* Loop forever */
14
15
  for(;;)
16
  {
17
18
  }
19
}

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" :
1
  RCC->CFGR |= RCC_CFGR_SW_1;
2
  while((RCC->CFGR & RCC_CFGR_SWS_1) != RCC_CFGR_SWS_1);

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.

von STK500-Besitzer (Gast)


Lesenswert?

STM32CubeMX verwenden.
Da kann man sich auch die Clock-Konfiguration optisch darstellen lassen.

von Moot S. (mootseeker)


Lesenswert?

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.

von STK500-Besitzer (Gast)


Lesenswert?

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.

von pegel (Gast)


Lesenswert?

Oder die LL Funktionen nutzen.

von pegel (Gast)


Angehängte Dateien:

Lesenswert?

z.B.

von Harry L. (mysth)


Lesenswert?

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)

von Bauform B. (bauformb)


Lesenswert?

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.

von Moot S. (mootseeker)


Lesenswert?

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
1
 #define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

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?

von Moot S. (mootseeker)


Lesenswert?

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.

von pegel (Gast)


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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.

von Moot S. (mootseeker)


Lesenswert?

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.

von Moot S. (mootseeker)



Lesenswert?

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.

von pegel (Gast)


Lesenswert?

Moot S. schrieb:
> Reihenfolge und welche Register

Das genau meinte ich als Rahmen der von CubeMX vorgegeben wird.

von pegel (Gast)


Lesenswert?

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.

von Moot S. (mootseeker)


Lesenswert?

pegel schrieb:
> Das genau meinte ich als Rahmen der von CubeMX vorgegeben wird.

Achso, ja jetzt hab ich es verstanden. Ich schaue es mir mal an.

von A. B. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Bauform B. (bauformb)


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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.

: Bearbeitet durch User
von Markus M. (adrock)


Lesenswert?

Hier ist mein getesteter Code aus einem Projekt:
1
void rcc_init(void) {
2
    // Set Flash wait states to 0, wait until set
3
4
    MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY_Msk, (0<<FLASH_ACR_LATENCY_Pos));
5
    while((READ_REG(FLASH->ACR)&FLASH_ACR_LATENCY_Msk) != (0<<FLASH_ACR_LATENCY_Pos));
6
7
    // Wait until HSI is stable
8
9
    while(!READ_BIT(RCC->CR, RCC_CR_HSIRDY_Msk));
10
11
    // Configure & enable PLL
12
    // SysClk == HSI/PLLM*PLLN/PLLR == 16MHz/1*12/8 == 24MHz
13
14
    MODIFY_REG(RCC->PLLCFGR,
15
        RCC_PLLCFGR_PLLSRC_Msk|RCC_PLLCFGR_PLLM_Msk|RCC_PLLCFGR_PLLN_Msk|
16
        RCC_PLLCFGR_PLLP_Msk|RCC_PLLCFGR_PLLR_Msk,
17
        RCC_PLLCFGR_PLLSRC_HSI|         // PLLM = 1, PLLSRC = HSI
18
        (12<<RCC_PLLCFGR_PLLN_Pos)|     // PLLN = 12
19
        RCC_PLLCFGR_PLLP_0|             // PLLP = 2
20
        (7<<RCC_PLLCFGR_PLLR_Pos)|      // PLLR = 8
21
        RCC_PLLCFGR_PLLREN);
22
23
    SET_BIT(RCC->CR, RCC_CR_PLLON);     // Enable PLL
24
25
    while(!READ_BIT(RCC->CR, RCC_CR_PLLRDY_Msk)); // Wait 'til ready
26
 
27
    // Configure system clocks
28
29
    // AHB and APB at default == 1, SW == PLLRCLT
30
31
    MODIFY_REG(RCC->CFGR, RCC_CFGR_SW_Msk, RCC_CFGR_SW_1);
32
33
    // Wait until switched
34
35
    while(READ_BIT(RCC->CFGR, RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1); 
36
37
    // Whoooopie, clock is up! Update SystemCoreClock variable
38
39
    SystemCoreClockUpdate();
40
41
    // Take care of debug interface
42
    #ifdef  DEBUG
43
        SET_BIT(RCC->APBENR1, RCC_APBENR1_DBGEN);
44
//        SET_BIT(DBG->CR, DBG_CR_DBG_STANDBY|DBG_CR_DBG_STOP);
45
    #endif
46
}

Ich bevorzuge mittlerweile die Makros zum Modifizieren der Register.

: Bearbeitet durch User
von Moot S. (mootseeker)


Lesenswert?

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.

von sparfux (Gast)


Lesenswert?

Um einen ST M0 (im Beispiel ein F030) mit 32 MHz PLL anzutreiben:
1
FLASH_ACR_bit.LATENCY = 1;
2
RCC_CFGR = 0x414D0000;
3
RCC_CR = 0x1050300;
4
while(! RCC_CR_bit.PLLRDY); RCC_CFGR_bit.SW = 3;

Nicht besonders schoen, aber besonders sparsam.

von dumpf backe (Gast)


Lesenswert?

sparfux schrieb:
> Nicht besonders schoen, aber besonders sparsam.

Ja, Magic Numbers sind immer besonders vielsagend und sehr intuitiv.

von Bauform B. (bauformb)


Lesenswert?

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?

von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Moot S. (mootseeker)


Lesenswert?

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.

von sparfux (Gast)


Lesenswert?

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

von Stefan F. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Moot S. (mootseeker)


Lesenswert?

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?
1
#define SET_BIT(REG, BIT)     ((REG) |= (BIT))
2
3
#define CLEAR_BIT(REG, BIT)   ((REG) &= ~(BIT))
4
5
#define READ_BIT(REG, BIT)    ((REG) & (BIT))
6
7
#define CLEAR_REG(REG)        ((REG) = (0x0))
8
9
#define WRITE_REG(REG, VAL)   ((REG) = (VAL))
10
11
#define READ_REG(REG)         ((REG))
12
13
#define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

Also SET_BIT, CLEAR_BIT, CLEAR_REG, WRITE_REG und READ_REG sind klar, 
aber was macht z.B. MODIFY_REG?

von W.S. (Gast)


Lesenswert?

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.

von A. B. (Gast)


Lesenswert?

Moot S. schrieb:
> aber was macht z.B. MODIFY_REG?

Das steht schon da:
Beitrag "Re: Problem mit Clock Configuration beim STM32G031"

von Markus M. (adrock)


Lesenswert?

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.

von Steve van de Grens (roehrmond)


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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.

von Steve van de Grens (roehrmond)


Lesenswert?

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.

: Bearbeitet durch User
von Moot S. (mootseeker)


Lesenswert?

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:
1
#define PLLQ ( 2 )
2
#define PLLP ( 0 )
3
#define PLLN ( 8 )
4
#define PLLM ( 1 )
5
#define PLLR ( 2 )
6
#define Prescaler ( 0 )
7
8
//...........................................................................................................
9
/**
10
  * @brief  System Clock Configuration
11
  *         The system Clock is configured as follow :
12
  *            System Clock source            = PLL (HSI)
13
  *            SYSCLK(Hz)                     = 64000000
14
  *            HCLK(Hz)                       = 64000000
15
  *            AHB Prescaler                  = 1
16
  *            APB Prescaler                  = 1
17
  *            HSI Frequency(Hz)              = 16000000
18
  *            PLL_M                          = 1
19
  *            PLL_N                          = 8
20
  *            PLL_R                          = 2
21
  *            VDD(V)                         = 3.3
22
  *            Main regulator output voltage  = Scale1 mode
23
  *            Flash Latency(WS)              = 2
24
  * @param  None
25
  * @retval None
26
  */
27
void systick_config( void )
28
{
29
  // Set Flash wait states to 0, wait until set
30
  MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY_Msk, (0<<FLASH_ACR_LATENCY_Pos));
31
  while((READ_REG(FLASH->ACR)&FLASH_ACR_LATENCY_Msk) != (0<<FLASH_ACR_LATENCY_Pos));
32
33
  // Wait until HSI is stable
34
  while(!READ_BIT(RCC->CR, RCC_CR_HSIRDY_Msk));
35
36
  // Configure & enable PLL
37
  MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR,
38
               Source | PLLM | (PLLN << RCC_PLLCFGR_PLLN_Pos) | PLLR);
39
40
    SET_BIT(RCC->CR, RCC_CR_PLLON);     // Enable PLL
41
42
    while(!READ_BIT(RCC->CR, RCC_CR_PLLRDY_Msk)); // Wait 'til ready
43
44
    // Configure system clocks
45
    // AHB and APB at default == 1, SW == PLLRCLT
46
    MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, Prescaler);
47
48
    //Select Source
49
    MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_1);
50
51
    // Wait until switched
52
    while(READ_BIT(RCC->CFGR, RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1);
53
54
    /* Update SysCoreclk */
55
    SystemCoreClock = 64000000;
56
57
    // Enable Debug 
58
    SET_BIT(RCC->APBENR1, RCC_APBENR1_DBGEN);
59
}

Der Code sieht ähnlich aus wie im oberen Beitrag, wurde aber noch etwas 
angepasst. Dieser Funktioniert nun jedenfalls so wie er soll.

von Stefan F. (Gast)


Lesenswert?

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.

von A. B. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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?

von Markus M. (adrock)


Lesenswert?

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

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

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.