/**
 * Kap14-Einfaches ADC-Projekt
 * ===========================
 *
 * Am Abgriff eines Potentiometers wird eine Spannung, die zwischen 0 und 3,3V
 * liegt, abgegriffen und GPIOA/Pin 1 zugefuehrt.
 */

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

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

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

int main(void)
{
    GPIO_TypeDef  *port   = GPIOA;
    ADC_TypeDef   *adc    = ADC1;

    uint16_t       result = 0;


#ifdef MCAL     // Beginn der MCAL-Version

    // Liste der ADC-Kanaele in einer Sequenz
    ADC_CHANNEL_t chnList[] = { ADC_CHN_0 };

    // Anzahl der Listenelemente berechnen
    size_t         listSize = sizeof(chnList) / sizeof(chnList[0]);

    gpioSelectPort(port);                  // GPIOA: Bustakt aktivieren
    gpioSelectPinMode(port, PIN5, OUTPUT); // Verwendung der Onboard-LED

    adcSelectADC(adc);                     // ADC1: Bustakt aktivieren
    gpioSelectPinMode(port, PIN1, ANALOG); // PA1 : Analog-Modus

    adcDisableADC(adc);                    // ADC1: Deaktivieren

    // Konfiguration der Sequenz und Eintrag der Laenge von chnList[]
    adcSetChannelSequence(adc, chnList, listSize);
    adcEnableADC(adc);

    while (1)
    {
        adcStartConversion(adc);

        while (!(adcIsConversionFinished(adc)))
        {
            ;
        }
        result = adcGetConversionResult(adc);

        if (result & 0x1FF)                // LED in Abhaengigkeit vom Resultat
        {
            gpioSetPin(port, PIN5);        // einschalten bzw.
        }
        else
        {
            gpioResetPin(port, PIN5);      // ausschalten
        }

    }

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

    // Konfiguration von GPIOA / Pin 5
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;    // GPIOA: Bustakt aktivieren
    port->MODER  &= ~GPIO_MODER_MODER5_Msk; // PA5: Reset auf Default-Wert
    port->MODER  |= GPIO_MODER_MODER5_0;    // PA5: Output

    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;     // ADC1: Bustakt aktivieren
    port->MODER  &= ~GPIO_MODER_MODER1_Msk; // PA1 : Reset auf Default-Wert
    port->MODER  |= (GPIO_MODER_MODER1_1 |  // PA1 : Analog-Modus
                     GPIO_MODER_MODER1_0);
    adc->CR2   = 0;
    adc->SQR3  |= ADC_SQR3_SQ1_0;           // Wir beginnen mit Kanal 1...
    adc->SQR1  |= ADC_SQR1_L_0;             // ... und setzen die Laenge auf 1
    adc->CR2   |= ADC_CR2_ADON;             // ADC aktivieren

    while (1)
    {
        adc->CR2 |= ADC_CR2_SWSTART;       // A/D-Wandlung wird gestartet
        while (!(adc->SR & ADC_SR_EOC))    // Warten, bis Konvertierung beendet
        {
            ;
        }
        result = adc->DR;                  // Konvertierte Daten abholen
        if (result & 0x1FF)                // LED in Abhaengigkeit vom Resultat
        {
            port->BSRR = GPIO_BSRR_BS5;    // einschalten bzw.
        }
        else
        {
            port->BSRR = GPIO_BSRR_BR5;    // ausschalten
        }
    }
#endif      // Ende: Direkte Registerprogrammierung


    return 0;
}
