/**
 * Kap13-Einfaches-DAC-Projekt
 * ===========================
 *
 * Dieses Beispiel stellt einen einfachen Generator fuer sogenannte Dreieck-
 * Signale dar. Es nutzt zwei Kanaele, deren Phase gegeneinander verschoben
 * ist.
 *
 * Anmerkung:
 * ----------
 * Das Projekt ist bereits fuer den Einsatz der MCAL vorbereitet, wird von ihr
 * aber nur teilweise unterstuetzt: Derzeit fehlen noch DAC-Funktionen, die
 * aber später noch hinzugefuegt werden. Derzeit werden nur die GPIO-Funktionen
 * der MCAL genutzt.
 */

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

/**
 * Kommentar in Zeile 24 entfernen, wenn Sie die MCAL (nur GPIO) testen möchten.
 */
//#define MCAL


#define DAC_MAX_VAL_12_BIT      (4095)

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

int main(void)
{
    uint16_t dac1Data     = 0;
    uint16_t dac2Data     = DAC_MAX_VAL_12_BIT;
    bool     dac1RampUp   = true;
    bool     dac2RampDown = false;

#ifdef MCAL     // Beginn der MCAL-Version

    gpioSelectPort(GPIOA);                      // GPIOA : Bustakt aktivieren
    gpioSelectPinMode(GPIOA, PIN4, ANALOG);     // PA4   : Analog
    gpioSelectPinMode(GPIOA, PIN5, ANALOG);     // PA5   : Analog

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

    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;        // GPIOA: Bustakt aktivieren

    // PA4: Konfiguration. PA4 wird im Analog-Modus betrieben (0b11)
    GPIOA->MODER &= ~GPIO_MODER_MODER4_Msk;
    GPIOA->MODER |= (GPIO_MODER_MODER4_1 | GPIO_MODER_MODER4_0);

    // PA5: Konfiguration. PA5 wird im Analog-Modus betrieben (0b11)
    GPIOA->MODER &= ~GPIO_MODER_MODER5_Msk;
    GPIOA->MODER |= (GPIO_MODER_MODER5_1 | GPIO_MODER_MODER5_0);

#endif          // Ende: Direkte Registerprogrammierung

    /*****************************************
     * Reine Bare-Metal-Version fuer den DAC *
     **************************************/
    RCC->APB1ENR |= RCC_APB1ENR_DACEN;          // DAC   : Bustakt aktivieren
    DAC->CR      |= DAC_CR_EN1;                 // DAC   : Kanal 1 aktivieren
    DAC->CR      |= DAC_CR_EN2;                 // DAC   : Kanal 2 aktivieren

    while (1)
    {
        /**
         * Dreiecksignale an Ausgang 1 generieren
         */
        if (true == dac1RampUp)
        {
            DAC->DHR12R1 = dac1Data++ & 0x0FFF;

            if (dac1Data > DAC_MAX_VAL_12_BIT)
            {
                dac1RampUp = false;
            }
        }
        else
        {
            DAC->DHR12R1 = dac1Data-- & 0x0FFF;
            if (dac1Data <= 0)
            {
                dac1RampUp = true;
            }
        }

        /**
         * Dreiecksignale an Ausgang 2 generieren. Das Ausgangssignal
         * ist hier um 90° verschoben.
         */
        if (true == dac2RampDown)
        {
            DAC->DHR12R2 = dac2Data-- & 0x0FFF;
            if (dac2Data <= 0)
            {
                dac2RampDown = false;
            }
        }
        else
        {
            DAC->DHR12R2 = dac2Data++ & 0x0FFF;
            if (dac2Data >= DAC_MAX_VAL_12_BIT)
            {
                dac2RampDown = true;
            }
        }
    }

    return 0;
}
