Test program for Spikes when measuring 2 channels in Timer1/MAT1:0 triggering mode.

Dependencies:   mbed

main.cpp

Committer:
wvd_vegt
Date:
2012-10-31
Revision:
2:74fd179377d9
Parent:
1:b6dcd0de2a17

File content as of revision 2:74fd179377d9:

#include "mbed.h"
#include "ADC/adc.h"

//NOTE Baudrate 115200
//     Writes a . and flahes led 2 after each conversion of 1000 points (see MAX_SAMPLES)
//
//     A spike is a point that deviates more that SpikeAmplitude of it neighbours (now 128).
//
//     Measured on AD0 and AD1 without anything connected (so a nice humm).
//
//     ADC Code that makes the difference is 'ADC adc(SAMPLE_RATE,1);' 
//     Without it I had spikes (altough not now hen testing).
//
//     ADC Code by sblandford (see ADC Folder). It is not used but 
//     certainly initializes something i missed.
//
//     Currently code runs nice with or without the ADC line! (but in my larger 
//     program the ADC line DID make the difference. 
//
//     This 'cure' only worked in combination with timer1/mat1:0 triggering
//     Using ADC:Read Fails (no matter how timer), as did teh GPDMA based code 
//     (Timer that schedules 2 channel DMA transfers at each interrupt).

//NOTE This Value can  be changed to alter the detection criteria.
#define SpikeAmplitude 128

DigitalOut myled1(LED1);
DigitalOut myled2(LED2);

//We'll be using the Usb Serial port
Serial usb(USBTX, USBRX); //tx, rx

//------------------------------------------------------------------------------
//----Hardware Arrays.
//------------------------------------------------------------------------------

//Define ADC array, Note p18 is used as DAC!
AnalogIn adcs[5] = {AnalogIn(p15), AnalogIn(p16), AnalogIn(p17), AnalogIn(p19), AnalogIn(p20)};

//Define DAC array
AnalogOut dac[1] = {AnalogOut(p18)};

//------------------------------------------------------------------------------
//----ALL ADC Methods
//------------------------------------------------------------------------------

#define XTAL_FREQ       12000000

//NOTE The Number of samples per call.
#define MAX_SAMPLES     1000

//NOTE Only used for the statement below, the sample-rate is 1ms or lower (by skipping points).
#define SAMPLE_RATE     150000

//NOTE THIS LINE CURES THE SPIKES !!
ADC adc(SAMPLE_RATE,1);

//Current Skip Rate Index. (not important, left in to keep code identical)
//Basically it allows me to skip points 'automatically' and thus have a varying sample time.
static int adc_rate = 0;

//Start with every 10th point, end with every point. (not important, left in to keep code identical)
static int adc_rates[2] = {1, 1};

//Stop with first skip rate at sample 5. -1 is forever. (not important, left in to keep code identical)
static int adc_skippoint[2] = {-1, -1};

//Always start with a sample. (not important, left in to keep code identical)
static int adc_skip = 1;

//Results and Timestamps
unsigned long Samples0[MAX_SAMPLES];
unsigned long Samples1[MAX_SAMPLES];
unsigned long Timing01[MAX_SAMPLES];

Timer adc_stamper;          //Timestamping Samples.
Timer match_timing;         //Total Sampling Time.

//------------------------------------------------------------------------------
//----CID_TIMER (MAT1.0 Based ADC Triggering)
//------------------------------------------------------------------------------

volatile uint32_t timer1hits =     0;       // timer1 stops when timer1hits==imer1loop
uint32_t match               =   500;       // 0.5ms (2Mhz/1000)
uint32_t prescaler           =  96-1;       // 96Mhz/96 = 1Mhz

//See http://mbed.org/forum/mbed/topic/1965/?page=1#comment-10043

//Manually start a conversion (and cause an interrupt).
//NOTE: CLKDIV can be change to alter the ADC Clock.
#define CLKDIV 1UL
#define START_CONVERSION_NOW(ch) \
    LPC_ADC->ADCR=(0x1<<24)|(1UL<<21)|(CLKDIV<<8)|ch;\
    NVIC_EnableIRQ(ADC_IRQn);\
    LPC_ADC->ADINTEN = 0x3

//Trigger ADC on falling edge of MAT1:0 (and have it cause an interrupt).
#define START_CONVERSION_TIMED(ch) \
    LPC_ADC->ADCR=(0x6<<24)|(1UL<<21)|(CLKDIV<<8)|ch;\
    NVIC_EnableIRQ(ADC_IRQn);\
    LPC_ADC->ADINTEN = 0x3;\
    LPC_TIM1->TCR=0;\
    LPC_TIM1->TCR=1

extern "C" void Adc_IRQHandler(void) __irq {
    //LPC_TIM1->MR0 = match-1;              //* Reload MR0 does not seem to be neccesary.
    LPC_TIM1->IR = 0x1UL;                   //* Re-eanbled

    Timing01[timer1hits]=adc_stamper.read_us();

    //TODO Toggle Channel Mask (01 to 01 in ADCR).
    //     Take twice the number of samples at half the sampling time
    //     So 2000 samples (1000+1000) at 0.5ms -> 1000 pairs in 1 sec.

    switch (LPC_ADC->ADSTAT & 0xFF) {
        case 0x01:
            Samples0[timer1hits] = LPC_ADC->ADDR0;// adc[0];
            START_CONVERSION_NOW(0x02);
            break;

        case 0x02:
            Samples1[timer1hits] = LPC_ADC->ADDR1;// adc[1];
            START_CONVERSION_TIMED(0x01);

            //Skip Samples to lower rates. Change adc_rate to change sample rate.
            adc_skip--;
            if (adc_skip==0) {
                if (adc_skippoint[adc_rate]!=-1 && timer1hits==adc_skippoint[adc_rate]) {
                    adc_rate++;
                }

                //Reload adc_skip
                adc_skip = adc_rates[adc_rate];

                timer1hits++;
            }

            if (timer1hits==MAX_SAMPLES) {
                match_timing.stop();

                NVIC_DisableIRQ(ADC_IRQn);

                LPC_TIM1->TCR = 0x00;        // Disable Timer
            }

            break;
    }
}

//*******************************
//NOTE: Timer1 Driven ADC.
//
//      Works but way to fast!!
//
//      Did not work previously because connected
//      to the wrong IRQ (should be the adc one).
//
//      Skips 1 usec every 2*10 samples.
//*******************************
int Measure() {
    int spikes=0;

    // Enable the ISR vector
    NVIC_SetVector(ADC_IRQn,  (uint32_t)&Adc_IRQHandler);

    // Set PCLK_TIMER1
    //                    PCLK_TIMER1 = CCLK/1 96M/1 = 96MHz
    LPC_SC->PCLKSEL0 &= ~(3UL << 4);   // Clear bits
    LPC_SC->PCLKSEL0 |=  (1UL << 4);   // Set bit

    LPC_SC->PCONP |= 1 << 2;      // Power on Timer 1

    LPC_TIM1->TCR  = 0x2UL;       // Reset and set to timer mode

    //NOTE match-2 is to much (seems like a clock is off somehwere).

    LPC_TIM1->CTCR = 0x0UL;       // Connect to prescaler
    LPC_TIM1->PR   = prescaler;   // Prescale -> 1Mhz
    LPC_TIM1->MR0  = match-1;     // Match count for 5mS (we toggle so end up with half)
    LPC_TIM1->MCR  = 2;           // Reset TCR to zero on match

    //See http://mbed.org/forum/mbed/topic/1965/?page=1#comment-10043
    LPC_TIM1->EMR  = (3UL<<4)|1;  // Make MAT1.0 toggle (see START_CONVERSION_TIMED MACRO).

    // veg - ADC Max Clock = 13MHz. One conversion takes 65cycles so 200Khz Sampling frequency!
    //       For nice exact values for a single conversion we need the ADC Clock to be a 65 fold (So overclock).

    // Power up the ADC and set PCLK
    LPC_SC->PCLKSEL0 &= ~(3UL << 16);           // PCLK = CCLK/4 96M/4 = 24MHz

    LPC_SC->PCONP    |=  (1UL << 12);           // Power on ADC
    LPC_ADC->ADCR    |=  (1UL << 21) | (CLKDIV<<8);    // * Enable ADC & Set Divider Sample Rate 24Mhz / CLKDIV+1

    // Set the pin functions to ADC
    LPC_PINCON->PINSEL1 &= ~(3UL << 14);        // P0.23, Mbed p15. (AD0)
    LPC_PINCON->PINSEL1 |=  (1UL << 14);
    LPC_PINCON->PINSEL1 &= ~(3UL << 16);        // P0.24, Mbed p16. (AD1)
    LPC_PINCON->PINSEL1 |=  (1UL << 16);

    memset(Samples0, 0, sizeof(Samples0));
    memset(Samples1, 0, sizeof(Samples1));

    // Enable the ADC, 12MHz,  ADC0.0,  ADC0.1 -> Macro/Defines!
    // LPC_ADC->ADCR  = (1UL << 21) | (1UL << 8) | (3UL << 0);

    //Reset Test Variable.
    timer1hits   = 0;

    //Reset Skip Rate.
    adc_rate     = 0;
    adc_skip     = 1;             // We start with a sample!

    adc_stamper.reset();
    adc_stamper.start();

    match_timing.reset();
    match_timing.start();

    START_CONVERSION_TIMED(0x01);

    //Pause until timer stops.
    while (LPC_TIM1->TCR==1) {
        wait(0.001);
    }

    //LPC_ADC->ADCR &= ~(7UL << 24);          // Clear ADC Start bits -> Macro/Defines!

    int elapsed = match_timing.read_us();

    match_timing.stop();

    adc_stamper.stop();

    for (int i=1; i < MAX_SAMPLES-1; i++) {

        int lv = (Samples0[i-1]>>4) & 0xFFF;
        int cv = (Samples0[i+0]>>4) & 0xFFF;
        int nv = (Samples0[i+1]>>4) & 0xFFF;

        if (((cv >= lv + SpikeAmplitude) && (cv >= nv + SpikeAmplitude)) ||
                ((cv <= lv - SpikeAmplitude) && (cv <= nv - SpikeAmplitude))) {
            usb.printf("\r\nSpike on Channel AD%d @ %d [%04u] [%04u] [%04u]\r\n", 0, i, lv, cv, nv);
            spikes++;
        }
    }

    for (int i=1; i < MAX_SAMPLES-1; i++) {

        int lv = (Samples1[i-1]>>4) & 0xFFF;
        int cv = (Samples1[i+0]>>4) & 0xFFF;
        int nv = (Samples1[i+1]>>4) & 0xFFF;

        if (((cv >= lv + SpikeAmplitude) && (cv >= nv + SpikeAmplitude)) ||
                ((cv <= lv - SpikeAmplitude) && (cv <= nv - SpikeAmplitude))) {
            usb.printf("\r\nSpike on Channel AD%d @ %d [%04u] [%04u] [%04u]\r\n", 1, i, lv, cv, nv);
            spikes++;
        }
    }

    //NOTE Powering the ADC ON/OFF does not seem to be neccesary.

    LPC_ADC->ADCR    |=  (1UL << 21);           // * Disable ADC
    LPC_SC->PCONP    |=  (1UL << 12);           // * Power off ADC

    match_timing.reset();

    return spikes;
}

int main() {
    usb.baud(115200);

    while (1) {
        myled1=false;

        if (Measure()!=0) {
            myled1 = !myled1;
        }

        myled2 = !myled2;
        usb.printf(".");
        wait_ms(100);
        myled2 = !myled2;
    }
}