/**
 * Projekt Kap05-SYSCLK-Konfiguration
 * ==================================
 *
 * Dieses Projekt ist ein Beispiel fuer die Anwendung der MCAL-Funktionen
 * fuer die Konfiguration von SYSCLK, AHB-, APB1- und APB2-Takt.
 */

#include <stdint.h>
#include <stm32f4xx.h>
#include <system_stm32f4xx.h>

#include <mcalGPIO.h>
#include <mcalRCC.h>
#include <mcalFlashCtrl.h>

#define MCO_PIN         (8)                         // Verwendung von PIN8
#define MCO_MODE        (1)                         // Pin PA8 = Output
#define SYSCLOCK        (180)                       // Takt soll 180 MHz betragen

void configClock(void);


int main(void)
{
    /******************************
     * MCAL-Version               *
     *****************************/

    // Der GPIO-Port wird nur benoetigt, weil im Buch ein Oszillogramm
    // gezeigt wird, das an MCO1 (= GPIO-Port A, Pin 8) gemessen wird.
    gpioSelectPort(GPIOA);
    gpioSelectPinMode(GPIOA, PIN8, OUTPUT);

    configClock();                                  // Konfiguration der Systemfrequenzen

    /* Loop forever */
    while (1)
    {

    }
}

/**
 * Diese Funktion koennen Sie in eigene Projekte aufnehmen.
 */
void configClock(void)
{
    uint32_t pllInputFreq = HSE_VALUE / 1000000;    // Auswahl der Eingangsfrequenz der
                                                    // PLL-Schaltung.
    uint16_t mcuFreq = SYSCLOCK;                    // Taktfrequenz der MCU, z.B. 180 MHz

    // Konfiguration der Waitstates
    flashConfigWaitStates(mcuFreq);

    // Aktivieren der Taktquelle (HSE oder HSI)
    rccEnableHSE();

    // Wir verwenden PLLP als Ausgang der PLL-Schaltung
    rccSelectSysclkSrc(SYSCLKSRC_PLLP);

#if 0
    // Alternative Funktionen zur Auswahl der SYSCLK-Quelle
    rccSelectSysclkSrc(SYSCLKSRC_HSI);
    rccSelectSysclkSrc(SYSCLKSRC_HSE);
    rccSelectSysclkSrc(SYSCLKSRC_PLLR);
#endif

    // Auswahl der Taktquelle (HSE oder HSI)
    rccSelectPLLClockSource(PLL_SRC_HSE);

    // Optional: Hier wird SYSCLK an den Ausgang MCO1 weitergeleitet.
    // Hiermit können externe Bauelemente getaktet werden.
    rccAssignClk2MCO(PLL_MAIN, MCO1);

    // Berechnung der Werte von PLLN, PLLM and PLLP
    rccSetSysclkFreq(pllInputFreq, mcuFreq);

    // Auswahl der Prescaler zum Einstellen der AHB- und APB-Frequenzen
    rccSetAHBPrescaler(SYSCLK_DIV_1);
    rccSetAPB2Prescaler(AHB_DIV_1);
    rccSetAPB1Prescaler(AHB_DIV_2);

    // Nicht vergessen: PLL-Schaltkreis aktivieren
    rccEnableMainPLL();
}
