//
// ADC example with interrupt and timer
// By PEK '2007
//
// MCU: AT91SAM7S256
// Experiment board: AT91SAM7S-EK
//

#include "Board.h"

// Macros
#define SET_LED(x)  AT91C_BASE_PIOA->PIO_ODSR = (x)

// Definitions
#define INT_LEVEL_ADC   4           // Priority of interrupt
#define TIME_PERIOD     MCK/1024/5  // Period of 200 ms

// ADC EOC0 ISR
void adc_isr(void)
{
    unsigned int nAD;
    static unsigned int nFlag = 1;

    nAD = AT91F_ADC_GetConvertedDataCH0(AT91C_BASE_ADC);    // Get converted data from channel 0 and clear EOC0

    if(nFlag)
    {
        SET_LED(~(nAD >> 6));   // Show the four most significant bits
        nFlag = 0;
    }
    else
    {
        SET_LED(0xFF);  // Clear leds (then you can see the frequency of measurements)
        nFlag = 1;
    }
}

// Main
int main()
{
    // Setup PIO
    AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOA;  // Enable clock to PIO
    AT91C_BASE_PIOA->PIO_OER = LED_MASK;    // Output on PA1-PA3
    AT91C_BASE_PIOA->PIO_OWER = LED_MASK;   // Enable to set/clear PA0-PA3 with status register
    SET_LED(0xF); // Clear leds

    // Setup ADC
    AT91C_BASE_ADC->ADC_MR = AT91C_ADC_TRGEN_EN | AT91C_ADC_TRGSEL_TIOA0 | AT91C_ADC_LOWRES_10_BIT | AT91C_ADC_SLEEP_NORMAL_MODE | AT91C_ADC_PRESCAL | AT91C_ADC_STARTUP | AT91C_ADC_SHTIM; // TIOA0 as trigger, 10 bits, normal mode, max time
    AT91C_BASE_ADC->ADC_CHER = AT91C_ADC_CH0;   // Enable channel 0

    // Setup TC0
    AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0;   // Enable clock to TC0
    AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV5_CLOCK | AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_SET | AT91C_TC_ACPC_CLEAR;   // Prescaler set to 1024, Compare mode on RC, Change TIOA0 according to RA and RC
    AT91C_BASE_TC0->TC_RC = TIME_PERIOD;   // Compare value of RC, clear TIOA0 and reset timer
    AT91C_BASE_TC0->TC_RA = TIME_PERIOD/2;  // Compare value of RA, set TIOA0
    AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; // Enable timer

    // Setup interrupts
    AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_ADC, INT_LEVEL_ADC, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, adc_isr);
    AT91C_BASE_ADC->ADC_IER  = AT91C_ADC_EOC0;  //  IRQ enable EOC0
    AT91C_BASE_AIC->AIC_IECR = 1 << AT91C_ID_ADC;   // Enable interrupt in AIC

    AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;    // Start timer

    while(1);
}

