/**
 * Kap12-ACTIM-01-Center-and-Edge-Align
 * ====================================
 *
 * TIM8   : Erzeugung einer Totzeit zwischen dem Main-Output und seinem
 *          komplementären Ausgang. Es ist zu beachten, dass der nicht-
 *          invertierende Ausgang von TIM8/Kanal 1 an Pin 6 von GPIOC und
 *          sein invertierende Ausgang (Komplementaerausgang) an Pin 5 von
 *          GPIOA angeschlossen ist (siehe Tabelle 11 im Datenblatt des
 *          STM32F446).
 *
 * Pin PA5: Komplementaerausgang von TIM8/Kanal 1
 * Pin PC6: Nicht-invertierender Ausgang von TIM8/Kanal1
 */

#include <stm32f4xx.h>

#include <stdint.h>
#include <stdbool.h>

/**
 * Kommentar in Zeile 16 entfernen, wenn Sie die MCAL testen möchten.
 */
#define MCAL

#ifdef MCAL
#include <mcalGPIO.h>
#include <mcalTimer/mcalTimer.h>
#endif

int main(void)
{
    GPIO_TypeDef *port1 = GPIOA;
    GPIO_TypeDef *port2 = GPIOC;
    TIM_TypeDef  *tim   = TIM8;

#ifdef MCAL     // Beginn der MCAL-Version

    // Konfiguration von GPIOA / Pin 5 (Komplementaer-Ausgang)
    gpioSelectPort(port1);                      // GPIOA: Bustakt aktivieren
    gpioSelectPinMode(port1, PIN5, ALTFUNC);    // PA5 = AF3
    gpioSelectAltFunc(port1, PIN5, AF3);

    // Konfiguration von GPIOC / Pin 6 (Nicht-invertierender Ausgang)
    gpioSelectPort(port2);                      // GPIOC: Bustakt aktivieren
    gpioSelectPinMode(port2, PIN6, ALTFUNC);    // PC6 = AF3
    gpioSelectAltFunc(port2, PIN6, AF3);

    // Konfiguration von TIM8
    timerSelectTimer(tim);                      // TIM8: Bustakt aktivieren
    timerSetPrescaler(tim, 16);                 // TIM8: Takt = 1MHz
    timerSetAutoReloadValue(tim, 1000);         // TIM8: Auto-Reload-Register
    timerResetCounter(tim);                     // TIM8: Counter reset

    // TIM8: Kanal 1 --> Betriebsart = PWM-Mode 1
    timerSetOutputCompareMode(tim, TIMIO_CH1, CHN_PWM_MODE_1);
    timerSetPreloadValue(tim, TIMIO_CH1, 500);
    timerSetCaptureComparePreloadValue(tim, TIMIO_CH1, 500);
    timerEnableCaptureCompareChannel(tim, TIMIO_CH1);
    timerEnableCaptureCompareComplementaryChannel(tim, TIMIO_CH1);
    timerBdtrClearRegister(tim);
    timerSetBreakAndDeadTime(tim, 0xFF);
    timerBdtrEnableMainOutput(tim, MOE_ON);     // TIM8: Main-Output aktivieren
    timerSelectOutputCompareCenterAlignMode(tim, CENTER_ALIGN_1);
    timerSetCaptureCompareClkRatio(tim, TIMIO_CH1, CKD_4);
    timerStartTimer(tim);

#else           // Ende der MCAL-Version, Beginn: Direkte Registerprogrammierung

    // Konfiguration von GPIOA / Pin 5 (Komplementaer-Ausgang)
    RCC->AHB1ENR  |= RCC_AHB1ENR_GPIOAEN;      // GPIOA: Bustakt aktivieren
    port1->MODER  &= ~(GPIO_MODER_MODER5_Msk); // PA5  : Resetzustand
    port1->MODER  |= GPIO_MODER_MODER5_1;      // PA5  : Alt. Funktion
    port1->AFR[0] &= ~GPIO_AFRL_AFSEL5_Msk;    // PA5  : AF reset
    port1->AFR[0] |= (GPIO_AFRL_AFSEL5_1 | GPIO_AFRL_AFSEL5_0); // PA5: AF 3

    //    // Konfiguration von GPIOC / Pin 6 (Nicht-invertierender Ausgang)
    RCC->AHB1ENR  |= RCC_AHB1ENR_GPIOCEN;      // GPIOC: Bustakt aktivieren
    port2->MODER  &= ~(GPIO_MODER_MODER6_Msk); // PC6  : Resetzustand
    port2->MODER  |= GPIO_MODER_MODER6_1;      // PC6  : Alt. Funktion
    port2->AFR[0] &= ~GPIO_AFRL_AFSEL6_Msk;    // PC6  : AF reset
    port2->AFR[0] |= (GPIO_AFRL_AFSEL6_1 | GPIO_AFRL_AFSEL6_0); // PC6: AF 3

    // Konfiguration von TIM8
    RCC->APB2ENR |= RCC_APB2ENR_TIM8EN;        // TIM8: Bustakt aktivieren
    tim->PSC     = (16 - 1);                   // TIM8: Prescaler, Takt = 1MHz
    tim->ARR     = (1000 - 1);                 // TIM8: Auto-Reload-Wert
    tim->CNT     = 0;                          // TIM8: Counter reset

    // TIM8: Kanal 1 --> Betriebsart = PWM-Mode 1
    tim->CCMR1 &= ~(TIM_CCMR1_CC1S_Msk | TIM_CCMR1_OC1M_Msk);
    tim->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; // TIM8: CH1 = PWM-Mode 1
    tim->CCR1  =  (500 - 1);                   // TIM8: Preload-Wert
    tim->CCER  |= TIM_CCER_CC1E;               // TIM8: CH1 aktivieren
    tim->CCER  |= TIM_CCER_CC1NE;              // TIM8: Kompl. CH1 aktivieren
    tim->BDTR  = 0xFF;                         // TIM8: Deadtime (DTG) einstellen
    tim->BDTR  |= TIM_BDTR_MOE;                // TIM8: Main-Output aktivieren
    tim->CR1   |= TIM_CR1_CMS_0;               // TIM8: Akt. Center-Align-Mode 1
    tim->CR1   &= ~TIM_CR1_CMS_1;              // Fortsetzung der letzten Zeile
    tim->CR1   &= ~TIM_CR1_CKD_Msk;            // TIM8: Reset CKD-Bits
    tim->CR1   |= TIM_CR1_CKD_1;               // TIM8: CKD = 4
    tim->CR1   |= TIM_CR1_CEN;                 // TIM8: Timer starten

#endif          // Ende: Direkte Registerprogrammierung


    while (1)
    {

    }
}

