01 - Takteinstellung mit der MCAL-Bibliothek

An verschiedenen Stellen im Buch habe ich auf Anhang B verwiesen, wo Informationen zur Einstellung der Taktfrequenz zu finden sind. Die Schwierigkeit besteht darin, dass die dort beschriebene Vorgehensweise schließlich Code generiert, der stark von der HAL-Bibliothek von STM abhängt: Und die Abhängigkeit von der HAL-Bibliothek wollte ich möglichst vermeiden!

Nun ist es aber so, dass zwischen der Abgabe eines Buchmanuskripts und dem Erscheinungsdatum des fertigen Buches naturgemäß einige Zeit vergeht: Lektorat – Korrektur – Erstellen der ersten und zweiten (manchmal auch der dritten) Buchfahne – Druck – Auslieferung an den Buchhandel sind Aktivitäten, die alle einige Zeit in Anspruch nehmen. Dies gilt umso mehr, wenn dann noch der Jahreswechsel mitsamt Feiertagen und Urlaub der Beteiligten „dazwischenfunkt“: Bei meinem STM32-Buch dauerte dies ca. 10 Wochen!

Diese Zeitspanne habe ich genutzt, um die im Verlauf des Buches entwickelte MCAL-Bibliothek um Funktionen zur Einstellung der Taktfrequenz des Mikrocontrollers zu erweitern.

Maximale Taktfrequenzen der STM32F4xx-Familie

Bekanntermaßen beträgt die maximale Taktfrequenz, mit der STM32F4xx-Mikrocontroller getaktet werden können, 180 MHz. Dies gilt aber nicht für alle Mitglieder dieser Familie. Die folgende Abbildung zeigt die möglichen maximalen Taktfrequenzen:

Übersicht: Maximale Taktfrequenzen

Das von mir verwendete NUCLEO64-STM32F446-Entwicklungsboard ist vom Werk so konfiguriert, dass der Mikrocontroller mit einer Frequenz von 16 MHz getaktet wird: Da dieser Mikrocontroller aber mit maximal 180 MHz getaktet werden kann, gibt es also „viel Luft nach oben“.

!!!ACHTUNG!!!

In der Datei \CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c ist für den Wert HSE_VALUE die maximal zulässige Taktfrequenz des externen Quarzoszillators eingetragen. HSE_VALUE ist die Basis für alle Taktfrequenzen, die von einem externen Quarz abgeleitet werden. Standardmäßig ist hier der Wert 25000000, entsprechend 25 MHz, eingetragen. Wenn Sie einen externen Quarz mit dieser Taktfrequenz verwenden, ist alles in Ordnung. Wenn Sie hingegen einen anderen Quarz verwenden, wie z.B. den mit 8 MHz schwingenden Quarz auf dem ST-LINK-Board, führt dies zu einer erheblichen Abweichung (ca. Faktor 3) der internen Taktfrequenzen der Peripheriekomponenten!

Aufgefallen ist mir dies, als ich mit dem externen 8MHz-Quarz ein einfaches Toggeln eines GPIO-Pins mit meinem Oszilloskop nachgemessen habe. Statt, wie erwartet, das Toggeln im 35ms-Rhythmus (Periodendauer = 70ms) zu sehen, lag jeder High- bzw. Low-Wert nun ca. 115ms an (Periodendauer ca. 230ms). Ich habe daher den HSE_WERT testweise auf die tatsächliche Frequenz von 8 MHz gestellt, und dann verhielt sich das Programm korrekt! Die Datei system_stm32f4xx.c enthält folgende Sequenz (ohne die hier deaktivierte Zeile):

#if !defined (HSE_VALUE)
    #define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */
    // #define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz */
#endif /* HSE_VALUE */

#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */

 

Tipp:

Wenn ihnen die Taktfrequenz des externen Quarzes nicht bekannt ist, konfigurieren Sie den Systemtakt (MCAL-Version) durch Nutzung des durch den internen RC-Oszillator erzeugten HSI-Takt:

int main(void)
{
    uint16_t mcuClock = 180;

    setupSystemClock(SYSCLKSRC_PLLP, PLL_SRC_HSI, &mcuClock);

    ...

}

Grundsätzliches

Es gibt verschiedene Taktquellen, die ein Mikrocontroller nutzen kann, um aus diesem „Ur-Takt“ die gewünschte Zielfrequenz zu erzeugen. Bei den NUCLEO64-STM32F4xx-Boards sind dies

  • HSI (High-Speed Internal): Aus diesem wird auch die im Buch verwendete Taktfrequenz erzeugt.
  • HSE (High-Speed External): Hier wird ein externer Quarz verwendet, dessen Frequenz zwischen 4 und 25 MHz liegen darf.

Auf dem abtrennbaren ST-Link ist aber auch ein externer 8-MHz-Quarz vorhanden, der ebenfalls verwendet werden kann.

Funktionssammlung im Modul mcalFlash und mcalRCC

ACHTUNG: Die Funktionen, die in früheren Versionen der MCAL-Bibliothek im Modul mcalSystem enthalten waren, wurden in die Module mcalRCC und mcalFlash ausgelagert. 

mcalFlash.h / mcalFlash.c

Der Zugriff auf den integrierten Flash-Speicher ist von der System-Taktfrequenz abhängig und muss entsprechend angepasst werden. Derzeit enthält mcalFlash.h/mcalFlash.c nur eine Funktion, die diese Aufgabe übernimmt. Sie heißt

void flashConfigWaitStates(uint16_t sysclk).

Als Parameter sysclk wird die gewünschte Taktfrequenz in MHz angegeben. Wenn Sie den Mikrocontroller also mit einer Taktfrequenz von 180 MHz betreiben wollen, so verwenden Sie in Ihrem Projekt die Funktion flashConfigWaitStates(180).

mcalRCC.h / mcalRCC.c

Dieses Modul enthält die Funktionen, die für die Einstellungen der Peripheriekomponente Reset and Clock Control zuständig sind. Zu diesem Zweck stehen derzeit 24 Funktionen zur Verfügung, von denen ich die wichtigsten hier beschreibe. Die Beschreibung der weiteren Funktionen finden Sie in der MCAL-Dokumentation, die Bestandteil der MCAL ist.

void rccEnableHSE(void) / void sysEnableHSI(void)

Hiermit können Sie auswählen, ob der Systemtakt aus dem externen Quarz oder aus dem internen RC-Generator erzeugt werden soll.

void rccSelectSysclkSrc(SYSCLK_SRC_t sysclkSrc)

Diese Funktion dient zur Einstellung der Taktquelle, aus der schließlich die gewünschte Taktfrequenz erzeugt wird. sysclkSrc kann die Werte SYSCLKSRC_HSI, SYSCLKSRC_HSE, SYSCLKSRC_PLLP oder SYSCLKSRC_PLLR annehmen. Wählen Sie die beiden ersten Parameter, so ist der Systemtakt auf die Taktfrequenz HSI (16 MHz) oder HSE (die Frequenz des verwendeten Quarzes) beschränkt. Um höhere Taktfrequenzen bis hin zum maximalen Systemtakt zu erzielen, müssen als Parameter SYSCLKSRC_PLLP oder SYSCLKSRC_PLLR verwendet werden.

void rccSelectPLLClockSource(PLL_CLOCK_SRC_t clkSrc)

Mit dieser Funktion wird eingestellt, ob HSI oder HSE in die PLL-Schaltung (PLL = Phased-lock Loop) eingespeist wird.

void rccAssignClk2MCO(MCO_CLK_SRC_t clkSrc, MCO_TypeDef_t mco)

Der STM32F446 hat zwei Anschlüsse, aus denen der gewählte Systemtakt zur Taktung weiterer externer Peripherie herausgeführt wird. Als clkSrc können hier  die Parameter SYSCLK, PLL_I2S, HSE, PLL_MAIN, HSI oder LSE gewählt werden. Der Parameter mco kann die Werte MCO1 oder MCO2 annehmen.

Der Einsatz dieser Funktion ist nicht vorgeschrieben! Ich habe sie nur genutzt, um die Funktionen zu testen.

void rccSetSysclkFreq(uint8_t fOsc, uint16_t *mcuFreq)

Hier werden die Werte für die PLL-Register berechnet, damit die gewünschte Frequenz auch korrekt erreicht wird. Diese Funktion berücksichtigt Ihre Einstellung in der Datei stm32f4xx.h, in der Sie den von Ihnen verwendeten Mikrocontroller auswählen und begrenzt die Frequenz unabhängig vom Wert von fOsc auf die maximale Taktfrequenz des gewählten Mikrocontrollers.

void rccSetAHBPrescaler(AHB_DIVIDER_t div) / void sysSetAPBPrescaler(AHB_DIVIDER_t div)

Da die Busse AHB und APB aus dem Systemtakt abgeleitet werden, habe ich zur Einstellung ihrer Taktfrequenzen diese beiden Funktionen vorgesehen.

void rccEnableMainPLL(void)

Ganz zum Schluss muss natürlich noch die PLL-Schaltung aktiviert werden: Zu diesem Zweck nutzen Sie diese Funktion.

Anwendungsbeispiel

Sysclock.zip (17,2 KiB)

Das Ergebnis

Das folgende Oszillogramm zeigt den Systemtakt (gemessen an MCO1): Hier beträgt die Taktfrequenz 180 MHz. Im rot umrandeten Kasten sehen Sie, was mein Oszilloskop gemessen hat.

Anmerkung:

Die (geringfügige) Abweichung von ca. 0,5% zur gewünschten Taktfrequenz ist sicherlich auch darauf zurückzuführen, dass mein Oszilloskop offiziell „nur“ 100 MHz messen kann.