/*******************************************************************************
    main file

  Company:
    Microchip Technology Inc.

  File Name:
    main.c

  Summary:
    Calls all the ADC and DMA functions

  Description:
    This file has the main function that calls the ADC init and DMA init and adcdrv2 
    function that configures the ADC to a particular mode of operation. The main file 
    also has macros to configure the clock source for the device.
 *******************************************************************************/

// *****************************************************************************
// Section: Included Files
// *****************************************************************************
#include <xc.h>
#include "tglpin.h"

// User Defines
//#define FCY         70000000        // User must calculate and enter FCY here
#define NUMSAMP 16 // Number of Samples to Buffer until DMA Interrupt

// *****************************************************************************
// *****************************************************************************
// Section: File Scope or Global Constants
// *****************************************************************************
// *****************************************************************************
/* This section defines the input and the output buffers having an integer data type.
The input buffers are stored in either the extended data space or the x-memory area
depending on whether the extended data space (EDS) is available in the given dsPIC33E device.
 */

__eds__ int bufferA[NUMSAMP] __attribute__( (eds, space(dma)) );
__eds__ int bufferB[NUMSAMP] __attribute__( (eds, space(dma)) );

//void        ProcessADCSamples( __eds__ int *adcBuffer );

unsigned int adc_messwert = 0;
unsigned int PWM_PERIOD=2800;   //The PWM period can be computed using the following equation: PWM_PERIOD = FOSC/(FPWM*PWMInputClockPrescaler)       
float DC =0.02;
float DC1=0.02;
float DC2=0.02;
float DC3=0.02;
float DC4=0.02;
float DC5=0.02;
unsigned int    dmaBuffer = 0;

/******************************************************************************
 * Function:        void InitPWM(void)
 *
 * Overview:        
 *****************************************************************************/

void InitPWM (void)
{   
    PTCON = 0; // PWM Aussschalten während der Konfiguration
    SEVTCMP = DC/2; // Special Event Trigger value set at ~DC/2
    PTCONbits.SEVTPS = 1; // Special Event Trigger output postscalerset to 1:1 selection (trigger generated every PWM cycle 
    PTCON2 = 0; //Vollgas (max Freq)
    PTPER = PWM_PERIOD;

    SEVTCMP = 0;

    // Config PWM1
    PWMCON1bits.ITB = 0;    //  PTPER stellt Timing für den PWM Generator
    PWMCON1bits.MDCS = 0;   //  PTPER stellt Info zum Tastgrad ->Each channel will have a different duty
    PWMCON1bits.DTC = 0;    //  Positive Totzeit
    PWMCON1bits.IUE = 1;    //  DC wird SOFORT übernommen (bei 0 erst synchon mit PWM-Master-Clock)
    PDC1 = (PWM_PERIOD*DC1); // It selects the duty cycle
    PHASE1 = 0;
    SPHASE1 = 0;            //Keine Phasenverschiebung zwischen Low und High!   
    IOCON1 = 0;
    IOCON1bits.PENH = 1; // PWM Modul steuert PWMxH Pin
    IOCON1bits.PENL = 1; // PWM Modul steuert PWMxL Pin
    IOCON1bits.POLH = 0; // Pin activ high
    IOCON1bits.PMOD = 0; // Complemanty Output Mode

    // Config PWM2 (Shorter)
    PWMCON2 = 0x0001; // u.A.: PDCx and SDCx registers provide dc information for PWM generator
    PDC2 = (PWM_PERIOD*DC2); // It selects the duty cycle --> Sofern der nicht überall gleich es, ruhig hier auch setzen
    PHASE2 = PWM_PERIOD/5; //   Die Phase muss natürlch eingestellt werden
    IOCON2 = 0xC000;

    // Config PWM3 (Shorter) 
    PWMCON3 = 0x0001; // u.A.: PDCx and SDCx registers provide dc information for PWM generator
    PDC3 = (PWM_PERIOD*DC3); // It selects the duty cycle --> Sofern der nicht überall gleich es, ruhig hier auch setzen
    PHASE3 = PWM_PERIOD/5*2; //   Die Phase muss natürlch eingestellt werden
    IOCON3 = 0xC000;

    // Config PWM4 (Shorter)
    PWMCON4 = 0x0001; // u.A.: PDCx and SDCx registers provide dc information for PWM generator
    PDC4 = (PWM_PERIOD*DC4); // It selects the duty cycle --> Sofern der nicht überall gleich es, ruhig hier auch setzen
    PHASE4 = PWM_PERIOD/5*3; //   Die Phase muss natürlch eingestellt werden
    IOCON4 = 0xC000;
    
    // Config PWM5(Shorter)
    PWMCON5 = 0x0001; // u.A.: PDCx and SDCx registers provide dc information for PWM generator
    PDC5 = (PWM_PERIOD*DC5); // It selects the duty cycle --> Sofern der nicht überall gleich es, ruhig hier auch setzen
    PHASE5 = PWM_PERIOD/5*4; //   Die Phase muss natürlch eingestellt werden
    IOCON5 = 0xC000;

    //Same for all PWMs
    DTR1 = DTR2 = DTR3 = DTR4 = DTR5 = 14; //Deadtime (für steigende High-Flanke))
    ALTDTR1 = ALTDTR2 = ALTDTR3 = ALTDTR4 = ALTDTR5 = 14;    // Alternate Deadtime (für fallende High-Flanke))

    LATAbits.LATA0 = 1; // Turn on LED D3  --> PWM INIT successful
}

/******************************************************************************
 * Function:        void InitAdc1(void)
 *
 * Overview:        This function is used to configure A/D to convert channel 5 on Timer event.
 *                  It generates event to DMA on every sample/convert sequence. ADC clock is configured at 625Khz.
 *****************************************************************************/
void InitAdc1( void )
{
    AD1CON1bits.FORM = 0;       // 0=Integer, 1=Signed Integer        //  Data Output Format: 3: Signed Fraction (Q15 format)
    AD1CON1bits.SSRCG= 0;      // 1:PWM Gen X Beendet Sampling und startet die Conv (SSRC wählt welcher Gen) /-/ 2 Andere Funktion Beendet Sampling und startet die Conv
    AD1CON1bits.SSRC = 7;       // 7 Interan Counter (SAMC) ends sampling and starts convertion // 3 PWM -  PWM primary Special Event Trigger ends sampling and starts conversion
    AD1CON1bits.ASAM = 1;       // ADC Sample Control: Sampling begins immediately after conversion
    AD1CON1bits.AD12B= 0;      // 10-bit ADC operation
    AD1CON2bits.CHPS = 1;       // 0: Converts CH0  //   1 for: CH0 and CH1
    AD1CON3bits.ADRC = 0;       // ADC Clock is derived from Systems Clock
    AD1CON3bits.SAMC = 0;       // Auto Sample Time = 0*Tad
    AD1CON3bits.ADCS = 6;       // ADC Conversion Clock Tad=Tcy*(ADCS+1)= (1/70M)*7 = 100ns (10.0Mhz)
      
    // ADC Conversion Time for 10-bit Tc=12*Tab =  900ns (1.1MHz)
    AD1CON1bits.ADDMABM = 1;    // 1: DMA buffers are built in conversion order mode ([0]1, [1]=2, [3]=1.. //0 Scatter gather mode
    AD1CON2bits.SMPI = 0;       // SMPI must be 0
    AD1CON4bits.ADDMAEN = 1;    // Converts in ADC1BUF0

    // AD1CHS0/AD1CHS123: A/D Input Select Register
    AD1CHS0bits.CH0SA = 0;    // MUXA +ve input selection (AIN0) for CH0
    AD1CHS0bits.CH0SA = 5;      // MUXA +ve input selection (AIN5) for CH0
    AD1CHS0bits.CH0NA = 0;      // MUXA -ve input selection (Vref-) for CH0
    AD1CHS123bits.CH123SA = 0;  // MUXA +ve input selection (AIN0) for CH1
    AD1CHS123bits.CH123NA = 0;  // MUXA -ve input selection (Vref-) for CH1
    IFS0bits.AD1IF = 0;         // Clear the A/D interrupt flag bit
    IEC0bits.AD1IE = 0;         // Do Not Enable A/D interrupt
    AD1CON1bits.ADON = 1;       // Turn on the A/D converter
    TglPinInit();
}

/******************************************************************************
 * Function:        void InitDma0(void)
 *
 * Overview:        DMA0 configuration function.
                    Direction: Read from peripheral address 0-x300 (ADC1BUF0) and write to DMA RAM
                    AMODE: Register indirect with post increment
                    MODE: Continuous, Ping-Pong Mode
                    IRQ: ADC Interrupt
                    ADC stores results stored alternatively between DMA_BASE[0]/DMA_BASE[16] on every
                    16th DMA request
 *****************************************************************************/
void InitDma0( void )
{
    DMA0CONbits.AMODE = 0;  // Configure DMA for Register indirect with post increment
    DMA0CONbits.MODE = 2;   // 2 Configure DMA for Continuous Ping-Pong mode
        
    DMA0PAD = ( int ) &ADC1BUF0; // Point DMA to ADC1BUF
    DMA0CNT = ( NUMSAMP - 1 ); // Interrupt auf NUMSAMP Transfers

    DMA0REQ = 13; // ADC1 ? ADC1 Convert Done

    DMA0STAL = __builtin_dmaoffset( &bufferA );
    DMA0STAH = __builtin_dmapage( &bufferA );

    DMA0STBL = __builtin_dmaoffset( &bufferB );
    DMA0STBH = __builtin_dmapage( &bufferB );


    IFS0bits.DMA0IF = 0;    //Clear the DMA interrupt flag bit
    IEC0bits.DMA0IE = 1;    //Set the DMA interrupt enable bit
    DMA0CONbits.CHEN = 1;
}



/******************************************************************************
 * Function:        void ProcessADCSamples(__eds__ int16_t * adcBuffer)
 *
 * Overview:        This function is just a prototype which can be used to perform
 *                  some activity on the samples taken by the ADC.
 *****************************************************************************/
void ProcessADCSamples( __eds__ int *adcBuffer )
{
    /* Do something with ADC Samples */
    int avg=0;
    avg=(adcBuffer[2]); //+adcBuffer[4]+adcBuffer[6])/3;
    adc_messwert= avg;
    IEC0bits.DMA0IE = 1;    //Set the DMA interrupt enable bit
 }

/******************************************************************************
 * Function:        void __attribute__((interrupt, auto_psv)) _DMA0Interrupt(void)
 *
 * Overview:        Depending on the dmaBuffer value, the data in bufferA or bufferB is passed
 *****************************************************************************/
void __attribute__ ( (interrupt, auto_psv) ) _DMA0Interrupt( void )
{
    DMA0CONbits.CHEN=0; //Disable DMA
    
    if( dmaBuffer == 0 )
    {
        ProcessADCSamples( bufferA );
    }
    else
    {
        ProcessADCSamples( bufferB );
    }
   
    dmaBuffer ^= 1;
    TglPin();               // Toggle RA4 -> LED D7
    IFS0bits.DMA0IF = 0;    // Clear the DMA0 Interrupt Flag
    DMA0CONbits.CHEN=1; //Enable DMA
  }

/******************************************************************************
 ******************************************************************************
 * Function:        int main(void)
 *
 * Overview:        Main function
 ******************************************************************************
 *****************************************************************************/

int main(void)
//#endif
{
    // *****************************************************************************
    // Section: DSPIC33EP512MU810 Configuration Bit Settings
    // *****************************************************************************

    // FGS
    #pragma config GWRP = OFF               // General Segment Write-Protect bit (General Segment may be written)
    #pragma config GSS = OFF                // General Segment Code-Protect bit (General Segment Code protect is disabled)
    #pragma config GSSK = OFF               // General Segment Key bits (General Segment Write Protection and Code Protection is Disabled)

    // FOSCSEL
    #pragma config FNOSC = PRIPLL           // Initial Oscillator Source Selection Bits (Primary Oscillator (XT, HS, EC) with PLL)
    #pragma config IESO = OFF               // Two-speed Oscillator Start-up Enable bit (Start up with user-selected oscillator source)

    // FOSC
    #pragma config POSCMD = XT              // Primary Oscillator Mode Select bits (XT Crystal Oscillator Mode)
    #pragma config OSCIOFNC = OFF           // OSC2 Pin Function bit (OSC2 is clock output)
    #pragma config IOL1WAY = OFF            // Peripheral pin select configuration (Allow multiple reconfigurations)
    #pragma config FCKSM = CSECMD           // Clock Switching Mode bits (Clock switching is enabled,Fail-safe Clock Monitor is disabled)

    // FWDT
    #pragma config WDTPOST = PS32768        // Watchdog Timer Postscaler Bits (1:32,768)
    #pragma config WDTPRE = PR128           // Watchdog Timer Prescaler bit (1:128)
    #pragma config PLLKEN = ON              // PLL Lock Wait Enable bit (Clock switch to PLL source will wait until the PLL lock signal is valid.)
    #pragma config WINDIS = OFF             // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
    #pragma config FWDTEN = OFF             // Watchdog Timer Enable bit (Watchdog timer enabled/disabled by user software)

    // FPOR
    #pragma config FPWRT = PWR128           // Power-on Reset Timer Value Select bits (128ms)
    #pragma config BOREN = ON               // Brown-out Reset (BOR) Detection Enable bit (BOR is enabled)
    #pragma config ALTI2C1 = ON             // Alternate I2C pins for I2C1 (ASDA1/ASCK1 pins are selected as the I/O pins for I2C1)
    #pragma config ALTI2C2 = ON             // Alternate I2C pins for I2C2 (ASDA2/ASCK2 pins are selected as the I/O pins for I2C2)

    // FICD
    #pragma config ICS = PGD1               // ICD Communication Channel Select bits (Communicate on PGEC1 and PGED1)
    #pragma config RSTPRI = PF              // Reset Target Vector Select bit (Device will obtain reset instruction from Primary flash)
    #pragma config JTAGEN = OFF             // JTAG Enable bit (JTAG is disabled)

    // FAS
    #pragma config AWRP = OFF               // Auxiliary Segment Write-protect bit (Auxiliary program memory is not write-protected)
    #pragma config APL = OFF                // Auxiliary Segment Code-protect bit (Aux Flash Code protect is disabled)
    #pragma config APLK = OFF               // Auxiliary Segment Key bits (Aux Flash Write Protection and Code Protection is Disabled)

    // *****************************************************************************
    // End of: DSPIC33EP512MU810 Configuration Bit Settings
    // *****************************************************************************
    
    // Disable Watch Dog Timer
    RCONbits.SWDTEN = 0;

    // Peripheral Initialisation
     /* Configure Oscillator to operate the device at 140Mhz */
    // Fosc= Fin*M/(N1*N2), Fcy=Fosc/2
    // Fosc= 8 MHz*70/(2*2)=140Mhz for 8 MHz input clock -> Maximum!
    PLLFBD=68;     // M=70
    CLKDIVbits.PLLPOST=0;  // N1=2
    CLKDIVbits.PLLPRE=0;  // N2=2
    
    // PORT C
    LATCbits.LATC1 = 0; // Die PWM-H Pins müssen erstmal auf low 
    LATCbits.LATC2 = 1; // Die PWM-L Pins können schon mal high gestzt werden 
    
    // PORT E
    // PWM-H Pins set low 
    LATEbits.LATE1 = 0; 
    LATEbits.LATE3 = 0;
    LATEbits.LATE5 = 0;
    LATEbits.LATE7 = 0;
    TRISE = 0x0000; // OUTPUT
    
    // PWM-L Pins set high
    LATEbits.LATE0 = 1; 
    LATEbits.LATE2 = 1;
    LATEbits.LATE4 = 1;
    LATEbits.LATE6 = 1;
  	TRISC = 0x0000; // OUTPUT
    
     /* Enable LEDs --> als Ausgang setzen*/
    TRISAbits.TRISA6 = 0 ; //LED D9 ist Output
    TRISAbits.TRISA7 = 0 ; //LED D10 ist Output
    TRISAbits.TRISA0 = 0 ; //LED D3 ist Output
  
    InitDma0(); // Initialise the DMA controller to buffer ADC data in conversion order
    InitAdc1(); // Initialize the A/D converter to convert Channel 5
    InitPWM();  //  Initialize the 5 "Channel" PWM function

    TRISDbits.TRISD13 = 1 ; // Btn3 Enable -> Ist input
                                                              
    PTCONbits.PTEN = 1; // PWM aktivieren
    LATAbits.LATA7 = 1; // LED D3 einschalten --> Alles INITs abgeschlossen, PWM aktiviert
    TRISAbits.TRISA6 = 0 ; //LED -> Ausgang -> Blinken

    
    while(1)//Loop Endlessly 
    {
        LATAbits.LATA6 ^= 1 ;
                
        //adc_messwert=ADC_Read10bit(5); //ADC Messwert=10bit =1024 //Eingelesen: 31...1023
        DC=(adc_messwert+110)/2;    //dc = 5%=140 ... 20%=560 -> Deadtime not considered yet
        PDC1=PDC2=PDC3=PDC4=PDC5=DC;
    };
 }