Forum: Mikrocontroller und Digitale Elektronik STM32L073RZ läuft auf HSE nur halb so schnell wie erwartet


von Hans W. (hanswieland)


Angehängte Dateien:

Lesenswert?

Ich benutze das Nucleo L073RZ Board mit der Arduino IDE und lasse eine 
LED blinken:
1
void setup() {    
2
    pinMode(PA5, OUTPUT);
3
}
4
5
void loop() {
6
    digitalWrite(PA5, LOW);
7
    delay(500);
8
9
    digitalWrite(PA5, HIGH);
10
    delay(500);
11
}

Funktioniert bis dahin. Die Blink-Frequenz der LED bestätigt, dass das 
Setup korrekt funktioniert.

Dann habe ich mir den Quelltext der Taktkonfiguration angeschaut und 
gesehen, dass der Systemtakt vom internen Oszillator HSI (= 16 MHz) 
bezogen wird. Das möchte ich auf HSE (= 8 MHz vom ST-Link) umstellen.

Aber egal wie ich es versuche, die CPU läuft immer nur halb so schnell 
wie sie soll.

Versuch 1:

Zuerst habe ich den Code von STM32duino kopiert und modifiziert. Ich 
habe HSI durch HSE ersetzt und die PLL verdoppelt. Das sollte wieder 32 
MHz ergeben, läuft aber nur halb so schnell.
1
void SystemClock_Config(void)
2
{
3
4
  RCC_OscInitTypeDef RCC_OscInitStruct = {};
5
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
6
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {};
7
8
  /* Configure the main internal regulator output voltage */
9
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
10
11
  /* Initializes the CPU, AHB and APB busses clocks */
12
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI48;
13
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
14
  //RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
15
  RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
16
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
17
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
18
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_8;
19
  RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;
20
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
21
    Error_Handler();
22
  }
23
24
  /* Initializes the CPU, AHB and APB busses clocks */
25
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
26
                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
27
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
28
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
29
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
30
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
31
32
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
33
    Error_Handler();
34
  }
35
36
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
37
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
38
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
39
    Error_Handler();
40
  }
41
}

Versuch 2:
Komplett selbst geschrieben. Sollte 32 MHz ergeben, läuft aber nur halb 
so schnell.
1
void SystemClock_Config(void) {
2
3
    // Wait until voltage regulator is stabilized
4
    while(READ_BIT(PWR->CSR, PWR_CSR_VOSF)) {}
5
6
    // Switch to voltage scaling range 1
7
    MODIFY_REG(PWR->CR, PWR_CR_VOS, 1 << PWR_CR_VOS_Pos);
8
9
    // Wait until voltage regulator is stabilized
10
    while(READ_BIT(PWR->CSR, PWR_CSR_VOSF)) {}
11
12
    // Enable HSE oscillator
13
    SET_BIT(RCC->CR, RCC_CR_HSEON);
14
15
    // Wait until HSE oscillator is ready
16
    while(!READ_BIT(RCC->CR, RCC_CR_HSERDY)) {}
17
18
    // Switch to HSE oscillator
19
    MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_HSE);
20
21
    // Wait until the switch is done
22
    while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_HSE) {}
23
24
    // Disable the PLL
25
    CLEAR_BIT(RCC->CR, RCC_CR_PLLON);
26
27
    // Wait until the PLL is fully stopped
28
    while(READ_BIT(RCC->CR, RCC_CR_PLLRDY)) {}
29
   
30
    // Flash latency 1 wait state
31
    SET_BIT(FLASH->ACR, FLASH_ACR_LATENCY);
32
33
    // 32 MHz using the 8 MHz HSE oscillator multiply by 8 divide by 2
34
    RCC->CFGR = RCC_CFGR_PLLSRC_HSE + RCC_CFGR_PLLMUL8 + RCC_CFGR_PLLDIV2;
35
36
    // Enable PLL
37
    SET_BIT(RCC->CR, RCC_CR_PLLON);
38
39
    // Wait until PLL is ready
40
    while(!READ_BIT(RCC->CR, RCC_CR_PLLRDY)) {}
41
42
    // Select PLL as clock source
43
    MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_PLL);
44
45
    // Update system timer
46
    SystemCoreClock=32000000;
47
    SysTick_Config(SystemCoreClock/1000);
48
49
    // Switch the MSI oscillator off
50
    CLEAR_BIT(RCC->CR, RCC_CR_MSION);    
51
}

Versuch 3:
Die CPU soll ganz simpel direkt von HSE getaktet werden, ohne PLL. Ich 
erwarte 8 MHz, sie läuft aber wieder nur halb so schnell:
1
void SystemClock_Config(void) {
2
3
    // Enable HSE oscillator
4
    SET_BIT(RCC->CR, RCC_CR_HSEON);
5
6
    // Wait until HSE oscillator is ready
7
    while(!READ_BIT(RCC->CR, RCC_CR_HSERDY)) {}
8
9
    // Switch to HSE oscillator
10
    MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_HSE);
11
12
    // Wait until the switch is done
13
    while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_HSE) {}
14
15
    // Update system timer
16
    SystemCoreClock=8000000;
17
    SysTick_Config(SystemCoreClock/1000);
18
19
    // Switch the MSI oscillator off
20
    CLEAR_BIT(RCC->CR, RCC_CR_MSION);    
21
}

Wie gesagt habe ich den HSE Takt mit einem Oszilloskop kontrolliert. Der 
hat wirklich 8 MHz, so wie es dokumentiert ist.

Was übersehe ich?
: Bearbeitet durch User
von Wastl (hartundweichware)


Lesenswert?

Hans W. schrieb:
> Was übersehe ich?

Zunächst übersiehst du mal dass dir bei jedem Beitrag, den du
schreibst, gesagt wird dass:

"Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang"

Länger bedeuted in diesem Zusammenhang "mehr als eine Bildschirmseite".

Das ist ein Gebot der Freundlichkeit und der Netiquette.
Siehe dazu speziell auch "Äußere Form".
von Hans W. (hanswieland)


Lesenswert?

Zum Vergleich: Mit dem Nucleo F303RE Board habe ich das Problem nicht. 
Dort konnte ich problemlos auf den HSE wechseln:
1
    // Enable HSE oscillator
2
    SET_BIT(RCC->CR, RCC_CR_HSEON);
3
4
    // Wait until HSE oscillator is ready
5
    while(!READ_BIT(RCC->CR, RCC_CR_HSERDY)) {}
6
7
    // Switch to HSE oscillator
8
    MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_HSE);
9
10
    // Wait until the switch is done
11
    while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_HSE) {}
12
13
    // Disable the PLL
14
    CLEAR_BIT(RCC->CR, RCC_CR_PLLON);
15
16
    // Wait until PLL is fully stopped
17
    while(READ_BIT(RCC->CR, RCC_CR_PLLRDY)) {}
18
    
19
    // Flash latency 2 wait states
20
    MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, 2 << FLASH_ACR_LATENCY_Pos);
21
    
22
    // 72 MHz using the 8 MHz HSE oscillator with 9x PLL, lowspeed I/O runs at 36 MHz
23
    RCC->CFGR = RCC_CFGR_SWS_HSE + RCC_CFGR_PLLSRC_HSE_PREDIV + RCC_CFGR_PLLMUL9 + RCC_CFGR_PPRE1_DIV2;
24
25
    // Enable PLL
26
    SET_BIT(RCC->CR, RCC_CR_PLLON);
27
28
    // Wait until PLL is ready
29
    while(!READ_BIT(RCC->CR, RCC_CR_PLLRDY)) {}
30
31
    // Select PLL as clock source
32
    MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_PLL);
33
34
    // Update system timer
35
    SystemCoreClock=72000000;
36
    SysTick_Config(SystemCoreClock/1000);
37
    
38
    // Disable the HSI oscillator
39
    CLEAR_BIT(RCC->CR, RCC_CR_HSION);
: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Hallo,

Hans W. schrieb:
> Was übersehe ich?

Du hast die Hardwarekonfiguration geändert, nur das Programm selbst weiß 
noch nichts davon. Funktionen wie delay() beruhen auf der Definition vom 
CPU Takt.
Du müsstest noch #define F_CPU anpassen. Heißt bei AVR so, ob der Name 
bei STM gleich lautet weiß ich nicht, nehme ich aber stark an.

Edit:
Wenn bei STM 'SystemCoreClock' dem AVR 'F_CPU' entspricht und du das 
geändert hast, dann weiß ich es nicht.
: Bearbeitet durch User
von Hans W. (hanswieland)


Lesenswert?

Veit D. schrieb:
> Du hast die Hardwarekonfiguration geändert, nur das Programm selbst weiß
> noch nichts davon. Funktionen wie delay() beruhen auf der Definition vom
> CPU Takt.

Daran liegt es nicht. Diese Zeilen erledigen das:
> SystemCoreClock=72000000;
> SysTick_Config(SystemCoreClock/1000);

Habe ich mit anderen Frequenzen auf Basis des HSI gegen getestet.

> Du müsstest noch #define F_CPU anpassen. Heißt bei AVR so, ob der Name
> bei STM gleich lautet weiß ich nicht, nehme ich aber stark an.

F_CPU ist als Alias für SystemCoreClock definiert.
von Hans W. (hanswieland)


Angehängte Dateien:

Lesenswert?

Ich habe das Problem auch unabhängig von allen Frameworks mit einem 
minimalen Projekt in der Cube IDE. Auch dieses Programm läuft nur halb 
so schnell, wie es sollte.
: Bearbeitet durch User
von Hans W. (hanswieland)


Lesenswert?

Juhuuu, ich hab's gefunden!

falsch:
1
    // Enable HSE oscillator
2
    SET_BIT(RCC->CR, RCC_CR_HSEON);

richtig:
1
    // Enable HSE oscillator
2
    SET_BIT(RCC->CR, RCC_CR_HSEON + RCC_CR_HSEBYP);

Das ist aber echt schräg, dass durch diesen Fehler exakt die halbe 
Taktfrequenz entsteht. Ich habe dieses HSEBYP Bit noch nie zuvor 
benutzen müssen. Werde mich jetzt dazu einlesen.
Beitrag #8053897 wurde vom Autor gelöscht.
von Alexander (alecxs)


Lesenswert?

Hans W. schrieb:
> Was übersehe ich?
1
SET_BIT(RCC->CR, RCC_CR_HSEBYP);
von Hans W. (hanswieland)


Lesenswert?

Alexander schrieb:
> Was übersehe ich?
> SET_BIT(RCC->CR, RCC_CR_HSEBYP);

Haha, echt witzig. Als wäre ich nicht kurz vorher selbst drauf gekommen.

Bonusfrage extra für dich:
Warum ist die Taktfrequenz ohne dieses bit exakt halb so hoch?
: Bearbeitet durch User
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.