Wim van der Vegt
/
Spiker
Test program for Spikes when measuring 2 channels in Timer1/MAT1:0 triggering mode.
Diff: main.cpp
- 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; + } +}