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

Dependencies:   mbed

Revision:
0:ff3d852b6266
Child:
1:b6dcd0de2a17
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Nov 30 17:02:16 2011 +0000
@@ -0,0 +1,285 @@
+#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;
+    }
+}