Dependencies:   mbed

Committer:
bobanderson
Date:
Fri Feb 18 02:36:18 2011 +0000
Revision:
2:e1781d02ec0d
Parent:
1:ecca38babc13
Rev to allow either MPC3304 or MPC3208 A/D converters to be used.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bobanderson 0:7c70badd2847 1 /* Bob Anderson (bob.anderson.ok@gmail.com)
bobanderson 0:7c70badd2847 2
bobanderson 0:7c70badd2847 3 This program...
bobanderson 0:7c70badd2847 4
bobanderson 0:7c70badd2847 5 1) Uses AnalogIn but speeds it up by setting
bobanderson 0:7c70badd2847 6 the ADC clock to 12MHz (13MHz is max from spec sheet)
bobanderson 0:7c70badd2847 7
bobanderson 0:7c70badd2847 8 2) Produces a histogram of deviations around a center
bobanderson 0:7c70badd2847 9 value that is determined at the beginning of a run
bobanderson 0:7c70badd2847 10 by a "vote" taken from three successive readings.
bobanderson 0:7c70badd2847 11
bobanderson 0:7c70badd2847 12 3) Introduces a "glitch" suppression method that appears
bobanderson 1:ecca38babc13 13 to be effective. I consider a glitch to have occurred
bobanderson 1:ecca38babc13 14 when two consecutive reading differ in value by more than
bobanderson 1:ecca38babc13 15 3 sigma (approximately 10 for the noise distributions
bobanderson 1:ecca38babc13 16 exhibited by the internal ADC).
bobanderson 1:ecca38babc13 17
bobanderson 1:ecca38babc13 18 4) Provides for side-by-side comparison of an external ADC
bobanderson 1:ecca38babc13 19 (MCP3304 or MCP3208) running at about 20,000 sps (because
bobanderson 1:ecca38babc13 20 I'm running the part at 3.3v).
bobanderson 0:7c70badd2847 21
bobanderson 0:7c70badd2847 22 With a 100nf capacitor from the analog pin to ground and
bobanderson 0:7c70badd2847 23 a reasonably low impedance source ( < 5K ) and glitch suppression
bobanderson 0:7c70badd2847 24 enabled, the LPC1768/9 onboard analog to digital converter subsystem
bobanderson 0:7c70badd2847 25 becomes quite useable. Without the capacitor and glitch suppression,
bobanderson 0:7c70badd2847 26 it is not a reliable ADC --- it is glitch prone, even with the
bobanderson 0:7c70badd2847 27 cleanest of inputs. This program will help you determine for
bobanderson 0:7c70badd2847 28 yourself whether that statement is true. Play with it.
bobanderson 0:7c70badd2847 29
bobanderson 1:ecca38babc13 30 The comparison of the internal ADC with the external ADC show that the
bobanderson 1:ecca38babc13 31 external ADC is well behaved in circumstances that wipe out the internal ADC
bobanderson 1:ecca38babc13 32 which is apparently quite sensitive to noise, whereas the external ADC is quite
bobanderson 1:ecca38babc13 33 tolerant of noise. The external ADC produces very narrow "distributions".
bobanderson 1:ecca38babc13 34
bobanderson 0:7c70badd2847 35 */
bobanderson 0:7c70badd2847 36
bobanderson 0:7c70badd2847 37 #include "mbed.h"
bobanderson 0:7c70badd2847 38
bobanderson 0:7c70badd2847 39 Serial pc( USBTX, USBRX );
bobanderson 0:7c70badd2847 40
bobanderson 0:7c70badd2847 41 AnalogIn ain( p20 );
bobanderson 0:7c70badd2847 42
bobanderson 2:e1781d02ec0d 43 DigitalOut extAdcSelect(p8);
bobanderson 1:ecca38babc13 44 DigitalOut led4(LED4);
bobanderson 1:ecca38babc13 45
bobanderson 1:ecca38babc13 46 SPI spi(p5,p6,p7); // spi(mosi,miso,sck)
bobanderson 1:ecca38babc13 47
bobanderson 2:e1781d02ec0d 48 #define MCP3208 // or MCP3304
bobanderson 2:e1781d02ec0d 49
bobanderson 2:e1781d02ec0d 50 #define EXT_ADC_CHAN 5
bobanderson 2:e1781d02ec0d 51
bobanderson 0:7c70badd2847 52 #define NUM_SAMPLES 1000000
bobanderson 0:7c70badd2847 53 #define HGRAM_MAX_INDEX 60
bobanderson 1:ecca38babc13 54
bobanderson 1:ecca38babc13 55 int histoGramA[ HGRAM_MAX_INDEX + 1 ]; // histogram array for internal ADC
bobanderson 1:ecca38babc13 56 int histoGramB[ HGRAM_MAX_INDEX + 1 ]; // histogram array for (possible) external ADC
bobanderson 0:7c70badd2847 57
bobanderson 2:e1781d02ec0d 58 int glitchCount = 0;
bobanderson 0:7c70badd2847 59 bool glitchSuppressionWanted = false;
bobanderson 1:ecca38babc13 60 bool useExternalADC = false;
bobanderson 0:7c70badd2847 61
bobanderson 1:ecca38babc13 62 void setADCclockToMaxConversionRate( void );
bobanderson 1:ecca38babc13 63 int glitchSuppressedAnalogIn( bool );
bobanderson 2:e1781d02ec0d 64 int readExternalADC( int );
bobanderson 1:ecca38babc13 65 void displayMenu( void );
bobanderson 2:e1781d02ec0d 66 int getCenterValue( bool externalADC );
bobanderson 0:7c70badd2847 67
bobanderson 0:7c70badd2847 68 int max( int a, int b ) {
bobanderson 0:7c70badd2847 69 if ( a > b ) return a;
bobanderson 0:7c70badd2847 70 return b;
bobanderson 0:7c70badd2847 71 }
bobanderson 0:7c70badd2847 72
bobanderson 0:7c70badd2847 73 int min( int a, int b ) {
bobanderson 0:7c70badd2847 74 if ( a < b ) return a;
bobanderson 0:7c70badd2847 75 return b;
bobanderson 0:7c70badd2847 76 }
bobanderson 0:7c70badd2847 77
bobanderson 0:7c70badd2847 78 // middle( a, b, c ) returns true if a is between b and c
bobanderson 0:7c70badd2847 79 bool middle( int a, int b, int c ) {
bobanderson 0:7c70badd2847 80 return (a <= max(b,c)) && (a >= min(b,c));
bobanderson 0:7c70badd2847 81 }
bobanderson 0:7c70badd2847 82
bobanderson 1:ecca38babc13 83 // The MPC3304 chip select line is inverted: low == selected
bobanderson 1:ecca38babc13 84 #define EXT_ADC_OFF 1
bobanderson 1:ecca38babc13 85 #define EXT_ADC_ON 0
bobanderson 1:ecca38babc13 86
bobanderson 1:ecca38babc13 87
bobanderson 1:ecca38babc13 88
bobanderson 0:7c70badd2847 89 int main() {
bobanderson 0:7c70badd2847 90
bobanderson 0:7c70badd2847 91 int referenceValue;
bobanderson 0:7c70badd2847 92 int delta;
bobanderson 0:7c70badd2847 93 int newValue;
bobanderson 0:7c70badd2847 94
bobanderson 1:ecca38babc13 95 led4 = 0; // This led shows progress during data acquisition.
bobanderson 1:ecca38babc13 96
bobanderson 2:e1781d02ec0d 97 extAdcSelect = EXT_ADC_OFF; // deselect
bobanderson 1:ecca38babc13 98
bobanderson 1:ecca38babc13 99 spi.format( 8, 0 );
bobanderson 1:ecca38babc13 100 spi.frequency( 500000 );
bobanderson 1:ecca38babc13 101
bobanderson 0:7c70badd2847 102 // Speedup the AnalogIn conversion rate by readjusting
bobanderson 0:7c70badd2847 103 // the ADC clock to 12 MHz (assuming SystemCoreClock = 96MHz)
bobanderson 0:7c70badd2847 104 setADCclockToMaxConversionRate();
bobanderson 0:7c70badd2847 105
bobanderson 0:7c70badd2847 106 while(1) {
bobanderson 1:ecca38babc13 107
bobanderson 1:ecca38babc13 108 displayMenu();
bobanderson 1:ecca38babc13 109
bobanderson 0:7c70badd2847 110 bool waitingForKeyInput = true;
bobanderson 0:7c70badd2847 111
bobanderson 0:7c70badd2847 112 while ( waitingForKeyInput ){
bobanderson 0:7c70badd2847 113 switch (pc.getc()) {
bobanderson 0:7c70badd2847 114 case 'g':
bobanderson 0:7c70badd2847 115 case 'G':
bobanderson 0:7c70badd2847 116 glitchSuppressionWanted = ! glitchSuppressionWanted;
bobanderson 0:7c70badd2847 117 if ( glitchSuppressionWanted )
bobanderson 1:ecca38babc13 118 printf( "...glitch suppression on...\r\n" );
bobanderson 0:7c70badd2847 119 else
bobanderson 1:ecca38babc13 120 printf( "...glitch suppression off...\r\n" );
bobanderson 1:ecca38babc13 121 break;
bobanderson 1:ecca38babc13 122
bobanderson 1:ecca38babc13 123 case 'x':
bobanderson 1:ecca38babc13 124 case 'X':
bobanderson 1:ecca38babc13 125 useExternalADC = ! useExternalADC;
bobanderson 1:ecca38babc13 126 if ( useExternalADC )
bobanderson 1:ecca38babc13 127 printf( "...external ADC will be used...\r\n\r\n" );
bobanderson 1:ecca38babc13 128 else
bobanderson 1:ecca38babc13 129 printf( "...only internal ADC will be used...\r\n" );
bobanderson 1:ecca38babc13 130 break;
bobanderson 1:ecca38babc13 131
bobanderson 1:ecca38babc13 132 case 't':
bobanderson 1:ecca38babc13 133 for ( int cnt = 0; cnt < 50; cnt++ )
bobanderson 2:e1781d02ec0d 134 printf( "EXT ADC = %d\r\n", readExternalADC(EXT_ADC_CHAN) );
bobanderson 0:7c70badd2847 135 break;
bobanderson 1:ecca38babc13 136
bobanderson 0:7c70badd2847 137 case 's':
bobanderson 1:ecca38babc13 138 case 'S': waitingForKeyInput = false; break;
bobanderson 1:ecca38babc13 139
bobanderson 1:ecca38babc13 140 default:
bobanderson 1:ecca38babc13 141 displayMenu(); break;
bobanderson 0:7c70badd2847 142 }
bobanderson 0:7c70badd2847 143 }
bobanderson 1:ecca38babc13 144
bobanderson 1:ecca38babc13 145 // Clear the histogram arrays.
bobanderson 1:ecca38babc13 146 for ( int k = 0; k <= HGRAM_MAX_INDEX; k++ ) histoGramA[k] = histoGramB[k] = 0;
bobanderson 1:ecca38babc13 147
bobanderson 1:ecca38babc13 148 bool readFromExternalADC = false;
bobanderson 1:ecca38babc13 149
bobanderson 1:ecca38babc13 150 referenceValue = getCenterValue( readFromExternalADC );
bobanderson 1:ecca38babc13 151
bobanderson 1:ecca38babc13 152 printf( "Internal ADC center value = %d\r\n\r\n", referenceValue );
bobanderson 1:ecca38babc13 153 printf( "...now gathering... LED4 toggles at each 10,000 readings\r\n\r\n" );
bobanderson 1:ecca38babc13 154
bobanderson 1:ecca38babc13 155 glitchCount = 0;
bobanderson 1:ecca38babc13 156 for ( int i = 0; i < NUM_SAMPLES; i++ ) {
bobanderson 1:ecca38babc13 157 newValue = glitchSuppressedAnalogIn( readFromExternalADC );
bobanderson 1:ecca38babc13 158 delta = newValue - referenceValue + (HGRAM_MAX_INDEX / 2);
bobanderson 1:ecca38babc13 159 if ( delta < 0 ) histoGramA[0]++;
bobanderson 1:ecca38babc13 160 else if ( delta > HGRAM_MAX_INDEX ) histoGramA[HGRAM_MAX_INDEX]++;
bobanderson 1:ecca38babc13 161 else histoGramA[delta]++;
bobanderson 1:ecca38babc13 162 if ( (i % 10000) == 0 ) led4 = !led4;
bobanderson 1:ecca38babc13 163 }
bobanderson 1:ecca38babc13 164 led4 = 0;
bobanderson 1:ecca38babc13 165
bobanderson 1:ecca38babc13 166 int glitchCountInternal = glitchCount;
bobanderson 2:e1781d02ec0d 167 int glitchCountExternal = 0;
bobanderson 1:ecca38babc13 168
bobanderson 1:ecca38babc13 169 if ( useExternalADC )
bobanderson 1:ecca38babc13 170 {
bobanderson 1:ecca38babc13 171 readFromExternalADC = true;
bobanderson 1:ecca38babc13 172
bobanderson 1:ecca38babc13 173 referenceValue = getCenterValue( readFromExternalADC );
bobanderson 1:ecca38babc13 174
bobanderson 1:ecca38babc13 175 printf( "External ADC center value = %d\r\n\r\n", referenceValue );
bobanderson 1:ecca38babc13 176 printf( "...now gathering... LED4 toggles at each 10,000 readings\r\n\r\n" );
bobanderson 1:ecca38babc13 177
bobanderson 1:ecca38babc13 178 glitchCount = 0;
bobanderson 1:ecca38babc13 179 for ( int i = 0; i < NUM_SAMPLES; i++ ) {
bobanderson 1:ecca38babc13 180 newValue = glitchSuppressedAnalogIn( readFromExternalADC );
bobanderson 1:ecca38babc13 181 delta = newValue - referenceValue + (HGRAM_MAX_INDEX / 2);
bobanderson 1:ecca38babc13 182 if ( delta < 0 ) histoGramB[0]++;
bobanderson 1:ecca38babc13 183 else if ( delta > HGRAM_MAX_INDEX ) histoGramB[HGRAM_MAX_INDEX]++;
bobanderson 1:ecca38babc13 184 else histoGramB[delta]++;
bobanderson 1:ecca38babc13 185 if ( (i % 10000) == 0 ) led4 = !led4;
bobanderson 1:ecca38babc13 186 }
bobanderson 1:ecca38babc13 187 led4 = 0;
bobanderson 1:ecca38babc13 188
bobanderson 1:ecca38babc13 189 glitchCountExternal = glitchCount;
bobanderson 2:e1781d02ec0d 190 }
bobanderson 0:7c70badd2847 191
bobanderson 2:e1781d02ec0d 192 // Output histoGram(s)
bobanderson 0:7c70badd2847 193 for ( int j = 0; j <= HGRAM_MAX_INDEX; j++ ) {
bobanderson 1:ecca38babc13 194 if ( useExternalADC )
bobanderson 1:ecca38babc13 195 printf( "%4d %8d %8d\r\n", j - (HGRAM_MAX_INDEX/2), histoGramA[j], histoGramB[j] );
bobanderson 1:ecca38babc13 196 else
bobanderson 1:ecca38babc13 197 printf( "%4d %8d\r\n", j - (HGRAM_MAX_INDEX/2), histoGramA[j] );
bobanderson 0:7c70badd2847 198 }
bobanderson 0:7c70badd2847 199
bobanderson 2:e1781d02ec0d 200 // Show glitch stats if glitch suppression was enabled
bobanderson 1:ecca38babc13 201 if ( glitchSuppressionWanted ) {
bobanderson 1:ecca38babc13 202 if ( useExternalADC )
bobanderson 1:ecca38babc13 203 printf( "\nglitchCount: Internal = %d External = %d\r\n",
bobanderson 1:ecca38babc13 204 glitchCountInternal, glitchCountExternal );
bobanderson 1:ecca38babc13 205 else
bobanderson 1:ecca38babc13 206 printf( "\nglitchCountInternal = %d\r\n", glitchCountInternal );
bobanderson 1:ecca38babc13 207 }
bobanderson 0:7c70badd2847 208 }
bobanderson 0:7c70badd2847 209 }
bobanderson 0:7c70badd2847 210
bobanderson 0:7c70badd2847 211 void setADCclockToMaxConversionRate(void) {
bobanderson 0:7c70badd2847 212 // Set pclk = cclk / 4 (pclk = 96Mhz/4 = 24Mhz)
bobanderson 0:7c70badd2847 213 LPC_SC->PCLKSEL0 &= ~(0x3 << 24); // Clear bits 25:24
bobanderson 0:7c70badd2847 214
bobanderson 0:7c70badd2847 215 // software-controlled ADC settings
bobanderson 0:7c70badd2847 216 LPC_ADC->ADCR = (0 << 0) // SEL: 0 = no channels selected
bobanderson 0:7c70badd2847 217 | (1 << 8 ) // CLKDIV: ADCCLK = PCLK / (CLKDIV + 1) (12MHz)
bobanderson 0:7c70badd2847 218 | (0 << 16) // BURST: 0 = software control
bobanderson 0:7c70badd2847 219 | (0 << 17) // CLKS: not applicable
bobanderson 0:7c70badd2847 220 | (1 << 21) // PDN: 1 = operational
bobanderson 0:7c70badd2847 221 | (0 << 24) // START: 0 = no start
bobanderson 0:7c70badd2847 222 | (0 << 27); // EDGE: not applicable}
bobanderson 0:7c70badd2847 223 return;
bobanderson 0:7c70badd2847 224 }
bobanderson 0:7c70badd2847 225
bobanderson 1:ecca38babc13 226 int glitchSuppressedAnalogIn( bool externalADC ) {
bobanderson 0:7c70badd2847 227 int v1,v2,delta;
bobanderson 0:7c70badd2847 228
bobanderson 1:ecca38babc13 229 if ( externalADC )
bobanderson 2:e1781d02ec0d 230 v1 = readExternalADC(EXT_ADC_CHAN);
bobanderson 1:ecca38babc13 231 else
bobanderson 1:ecca38babc13 232 v1 = ain.read_u16() >> 4;
bobanderson 1:ecca38babc13 233
bobanderson 0:7c70badd2847 234 if ( ! glitchSuppressionWanted ) return v1;
bobanderson 0:7c70badd2847 235
bobanderson 0:7c70badd2847 236 // While this has the possiblity of never returning,
bobanderson 0:7c70badd2847 237 // the probability of that is vanishingly small. We assume
bobanderson 0:7c70badd2847 238 // that we will eventually find two successive readings that are
bobanderson 0:7c70badd2847 239 // within the tolerance band --- i.e., no glitch
bobanderson 0:7c70badd2847 240 while(1){
bobanderson 1:ecca38babc13 241 if ( externalADC )
bobanderson 2:e1781d02ec0d 242 v2 = readExternalADC(EXT_ADC_CHAN);
bobanderson 1:ecca38babc13 243 else
bobanderson 1:ecca38babc13 244 v2 = ain.read_u16() >> 4;
bobanderson 0:7c70badd2847 245 delta = v1 - v2;
bobanderson 0:7c70badd2847 246 if ( (delta > -10) && (delta < 10)) return (v1+v2)/2;
bobanderson 0:7c70badd2847 247 v1 = v2;
bobanderson 0:7c70badd2847 248 glitchCount++;
bobanderson 0:7c70badd2847 249 }
bobanderson 1:ecca38babc13 250 }
bobanderson 1:ecca38babc13 251
bobanderson 2:e1781d02ec0d 252 int readExternalADC( int channel ) {
bobanderson 2:e1781d02ec0d 253 int ch = channel & 0x7;
bobanderson 2:e1781d02ec0d 254 extAdcSelect = EXT_ADC_ON;
bobanderson 2:e1781d02ec0d 255
bobanderson 2:e1781d02ec0d 256 #ifdef MCP3208
bobanderson 2:e1781d02ec0d 257 int byte1 = spi.write( 0x6 | (ch >> 2) );
bobanderson 2:e1781d02ec0d 258 int byte2 = spi.write( (ch << 6) ) & 0xf; // d0 = 0
bobanderson 2:e1781d02ec0d 259 #else
bobanderson 2:e1781d02ec0d 260 #ifdef MCP3304
bobanderson 2:e1781d02ec0d 261 int byte1 = spi.write( 0xc | (ch >> 1) );
bobanderson 2:e1781d02ec0d 262 int byte2 = spi.write( (ch << 7) ) & 0xf; // d0 = 0
bobanderson 2:e1781d02ec0d 263 #else
bobanderson 2:e1781d02ec0d 264 error( "Undefined external ADC device" );
bobanderson 2:e1781d02ec0d 265 #endif
bobanderson 2:e1781d02ec0d 266 #endif
bobanderson 2:e1781d02ec0d 267
bobanderson 1:ecca38babc13 268 int byte3 = spi.write( 0xaa ); // dummy value, but nice pattern of logic analyzer
bobanderson 2:e1781d02ec0d 269 extAdcSelect = EXT_ADC_OFF;
bobanderson 1:ecca38babc13 270 int value = (byte2 << 8) | byte3;
bobanderson 1:ecca38babc13 271 //printf( "byte2 = %2x byte3 = %2x value = %d\r\n", byte2, byte3, value );
bobanderson 1:ecca38babc13 272 return value;
bobanderson 1:ecca38babc13 273 }
bobanderson 1:ecca38babc13 274
bobanderson 1:ecca38babc13 275 void displayMenu( void ) {
bobanderson 1:ecca38babc13 276
bobanderson 1:ecca38babc13 277 if ( glitchSuppressionWanted )
bobanderson 1:ecca38babc13 278 printf( "\r\n\r\nglitch suppression is enabled.\r\n" );
bobanderson 1:ecca38babc13 279 else
bobanderson 1:ecca38babc13 280 printf( "\r\nglitch suppression is disabled\r\n" );
bobanderson 1:ecca38babc13 281 if ( useExternalADC )
bobanderson 1:ecca38babc13 282 printf( "Results from an external ADC will be included.\r\n" );
bobanderson 1:ecca38babc13 283 else
bobanderson 1:ecca38babc13 284 printf( "External ADC not in use.\r\n" );
bobanderson 1:ecca38babc13 285
bobanderson 1:ecca38babc13 286 printf( "\r\nPress the s key to start data acquisition.\r\n" );
bobanderson 1:ecca38babc13 287 printf( "Press the g key to toggle glitch suppression.\r\n" );
bobanderson 1:ecca38babc13 288 printf( "Press the x key to toggle use of external ADC.\r\n\r\n" );
bobanderson 1:ecca38babc13 289 }
bobanderson 1:ecca38babc13 290
bobanderson 1:ecca38babc13 291 int getCenterValue( bool externalADC ) {
bobanderson 1:ecca38babc13 292 // Establish center point for histogram by taking three readings
bobanderson 1:ecca38babc13 293 // and selecting the one in the middle as the reference value around
bobanderson 1:ecca38babc13 294 // which deviations will be calculated.
bobanderson 1:ecca38babc13 295 int value1 = glitchSuppressedAnalogIn( externalADC );
bobanderson 1:ecca38babc13 296 int value2 = glitchSuppressedAnalogIn( externalADC );
bobanderson 1:ecca38babc13 297 int value3 = glitchSuppressedAnalogIn( externalADC );
bobanderson 1:ecca38babc13 298
bobanderson 1:ecca38babc13 299 if ( middle(value1,value2,value3) )
bobanderson 1:ecca38babc13 300 return value1;
bobanderson 1:ecca38babc13 301 else if ( middle(value2,value1,value3) )
bobanderson 1:ecca38babc13 302 return value2;
bobanderson 1:ecca38babc13 303 else
bobanderson 1:ecca38babc13 304 return value3;
bobanderson 0:7c70badd2847 305 }