/***************************************************************************//**
 *   @file   ADC10bitsDrv.c
 *   @brief  Initialisation des périphériques de l'ADC
 *   @author Kévin MARCHAND(Kevin.marchand@intelligence-electronique.com)
********************************************************************************
 * Copyright 2014(c) PLCD, Inc.
 *
 * Initialisation des périphériques gérant l'echantillonnage et le buffering
 * de l'acquisition des entrées analogique AN1 et AN2 (AN20 et AN21 du microcontrolleur).
 *
********************************************************************************
 *   SVN Revision: 1
*******************************************************************************/

/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#if defined(__dsPIC33E__)
#include "p33exxxx.h"
#elif defined(__PIC24E__)
#include "p24exxxx.h"
#endif

#include "ADC10bitsDrv.h"
#include "MODBUSTCPServer.h"
#include "Process.h"

/******************************************************************************/
/************************ Variables Declarations ******************************/
/******************************************************************************/

extern WORD INPUT_REG[INPUT_REG_SIZE];

// Number of locations for ADC buffer = 32 (AN0 to AN31) x 8 = 256 words
// Align the buffer to 128 words or 256 bytes. This is needed for peripheral indirect mode
#ifdef __HAS_DMA__
__eds__ int BufferA[MAX_CHNUM + 1][SAMP_BUFF_SIZE] __attribute__((space(dma),eds,aligned(256)));
__eds__ int BufferB[MAX_CHNUM + 1][SAMP_BUFF_SIZE] __attribute__((space(dma),eds,aligned(256)));
#else
int BufferA[MAX_CHNUM+1][SAMP_BUFF_SIZE] __attribute__((space(xmemory),aligned(256)));//__attribute__((space(dma),aligned(256)));
int BufferB[MAX_CHNUM+1][SAMP_BUFF_SIZE] __attribute__((space(xmemory),aligned(256)));//__attribute__((space(dma),aligned(256)));
#endif
unsigned int DmaBufferSwitch = 0;


/***************************************************************************//**
 * @brief Initialisation de l'ADC1 pour scanné le Channel 0.
 * @details Configuration de l'ADC1 avec les entrées AN20 et AN21 rythmé
 * par le Timer3. Résolution 10-bit.
 * @param none.
 * @return none.
*******************************************************************************/
void InitAdc1(void)
{
    AD1CON1bits.FORM   = 0;		// Data Output Format: 0=Integer 3=Signed Fraction (Q15 format)
    AD1CON1bits.SSRC   = 2;		// Sample Clock Source: Timer3 compare ends sampling and starts conversion
    AD1CON1bits.ASAM   = 1;		// ADC Sample Control: Sampling begins immediately after conversion
    AD1CON1bits.AD12B  = 0;		// 10-bit ADC operation

    AD1CON2bits.VCFG = 1;               // Converter Voltage Reference VrefH=VREF+ VrefL=AVSS
    AD1CON2bits.CSCNA = 1;		// Scan Input Selections for CH0+ during Sample A bit
    AD1CON2bits.CHPS  = 0;		// Converts CH0

    AD1CON3bits.ADRC = 0;		// ADC Clock is derived from Systems Clock
    AD1CON3bits.ADCS = 63;		// ADC Conversion Clock Tad=Tcy*(ADCS+1)= (1/40M)*64 = 1.6us (625Khz)
                                        // ADC Conversion Time for 10-bit Tc=12*Tab = 19.2us

    AD1CON1bits.ADDMABM = 0;            // DMA buffers are built in scatter/gather mode
    AD1CON2bits.SMPI    = (NUM_CHS2SCAN - 1);	// 2 ADC Channel is scanned
    AD1CON4bits.DMABL   = 3;            // Each buffer contains 8 words
    AD1CON4bits.ADDMAEN = 1;            // Conversion results stored in ADCxBUF0 register

    //AD1CSSH/AD1CSSL: A/D Input Scan Selection Register
    AD1CSSL = 0x0000;
    AD1CSSHbits.CSS20=1;		// Enable AN20 for channel scan
    AD1CSSHbits.CSS21=1;		// Enable AN21 for channel scan

    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

}

/***************************************************************************//**
 * @brief Initialisation du Timer 3.
 * @details Le Timer 3 est configuré pour un time-out toutes les 125 microsecondes 
 * (8Khz Rate). En conséquence, le module ADC va effectuer une conversion sur chaque 
 * time-out du Timer 3, c'est-à-Ts = 125uS.
 * @param none.
 * @return none.
*******************************************************************************/
void InitTmr3()
{
    TMR3 = 0x0000;
    PR3  = 7499;		// Trigger ADC1 every 125usec
    IFS0bits.T3IF = 0;		// Clear Timer 3 interrupt
    IEC0bits.T3IE = 0;		// Disable Timer 3 interrupt
    T3CONbits.TON = 1;		//Start Timer 3

    //pour TEST !!!
    //T3CONbits.TCKPS=3;
}

/***************************************************************************//**
 * @brief Configuration du DMA0.
 * @details Lit à partir de l'adresse (ADC1BUF0) et écrire dans la RAM DMA 
 * AMODE : Mode d'adressage indirect du périphérique.
 * MODE: Le mode de ping-pong continue.
 * IRQ : Interruption ADC.
 * @param none.
 * @return none.
*******************************************************************************/
void InitDma0(void)
{
    DMA0CONbits.AMODE = 2;			// Configure DMA for Peripheral indirect mode
    DMA0CONbits.MODE  = 2;			// Configure DMA for Continuous Ping-Pong mode
    DMA0PAD=(int)&ADC1BUF0;
    DMA0CNT = (SAMP_BUFF_SIZE*NUM_CHS2SCAN)-1;
    DMA0REQ = 13;				// Select ADC1 Convert Done as DMA Request source

    #ifdef __HAS_DMA__
    DMA0STAL = __builtin_dmaoffset(&BufferA);
    DMA0STAH = __builtin_dmapage(&BufferA);

    DMA0STBL = __builtin_dmaoffset(&BufferB);
    DMA0STBH = __builtin_dmapage(&BufferB);
    #else
    DMA0STAL = (unsigned int)&BufferA;
    DMA0STAH = (unsigned int)&BufferA;

    DMA0STBL = (unsigned int)&BufferB;
    DMA0STBH =(unsigned int)&BufferB;
    #endif

    IFS0bits.DMA0IF = 0;	// Clear the DMA interrupt flag bit
    IEC0bits.DMA0IE = 1;	// Set the DMA interrupt enable bit
    DMA0CONbits.CHEN=1;		// Enable DMA
}


/***************************************************************************//**
 * @brief Appelé par l'interruption, elle permet de traiter les échantillons.
 * @param NoChannel - numéro de l'entrée analogique.
 * @param AdcBuffer - pointeur sur le buffer de <b>SAMP_BUFF_SIZE</b> échantillons.
 * @return none.
*******************************************************************************/
void ProcessADCSamples(unsigned char NoChannel, __eds__ int * AdcBuffer)
{
char            reponse[85];
unsigned int    moyenne = 0;
int             cptSample;
float           corrPenteAna;
float           interf;

// EXEMPLE D'opération : Calcul de la moyenne des échantillons
for (cptSample=0; cptSample<SAMP_BUFF_SIZE; cptSample++)
    moyenne += *AdcBuffer++;
moyenne = moyenne/SAMP_BUFF_SIZE;

if (NoChannel == NUM_AN1)
{
    INPUT_REG[11] = (WORD)moyenne;
    //sprintf(reponse,"AN1 moy : %04X\r\n",moyenne);
}
else
    if(NoChannel == NUM_AN2)
    {
        INPUT_REG[12] = (WORD)moyenne;
        //sprintf(reponse,"AN2 moy : %04X\r\n",moyenne);
    }
//putsUART2 ((unsigned int *)reponse);
//while(BusyUART2());

// Gestion des entrées analogiques
if (PAR.EntreeANA[1] == 33)                                                     // Consigne analogique
{
    interf = INPUT_REG[11];
    if (PAR.TypeEntreeANA[1] == 2)                                              // Si 4-20mA
            interf = (interf - 180 - PAR.OrigineEntreeANA[1]) * 1.25;
    if (interf < 0) interf = 0;
    
    interf = interf * PAR.ConsigneAnaMax / 1024;  
    corrPenteAna = PAR.CoeffEntreeAna[1]; corrPenteAna /= 10000;
    interf = interf * corrPenteAna;
        
    PAR.ConsigneAna = (PAR.ConsigneAna*9 + interf)/10;
}

if (PAR.EntreeANA[2] == 33)                                                     // Consigne analogique
{
    interf = INPUT_REG[12];
    if (PAR.TypeEntreeANA[2] == 2)                                              // Si 4-20mA
            interf = (interf - 180 - PAR.OrigineEntreeANA[2]) * 1.25;
    if (interf < 0) interf = 0;
    
    interf = interf * PAR.ConsigneAnaMax / 1024;  
    corrPenteAna = PAR.CoeffEntreeAna[2]; corrPenteAna /= 10000;
    interf = interf * corrPenteAna;
        
    PAR.ConsigneAna = (PAR.ConsigneAna*9 + interf)/10;
}
}







