#include "config.h"
#include "adc.h"
#include "timer.h"

/* Layout of buffer: 
   adc_dmabuf[x] contains 16 samples of channel AN0
*/
uint16_t adc_dmabuf[16] __attribute__((space(dma)));

/* Stores the offset of the most recently written DMA sample */
int adc_offset = 0;

void (*adc_adc_callback)(void) = 0;
void (*adc_dma_callback)(void) = 0;

/* ADC1 interrupt after each sample */
void __attribute__((__interrupt__,auto_psv)) _ADC1Interrupt(void)
{       
	static int next_adc_offset = 0;

	adc_offset = next_adc_offset;

	/* DMA0STA points to the next sample that will be written.
	   Convert that into a buffer offset that we'll for next time */
	next_adc_offset = (DMA0STA - __builtin_dmaoffset(adc_dmabuf)) >> 1;

	IFS0bits.AD1IF = 0;
	if (adc_adc_callback)
		(*adc_adc_callback)();
}

/* DMA0 interrupt after 16 samples */
void __attribute__((__interrupt__,auto_psv)) _DMA0Interrupt(void)
{
	IFS0bits.DMA0IF = 0;
	if (adc_dma_callback)
		(*adc_dma_callback)();
}

/* Initialize ADC1 to constantly DMA AN0. */
void adc_init(void)
{
	/* AD1CON1 */
    AD1CON1bits.ADDMABM = 1;        /* Scatter-gather DMA */
	AD1CON1bits.AD12B = 1;          /* 12-bit, 1 channel */
    AD1CON1bits.FORM = 0;           /* Integer output 0000dddddddddddd */
    AD1CON1bits.SSRC = 2;           /* Convert on Timer3 */
    AD1CON1bits.ASAM = 1;           /* Automatically start sampling */
    AD1CON1bits.SIMSAM = 0;         /* Simul sampling, N/A when AD12B=1 */

    /* AD1CON2 */
    AD1CON2bits.VCFG = 0;           /* Ref: AVDD / AVSS */
//    AD1CON2bits.VCFG = 3;           /* Ref: VREF+ / VREF- */
    AD1CON2bits.CSCNA = 0;          /* Do not scan inputs on Mux A */
	AD1CON2bits.CHPS = 0;           /* Convert CH0 only, N/A when AD12B=1 */
    AD1CON2bits.SMPI = 0;           /* Increase DMA address at each sample */
    AD1CON2bits.BUFM = 0;           /* Fill buffer from start */
    AD1CON2bits.ALTS = 0;           /* Always use Mux A settings */

    /* AD1CON3 */
    AD1CON3bits.ADRC = 0;           /* Use system clock, not internal RC */
    AD1CON3bits.SAMC = 0;           /* Sample time, N/A when ADRC = 0 */
    AD1CON3bits.ADCS = 0x7;         /* Tad = 8 * Tcy */

    /* AD1CON4 */
    AD1CON4bits.DMABL = 4;          /* Each input gets 16 words in DMA buf */

    /* Channel 0 setup */
    AD1CHS0bits.CH0NA = 0;          /* CH0-: Vrefl */
    AD1CHS0bits.CH0SA = 0;          /* CH0+: AN0 */

	/* Set Timer3 to trigger conversion at 128KHz */
	timer_setup_16bit(3, 128000, 0);

    /* Turn it on */
    AD1PCFGL = 0xfffe;           	/* Analog = AN0 */
    AD1PCFGH = 0xffff;
    AD2PCFGL = 0xffff;
    AD1CON1bits.ADON = 1;

    /* DMA0 setup */
    DMA0CONbits.AMODE = 0;          /* Register indirect, post-increment */
    DMA0CONbits.MODE = 0;           /* Continuous, no ping-pong */
    DMA0PAD = (int)&ADC1BUF0;       /* Get addresses from ADC1 */
    DMA0CNT = 15;                   /* 16 transfers before wraparound */
    DMA0STA = __builtin_dmaoffset(adc_dmabuf);
    DMA0REQbits.IRQSEL = 13;        /* Triggered by ADC1 */
    IFS0bits.DMA0IF = 0;            
    IEC0bits.DMA0IE = 1;            /* DMA interrupt (every 16 samples) */
    DMA0CONbits.CHEN = 1;           /* enable this DMA channel */

    IFS0bits.AD1IF = 0;
    IEC0bits.AD1IE = 1;				/* ADC interrupt (every sample) */
}
