Bob Anderson / Mbed 2 deprecated AnalogInAnalyzer

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*  Bob Anderson   (bob.anderson.ok@gmail.com)
00002 
00003 This program...
00004 
00005    1) Uses AnalogIn but speeds it up by setting
00006       the ADC clock to 12MHz (13MHz is max from spec sheet)
00007       
00008    2) Produces a histogram of deviations around a center
00009       value that is determined at the beginning of a run
00010       by a "vote" taken from three successive readings.
00011       
00012    3) Introduces a "glitch" suppression method that appears
00013       to be effective.  I consider a glitch to have occurred
00014       when two consecutive reading differ in value by more than
00015       3 sigma (approximately 10 for the noise distributions
00016       exhibited by the internal ADC).
00017       
00018    4) Provides for side-by-side comparison of an external ADC
00019       (MCP3304 or MCP3208) running at about 20,000 sps (because
00020       I'm running the part at 3.3v).
00021       
00022 With a 100nf capacitor from the analog pin to ground and
00023 a reasonably low impedance source ( < 5K ) and glitch suppression
00024 enabled, the LPC1768/9 onboard analog to digital converter subsystem
00025 becomes quite useable.  Without the capacitor and glitch suppression,
00026 it is not a reliable ADC --- it is glitch prone, even with the
00027 cleanest of inputs.  This program will help you determine for
00028 yourself whether that statement is true.  Play with it.
00029 
00030 The comparison of the internal ADC with the external ADC show that the
00031 external ADC is well behaved in circumstances that wipe out the internal ADC
00032 which is apparently quite sensitive to noise, whereas the external ADC is quite
00033 tolerant of noise.  The external ADC produces very narrow "distributions".
00034 
00035 */
00036 
00037 #include "mbed.h"
00038 
00039 Serial pc( USBTX, USBRX );
00040 
00041 AnalogIn ain( p20 );
00042 
00043 DigitalOut extAdcSelect(p8);
00044 DigitalOut led4(LED4);
00045 
00046 SPI spi(p5,p6,p7);             // spi(mosi,miso,sck)
00047 
00048 #define MCP3208  // or MCP3304
00049 
00050 #define EXT_ADC_CHAN 5
00051 
00052 #define NUM_SAMPLES 1000000
00053 #define HGRAM_MAX_INDEX 60
00054 
00055 int histoGramA[ HGRAM_MAX_INDEX + 1 ];  // histogram array for internal ADC
00056 int histoGramB[ HGRAM_MAX_INDEX + 1 ];  // histogram array for (possible) external ADC
00057 
00058 int  glitchCount = 0;
00059 bool glitchSuppressionWanted = false;
00060 bool useExternalADC = false;
00061 
00062 void setADCclockToMaxConversionRate( void );
00063 int  glitchSuppressedAnalogIn( bool );
00064 int  readExternalADC( int );
00065 void displayMenu( void );
00066 int  getCenterValue( bool externalADC );
00067 
00068 int max( int a, int b ) {
00069     if ( a > b ) return a;
00070     return b;
00071 }
00072 
00073 int min( int a, int b ) {
00074     if ( a < b ) return a;
00075     return b;
00076 }
00077 
00078 // middle( a, b, c ) returns true if a is between b and c
00079 bool middle( int a, int b, int c ) {
00080     return (a <= max(b,c)) && (a >= min(b,c));
00081 }
00082 
00083 // The MPC3304 chip select line is inverted: low == selected
00084 #define EXT_ADC_OFF 1 
00085 #define EXT_ADC_ON  0
00086 
00087 
00088    
00089 int main() {
00090 
00091     int referenceValue;
00092     int delta;
00093     int newValue;
00094     
00095     led4 = 0;  // This led shows progress during data acquisition.
00096     
00097     extAdcSelect = EXT_ADC_OFF;  // deselect
00098     
00099     spi.format( 8, 0 );
00100     spi.frequency( 500000 );
00101      
00102     // Speedup the AnalogIn conversion rate by readjusting
00103     // the ADC clock to 12 MHz (assuming SystemCoreClock = 96MHz)
00104     setADCclockToMaxConversionRate();
00105     
00106     while(1) {
00107 
00108         displayMenu();    
00109        
00110         bool waitingForKeyInput = true;
00111         
00112         while ( waitingForKeyInput ){
00113             switch (pc.getc()) {
00114               case 'g':
00115               case 'G': 
00116                 glitchSuppressionWanted = ! glitchSuppressionWanted;
00117                 if ( glitchSuppressionWanted )
00118                   printf( "...glitch suppression on...\r\n" );
00119                 else
00120                   printf( "...glitch suppression off...\r\n" );
00121                 break;
00122              
00123               case 'x':
00124               case 'X': 
00125                 useExternalADC = ! useExternalADC;
00126                 if ( useExternalADC )
00127                     printf( "...external ADC will be used...\r\n\r\n" );
00128                 else
00129                     printf( "...only internal ADC will be used...\r\n" );
00130                 break;
00131                 
00132               case 't':
00133                 for ( int cnt = 0; cnt < 50; cnt++ )
00134                    printf( "EXT ADC = %d\r\n", readExternalADC(EXT_ADC_CHAN) );
00135                 break;
00136              
00137               case 's':
00138               case 'S': waitingForKeyInput = false; break;
00139               
00140               default:
00141                 displayMenu(); break;
00142             }
00143         }
00144              
00145         // Clear the histogram arrays.
00146         for ( int k = 0; k <= HGRAM_MAX_INDEX; k++ ) histoGramA[k] = histoGramB[k] = 0;
00147         
00148         bool readFromExternalADC = false;
00149         
00150         referenceValue = getCenterValue( readFromExternalADC );
00151         
00152         printf( "Internal ADC center value = %d\r\n\r\n", referenceValue );     
00153         printf( "...now gathering... LED4 toggles at each 10,000 readings\r\n\r\n" );
00154         
00155         glitchCount = 0;
00156         for ( int i = 0; i < NUM_SAMPLES; i++ ) {
00157             newValue = glitchSuppressedAnalogIn( readFromExternalADC );
00158             delta = newValue - referenceValue + (HGRAM_MAX_INDEX / 2);
00159             if ( delta < 0 ) histoGramA[0]++;
00160             else if ( delta > HGRAM_MAX_INDEX ) histoGramA[HGRAM_MAX_INDEX]++;
00161             else histoGramA[delta]++;
00162             if ( (i % 10000) == 0 ) led4 = !led4;
00163         }
00164         led4 = 0;
00165  
00166         int glitchCountInternal = glitchCount;
00167         int glitchCountExternal = 0;
00168         
00169         if ( useExternalADC )
00170         {
00171             readFromExternalADC = true;
00172         
00173             referenceValue = getCenterValue( readFromExternalADC );
00174         
00175             printf( "External ADC center value = %d\r\n\r\n", referenceValue );     
00176             printf( "...now gathering... LED4 toggles at each 10,000 readings\r\n\r\n" );
00177             
00178             glitchCount = 0;     
00179             for ( int i = 0; i < NUM_SAMPLES; i++ ) {
00180                 newValue = glitchSuppressedAnalogIn( readFromExternalADC );
00181                 delta = newValue - referenceValue + (HGRAM_MAX_INDEX / 2);
00182                 if ( delta < 0 ) histoGramB[0]++;
00183                 else if ( delta > HGRAM_MAX_INDEX ) histoGramB[HGRAM_MAX_INDEX]++;
00184                 else histoGramB[delta]++;
00185                 if ( (i % 10000) == 0 ) led4 = !led4;
00186             }
00187             led4 = 0;
00188             
00189             glitchCountExternal = glitchCount;
00190         }      
00191         
00192         // Output histoGram(s)
00193         for ( int j = 0; j <= HGRAM_MAX_INDEX; j++ ) {
00194             if ( useExternalADC )
00195                 printf( "%4d %8d %8d\r\n", j - (HGRAM_MAX_INDEX/2), histoGramA[j], histoGramB[j] );
00196             else
00197                 printf( "%4d %8d\r\n", j - (HGRAM_MAX_INDEX/2), histoGramA[j] );
00198         }
00199         
00200         // Show glitch stats if glitch suppression was enabled
00201         if ( glitchSuppressionWanted ) {
00202             if ( useExternalADC )
00203                 printf( "\nglitchCount: Internal =  %d  External = %d\r\n", 
00204                         glitchCountInternal, glitchCountExternal );
00205             else
00206                 printf( "\nglitchCountInternal =  %d\r\n", glitchCountInternal );
00207         }
00208     }
00209 }
00210 
00211 void setADCclockToMaxConversionRate(void) {
00212     // Set pclk = cclk / 4  (pclk = 96Mhz/4 = 24Mhz)
00213     LPC_SC->PCLKSEL0 &= ~(0x3 << 24); // Clear bits 25:24   
00214         
00215     // software-controlled ADC settings
00216     LPC_ADC->ADCR = (0 << 0) // SEL: 0 = no channels selected
00217               | (1 << 8 )    // CLKDIV: ADCCLK = PCLK / (CLKDIV + 1) (12MHz)
00218               | (0 << 16)    // BURST: 0 = software control 
00219               | (0 << 17)    // CLKS: not applicable 
00220               | (1 << 21)    // PDN: 1 = operational
00221               | (0 << 24)    // START: 0 = no start
00222               | (0 << 27);   // EDGE: not applicable}
00223     return;
00224 }
00225 
00226 int glitchSuppressedAnalogIn( bool externalADC ) {
00227     int v1,v2,delta;
00228     
00229     if ( externalADC )
00230         v1 = readExternalADC(EXT_ADC_CHAN);
00231     else    
00232         v1 = ain.read_u16() >> 4;
00233         
00234     if ( ! glitchSuppressionWanted ) return v1;
00235     
00236     // While this has the possiblity of never returning,
00237     // the probability of that is vanishingly small.  We assume
00238     // that we will eventually find two successive readings that are
00239     // within the tolerance band --- i.e., no glitch
00240     while(1){
00241         if ( externalADC )
00242             v2 = readExternalADC(EXT_ADC_CHAN);
00243         else
00244             v2 = ain.read_u16() >> 4;
00245         delta = v1 - v2;
00246         if ( (delta > -10) && (delta < 10)) return (v1+v2)/2;
00247         v1 = v2;
00248         glitchCount++;
00249     }
00250 }
00251 
00252 int readExternalADC( int channel ) {
00253     int ch = channel & 0x7;
00254     extAdcSelect = EXT_ADC_ON;
00255     
00256     #ifdef MCP3208
00257         int byte1 = spi.write( 0x6 | (ch >> 2) );
00258         int byte2 = spi.write( (ch << 6) ) & 0xf;  // d0 = 0
00259     #else
00260       #ifdef MCP3304
00261           int byte1 = spi.write( 0xc | (ch >> 1) );
00262           int byte2 = spi.write( (ch << 7) ) & 0xf;  // d0 = 0
00263       #else
00264           error( "Undefined external ADC device" );
00265       #endif
00266     #endif      
00267                 
00268     int byte3 = spi.write( 0xaa );        // dummy value, but nice pattern of logic analyzer
00269     extAdcSelect = EXT_ADC_OFF;
00270     int value = (byte2 << 8) | byte3;
00271     //printf( "byte2 = %2x  byte3 = %2x  value = %d\r\n", byte2, byte3, value );
00272     return value;
00273 }
00274 
00275 void displayMenu( void ) {
00276    
00277    if ( glitchSuppressionWanted )
00278        printf( "\r\n\r\nglitch suppression is enabled.\r\n" );
00279    else
00280        printf( "\r\nglitch suppression is disabled\r\n" );
00281    if ( useExternalADC )
00282        printf( "Results from an external ADC will be included.\r\n" );
00283    else
00284        printf( "External ADC not in use.\r\n" );
00285        
00286    printf( "\r\nPress the s key to start data acquisition.\r\n" );        
00287    printf( "Press the g key to toggle glitch suppression.\r\n" );
00288    printf( "Press the x key to toggle use of external ADC.\r\n\r\n" );
00289 }
00290 
00291 int getCenterValue( bool externalADC ) {
00292     // Establish center point for histogram by taking three readings
00293     // and selecting the one in the middle as the reference value around
00294     // which deviations will be calculated.
00295     int value1 = glitchSuppressedAnalogIn( externalADC );
00296     int value2 = glitchSuppressedAnalogIn( externalADC );
00297     int value3 = glitchSuppressedAnalogIn( externalADC );
00298     
00299     if ( middle(value1,value2,value3) ) 
00300         return value1;
00301     else if ( middle(value2,value1,value3) )
00302         return value2;
00303     else
00304         return value3;
00305 }