Forum: Mikrocontroller und Digitale Elektronik Halbe SYSCLK Geschwindigkeit beim STM32F205 PLL


von Albert F. (afc_audio)


Lesenswert?

Moin zusammen, lange hier nichts mehr gepostet. Und jetzt wo ich dran 
brin... kommt erstmal ne Frage.

Ich habe ein selbstentwickeltes STM32F205 Board, der Hardwaremäßig 
funktioniert. Flashen, programmieren, LEDs blinken, alles toll.

I möchte jetzt die Frequenz des SYSCLK auf ~98 MHz erhöhen (12.288 MHz 
Kristall x 8), leider bekomme ich beim Ausgang des PLLs nur die Hälfte? 
Um das zu testen, habe ich ein SysTick timer konfiguriert, der jede 1000 
Ticks ein Interrupt auslöst. Da wird kurz mal ein LED hoch und runter 
geschaltet.

Gemessen am Oszi funktioniert der SysTick ganz gut bei HSI oder HSE (je 
16 oder 12.288 KHz Signal), aber wie gesagt, beim PLL, zeigt es dann nur 
49 KHz statt erwarteten 98 KHz.

Weiter runter habe ich das Code mit Kommentare. Und Entschuldigung wenn 
mein Deutsch etwas komisch klingt, wohne seit ein paar Jahren nicht mehr 
in DE!

Albert
1
#include "typedef.h"
2
3
#include "stm32f2xx.h"
4
#include "stm32f2xx_it.h"
5
6
#include "digIo.h"
7
8
void initFlash(void);
9
void initClocks(void);
10
11
char ledsOn = 0x1;
12
13
int main(void){
14
15
    initFlash();
16
    initClocks();
17
18
    /** Set timer to 98 KHz **/
19
  if (SysTick_Config(1000))
20
  {
21
    /* Capture error */
22
    while (1);
23
  }
24
25
    initLEDS();
26
27
    setLED_Off(0);
28
    setLED_Off(1);
29
    setLED_Off(2);
30
    setLED_Off(3);
31
32
    setLED_On(0);
33
    setLED_On(1);
34
    setLED_On(2);
35
    setLED_On(3);
36
37
    while(1){
38
39
        if(timerExpired == 1){
40
            timerExpired = 0;
41
42
            setLED_On(3);
43
            setLED_Off(3);
44
        }
45
    }
46
47
}
48
49
void initFlash(void){
50
51
  /** Set three wait states **/
52
  FLASH->ACR |= FLASH_ACR_LATENCY_3WS ;
53
}
54
55
void initClocks(void){
56
57
  /** Initialize clock to external clock (12.288 MHz) **/
58
  RCC->CR |= RCC_CR_HSEON;
59
  while(!(RCC->CR & RCC_CR_HSERDY)){
60
    ;
61
  }
62
63
  /** Set PLL source to HSE **/
64
  RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE;
65
66
  /** Set M divider to 0x8 (/8) **/
67
  RCC->PLLCFGR |= (RCC_PLLCFGR_PLLM_3);
68
69
  /** Set N multiplier to 0x80 (x128) **/
70
  RCC->PLLCFGR |= (RCC_PLLCFGR_PLLN_7);
71
72
  /** Set P divider to 0x0 (/2) **/
73
  RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLP);
74
75
  /** Enable PLL **/
76
  RCC->CR |= RCC_CR_PLLON;
77
  while(!(RCC->CR & RCC_CR_PLLRDY)){
78
    ;
79
  }
80
81
  /** Set SW to PLL **/
82
  RCC->CFGR |= RCC_CFGR_SW_PLL;
83
  while(!(RCC->CFGR & RCC_CFGR_SWS_PLL)){
84
    ;
85
  }
86
}

von Nico (Gast)


Lesenswert?

Weiß der Systick davon etwas?
Laut CMSIS im syste_stm32f4xx.c z.B. muss nach einem Ändern der Core 
Clock noch nen SystemCoreClockUpdate() durchgeführt werden.

https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4XX/system_stm32f4xx.c#L259

Das müsste beim F2 ja ähnlich sein?!?

von Albert F. (afc_audio)


Lesenswert?

Ich meine in dem Fall ist der SystemCoreClock nur der Wert des 
erwarteten PLL Ausgangs.

Bei SysTick_Config(1000) heisst es (so wie ich das verstehe), nach 1000 
ticks (clocks), löse Interrupt aus.

Man kann auch SysTick_Config(SystemCoreClock/1000) konfigurieren, dann 
kommt der Interrupt eben alle 1 ms. Deswegen wird der Wert 
SystemCoreClock neu geschrieben.

Ich werde nochmal weiterschauen, mir ist aufgefallen ich habe was an 
Flash wait states und prefetch vergessen.

von Albert F. (afc_audio)


Lesenswert?

Lösung gefunden.

Es scheint als ob man das RCC->PLLCFGR register in einem Schritt 
beschreiben muss. So sieht es jetzt aus
1
void initClocks(void){
2
3
  /** Initialize clock to external clock (12.288 MHz) **/
4
  RCC->CR |= RCC_CR_HSEON;
5
  while(!(RCC->CR & RCC_CR_HSERDY)){
6
    ;
7
  }
8
9
  /** Flash configuration **/
10
    /** Flash prefetch and cache ON, Flash 3 wait state **/
11
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;
12
13
  /** Set M divider to 0x8 (/8) **/
14
  /** Set N multiplier to 0x80 (x128) **/
15
  /** Set P divider to 0x0 (/2) **/
16
  /** Set PLL source to HSE **/
17
    RCC->PLLCFGR = (0x8 | ((uint32_t)0x80 << 6) | (((0x2 >> 1) -1) << 16)) | (RCC_PLLCFGR_PLLSRC_HSE);
18
19
  /** Enable PLL **/
20
  RCC->CR |= RCC_CR_PLLON;
21
  while(!(RCC->CR & RCC_CR_PLLRDY)){
22
    ;
23
  }
24
25
  /** Set SW to PLL **/
26
  RCC->CFGR |= RCC_CFGR_SW_PLL;
27
  while(!(RCC->CFGR & RCC_CFGR_SWS_PLL)){
28
    ;
29
  }
30
}

Un es läuft wie erwartet, schön 98 Khz Interrupts ausgelöst.

Albert.

von Nico (Gast)


Lesenswert?

Albert F. schrieb:
> Ich meine in dem Fall ist der SystemCoreClock nur der Wert des
> erwarteten PLL Ausgangs.
>
> Bei SysTick_Config(1000) heisst es (so wie ich das verstehe), nach 1000
> ticks (clocks), löse Interrupt aus.

Ah, richtig. Das habe ich elegant überlesen.

Danke noch für den Hinweis. Bei mir ist aktuell der PLLCFGR zwar in 
einem durch, aber man weiß ja nie, was man daran mal ändern will.

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.