Bob Anderson
/
AnalogInAnalyzer
main.cpp
- Committer:
- bobanderson
- Date:
- 2011-02-18
- Revision:
- 2:e1781d02ec0d
- Parent:
- 1:ecca38babc13
File content as of revision 2:e1781d02ec0d:
/* Bob Anderson (bob.anderson.ok@gmail.com) This program... 1) Uses AnalogIn but speeds it up by setting the ADC clock to 12MHz (13MHz is max from spec sheet) 2) Produces a histogram of deviations around a center value that is determined at the beginning of a run by a "vote" taken from three successive readings. 3) Introduces a "glitch" suppression method that appears to be effective. I consider a glitch to have occurred when two consecutive reading differ in value by more than 3 sigma (approximately 10 for the noise distributions exhibited by the internal ADC). 4) Provides for side-by-side comparison of an external ADC (MCP3304 or MCP3208) running at about 20,000 sps (because I'm running the part at 3.3v). With a 100nf capacitor from the analog pin to ground and a reasonably low impedance source ( < 5K ) and glitch suppression enabled, the LPC1768/9 onboard analog to digital converter subsystem becomes quite useable. Without the capacitor and glitch suppression, it is not a reliable ADC --- it is glitch prone, even with the cleanest of inputs. This program will help you determine for yourself whether that statement is true. Play with it. The comparison of the internal ADC with the external ADC show that the external ADC is well behaved in circumstances that wipe out the internal ADC which is apparently quite sensitive to noise, whereas the external ADC is quite tolerant of noise. The external ADC produces very narrow "distributions". */ #include "mbed.h" Serial pc( USBTX, USBRX ); AnalogIn ain( p20 ); DigitalOut extAdcSelect(p8); DigitalOut led4(LED4); SPI spi(p5,p6,p7); // spi(mosi,miso,sck) #define MCP3208 // or MCP3304 #define EXT_ADC_CHAN 5 #define NUM_SAMPLES 1000000 #define HGRAM_MAX_INDEX 60 int histoGramA[ HGRAM_MAX_INDEX + 1 ]; // histogram array for internal ADC int histoGramB[ HGRAM_MAX_INDEX + 1 ]; // histogram array for (possible) external ADC int glitchCount = 0; bool glitchSuppressionWanted = false; bool useExternalADC = false; void setADCclockToMaxConversionRate( void ); int glitchSuppressedAnalogIn( bool ); int readExternalADC( int ); void displayMenu( void ); int getCenterValue( bool externalADC ); int max( int a, int b ) { if ( a > b ) return a; return b; } int min( int a, int b ) { if ( a < b ) return a; return b; } // middle( a, b, c ) returns true if a is between b and c bool middle( int a, int b, int c ) { return (a <= max(b,c)) && (a >= min(b,c)); } // The MPC3304 chip select line is inverted: low == selected #define EXT_ADC_OFF 1 #define EXT_ADC_ON 0 int main() { int referenceValue; int delta; int newValue; led4 = 0; // This led shows progress during data acquisition. extAdcSelect = EXT_ADC_OFF; // deselect spi.format( 8, 0 ); spi.frequency( 500000 ); // Speedup the AnalogIn conversion rate by readjusting // the ADC clock to 12 MHz (assuming SystemCoreClock = 96MHz) setADCclockToMaxConversionRate(); while(1) { displayMenu(); bool waitingForKeyInput = true; while ( waitingForKeyInput ){ switch (pc.getc()) { case 'g': case 'G': glitchSuppressionWanted = ! glitchSuppressionWanted; if ( glitchSuppressionWanted ) printf( "...glitch suppression on...\r\n" ); else printf( "...glitch suppression off...\r\n" ); break; case 'x': case 'X': useExternalADC = ! useExternalADC; if ( useExternalADC ) printf( "...external ADC will be used...\r\n\r\n" ); else printf( "...only internal ADC will be used...\r\n" ); break; case 't': for ( int cnt = 0; cnt < 50; cnt++ ) printf( "EXT ADC = %d\r\n", readExternalADC(EXT_ADC_CHAN) ); break; case 's': case 'S': waitingForKeyInput = false; break; default: displayMenu(); break; } } // Clear the histogram arrays. for ( int k = 0; k <= HGRAM_MAX_INDEX; k++ ) histoGramA[k] = histoGramB[k] = 0; bool readFromExternalADC = false; referenceValue = getCenterValue( readFromExternalADC ); printf( "Internal ADC center value = %d\r\n\r\n", referenceValue ); printf( "...now gathering... LED4 toggles at each 10,000 readings\r\n\r\n" ); glitchCount = 0; for ( int i = 0; i < NUM_SAMPLES; i++ ) { newValue = glitchSuppressedAnalogIn( readFromExternalADC ); delta = newValue - referenceValue + (HGRAM_MAX_INDEX / 2); if ( delta < 0 ) histoGramA[0]++; else if ( delta > HGRAM_MAX_INDEX ) histoGramA[HGRAM_MAX_INDEX]++; else histoGramA[delta]++; if ( (i % 10000) == 0 ) led4 = !led4; } led4 = 0; int glitchCountInternal = glitchCount; int glitchCountExternal = 0; if ( useExternalADC ) { readFromExternalADC = true; referenceValue = getCenterValue( readFromExternalADC ); printf( "External ADC center value = %d\r\n\r\n", referenceValue ); printf( "...now gathering... LED4 toggles at each 10,000 readings\r\n\r\n" ); glitchCount = 0; for ( int i = 0; i < NUM_SAMPLES; i++ ) { newValue = glitchSuppressedAnalogIn( readFromExternalADC ); delta = newValue - referenceValue + (HGRAM_MAX_INDEX / 2); if ( delta < 0 ) histoGramB[0]++; else if ( delta > HGRAM_MAX_INDEX ) histoGramB[HGRAM_MAX_INDEX]++; else histoGramB[delta]++; if ( (i % 10000) == 0 ) led4 = !led4; } led4 = 0; glitchCountExternal = glitchCount; } // Output histoGram(s) for ( int j = 0; j <= HGRAM_MAX_INDEX; j++ ) { if ( useExternalADC ) printf( "%4d %8d %8d\r\n", j - (HGRAM_MAX_INDEX/2), histoGramA[j], histoGramB[j] ); else printf( "%4d %8d\r\n", j - (HGRAM_MAX_INDEX/2), histoGramA[j] ); } // Show glitch stats if glitch suppression was enabled if ( glitchSuppressionWanted ) { if ( useExternalADC ) printf( "\nglitchCount: Internal = %d External = %d\r\n", glitchCountInternal, glitchCountExternal ); else printf( "\nglitchCountInternal = %d\r\n", glitchCountInternal ); } } } void setADCclockToMaxConversionRate(void) { // Set pclk = cclk / 4 (pclk = 96Mhz/4 = 24Mhz) LPC_SC->PCLKSEL0 &= ~(0x3 << 24); // Clear bits 25:24 // software-controlled ADC settings LPC_ADC->ADCR = (0 << 0) // SEL: 0 = no channels selected | (1 << 8 ) // CLKDIV: ADCCLK = PCLK / (CLKDIV + 1) (12MHz) | (0 << 16) // BURST: 0 = software control | (0 << 17) // CLKS: not applicable | (1 << 21) // PDN: 1 = operational | (0 << 24) // START: 0 = no start | (0 << 27); // EDGE: not applicable} return; } int glitchSuppressedAnalogIn( bool externalADC ) { int v1,v2,delta; if ( externalADC ) v1 = readExternalADC(EXT_ADC_CHAN); else v1 = ain.read_u16() >> 4; if ( ! glitchSuppressionWanted ) return v1; // While this has the possiblity of never returning, // the probability of that is vanishingly small. We assume // that we will eventually find two successive readings that are // within the tolerance band --- i.e., no glitch while(1){ if ( externalADC ) v2 = readExternalADC(EXT_ADC_CHAN); else v2 = ain.read_u16() >> 4; delta = v1 - v2; if ( (delta > -10) && (delta < 10)) return (v1+v2)/2; v1 = v2; glitchCount++; } } int readExternalADC( int channel ) { int ch = channel & 0x7; extAdcSelect = EXT_ADC_ON; #ifdef MCP3208 int byte1 = spi.write( 0x6 | (ch >> 2) ); int byte2 = spi.write( (ch << 6) ) & 0xf; // d0 = 0 #else #ifdef MCP3304 int byte1 = spi.write( 0xc | (ch >> 1) ); int byte2 = spi.write( (ch << 7) ) & 0xf; // d0 = 0 #else error( "Undefined external ADC device" ); #endif #endif int byte3 = spi.write( 0xaa ); // dummy value, but nice pattern of logic analyzer extAdcSelect = EXT_ADC_OFF; int value = (byte2 << 8) | byte3; //printf( "byte2 = %2x byte3 = %2x value = %d\r\n", byte2, byte3, value ); return value; } void displayMenu( void ) { if ( glitchSuppressionWanted ) printf( "\r\n\r\nglitch suppression is enabled.\r\n" ); else printf( "\r\nglitch suppression is disabled\r\n" ); if ( useExternalADC ) printf( "Results from an external ADC will be included.\r\n" ); else printf( "External ADC not in use.\r\n" ); printf( "\r\nPress the s key to start data acquisition.\r\n" ); printf( "Press the g key to toggle glitch suppression.\r\n" ); printf( "Press the x key to toggle use of external ADC.\r\n\r\n" ); } int getCenterValue( bool externalADC ) { // Establish center point for histogram by taking three readings // and selecting the one in the middle as the reference value around // which deviations will be calculated. int value1 = glitchSuppressedAnalogIn( externalADC ); int value2 = glitchSuppressedAnalogIn( externalADC ); int value3 = glitchSuppressedAnalogIn( externalADC ); if ( middle(value1,value2,value3) ) return value1; else if ( middle(value2,value1,value3) ) return value2; else return value3; }