adc.c
00001
00002
00003
00004
00005
00006 #include PLATFORM_HEADER
00007 #include "hal/error.h"
00008 #include "hal/hal.h"
00009 #include "hal/micro/adc.h"
00010
00011
00012 #if (NUM_ADC_USERS > 8)
00013 #error NUM_ADC_USERS must not be greater than 8, or int8u variables in adc.c must be changed
00014 #endif
00015
00016 static int16u adcData;
00017 static int8u adcPendingRequests;
00018 volatile static int8u adcPendingConversion;
00019 static int8u adcReadingValid;
00020 static int16u adcReadings[NUM_ADC_USERS];
00021 static int16u adcConfig[NUM_ADC_USERS];
00022 static boolean adcCalibrated;
00023 static int16s Nvss;
00024 static int16s Nvdd;
00025
00026
00027
00028
00029
00030
00031
00032 #ifdef ENABLE_ADC_EXTENDED_RANGE_BROKEN
00033 static int16s Nvref;
00034 static int16s Nvref2;
00035 #endif
00036 static int16u adcStaticConfig;
00037
00038 void halAdcSetClock(boolean slow)
00039 {
00040 if (slow) {
00041 adcStaticConfig |= ADC_1MHZCLK_MASK;
00042 } else {
00043 adcStaticConfig &= ~ADC_1MHZCLK_MASK;
00044 }
00045 }
00046
00047 void halAdcSetRange(boolean high)
00048 {
00049 if (high) {
00050 adcStaticConfig |= (ADC_HVSELP_MASK | ADC_HVSELN_MASK);
00051 } else {
00052 adcStaticConfig &= ~(ADC_HVSELP_MASK | ADC_HVSELN_MASK);
00053 }
00054 }
00055
00056 boolean halAdcGetClock(void)
00057 {
00058
00059 return (adcStaticConfig & ADC_1MHZCLK_MASK) ? TRUE : FALSE;
00060 }
00061
00062 boolean halAdcGetRange(void)
00063 {
00064
00065 return (adcStaticConfig & ((ADC_HVSELP_MASK | ADC_HVSELN_MASK))) ? TRUE : FALSE;
00066 }
00067
00068
00069
00070
00071 #define ADC_CHAN (ADC_MUXP | ADC_MUXN)
00072 #define ADC_CHAN_BIT ADC_MUXN_BIT
00073
00074 void halAdcIsr(void)
00075 {
00076 int8u i;
00077 int8u conversion = adcPendingConversion;
00078
00079
00080 if ( (INT_ADCFLAG & INT_ADCULDFULL)
00081 && (conversion < NUM_ADC_USERS) ) {
00082 adcReadings[conversion] = adcData;
00083 adcReadingValid |= BIT(conversion);
00084
00085 if (adcPendingRequests) {
00086 for (i = 0; i < NUM_ADC_USERS; i++) {
00087 if (BIT(i) & adcPendingRequests) {
00088 adcPendingConversion = i;
00089 adcPendingRequests ^= BIT(i);
00090 ADC_CFG = adcConfig[i];
00091 break;
00092 }
00093 }
00094 } else {
00095 ADC_CFG = 0;
00096 adcPendingConversion = NUM_ADC_USERS;
00097 }
00098 }
00099 INT_ADCFLAG = 0xFFFF;
00100 asm("DMB");
00101 }
00102
00103
00104
00105
00106 ADCUser startNextConversion()
00107 {
00108 int8u i;
00109
00110 ATOMIC (
00111
00112 if (adcPendingRequests && !(ADC_CFG & ADC_ENABLE)) {
00113 for (i = 0; i < NUM_ADC_USERS; i++) {
00114 if ( BIT(i) & adcPendingRequests) {
00115 adcPendingConversion = i;
00116 adcPendingRequests ^= BIT(i);
00117 ADC_CFG = adcConfig[i];
00118 INT_ADCFLAG = 0xFFFF;
00119 INT_CFGSET = INT_ADC;
00120 break;
00121 }
00122 }
00123 } else {
00124 i = NUM_ADC_USERS;
00125 }
00126 )
00127 return i;
00128 }
00129
00130 void halInternalInitAdc(void)
00131 {
00132
00133 adcPendingRequests = 0;
00134 adcPendingConversion = NUM_ADC_USERS;
00135 adcCalibrated = FALSE;
00136 adcStaticConfig = ADC_1MHZCLK | ADC_ENABLE;
00137
00138
00139 adcReadingValid = 0;
00140
00141
00142 ADC_CFG = 0;
00143 ADC_OFFSET = ADC_OFFSET_RESET;
00144 ADC_GAIN = ADC_GAIN_RESET;
00145 ADC_DMACFG = ADC_DMARST;
00146 ADC_DMABEG = (int32u)&adcData;
00147 ADC_DMASIZE = 1;
00148 ADC_DMACFG = (ADC_DMAAUTOWRAP | ADC_DMALOAD);
00149
00150
00151 INT_ADCCFG = INT_ADCULDFULL;
00152 INT_ADCFLAG = 0xFFFF;
00153 INT_CFGSET = INT_ADC;
00154
00155 stCalibrateVref();
00156 }
00157
00158 StStatus halStartAdcConversion(ADCUser id,
00159 ADCReferenceType reference,
00160 ADCChannelType channel,
00161 ADCRateType rate)
00162 {
00163
00164 if(reference != ADC_REF_INT)
00165 return ST_ERR_FATAL;
00166
00167
00168 adcConfig[id] = ( ((rate << ADC_PERIOD_BIT) & ADC_PERIOD)
00169 | ((channel << ADC_CHAN_BIT) & ADC_CHAN)
00170 | adcStaticConfig);
00171
00172
00173 if (adcPendingRequests & BIT(id)) {
00174 return ST_ADC_CONVERSION_DEFERRED;
00175 }
00176
00177 ATOMIC (
00178
00179 adcPendingRequests |= BIT(id);
00180
00181 adcReadingValid &= ~BIT(id);
00182 )
00183 if (startNextConversion() == id)
00184 return ST_ADC_CONVERSION_BUSY;
00185 else
00186 return ST_ADC_CONVERSION_DEFERRED;
00187 }
00188
00189 StStatus halRequestAdcData(ADCUser id, int16u *value)
00190 {
00191
00192
00193 boolean intsAreOff = ( INTERRUPTS_ARE_OFF()
00194 || !(INT_CFGSET & INT_ADC)
00195 || !(INT_ADCCFG & INT_ADCULDFULL) );
00196 StStatus stat;
00197
00198 ATOMIC (
00199
00200
00201
00202 if( intsAreOff
00203 && ( (INT_CFGSET & INT_ADC) && (INT_ADCCFG & INT_ADCULDFULL) )) {
00204 halAdcIsr();
00205 }
00206
00207
00208 if (BIT(id) & adcReadingValid) {
00209 *value = adcReadings[id];
00210 adcReadingValid ^= BIT(id);
00211 stat = ST_ADC_CONVERSION_DONE;
00212 } else if (adcPendingRequests & BIT(id)) {
00213 stat = ST_ADC_CONVERSION_DEFERRED;
00214 } else if (adcPendingConversion == id) {
00215 stat = ST_ADC_CONVERSION_BUSY;
00216 } else {
00217 stat = ST_ADC_NO_CONVERSION_PENDING;
00218 }
00219 )
00220 return stat;
00221 }
00222
00223 StStatus halReadAdcBlocking(ADCUser id, int16u *value)
00224 {
00225 StStatus stat;
00226
00227 do {
00228 stat = halRequestAdcData(id, value);
00229 if (stat == ST_ADC_NO_CONVERSION_PENDING)
00230 break;
00231 } while(stat != ST_ADC_CONVERSION_DONE);
00232 return stat;
00233 }
00234
00235 StStatus halAdcCalibrate(ADCUser id)
00236 {
00237 StStatus stat;
00238
00239
00240
00241
00242
00243
00244
00245 #ifdef ENABLE_ADC_EXTENDED_RANGE_BROKEN
00246 if(halAdcGetRange()){
00247
00248 halStartAdcConversion(id,
00249 ADC_REF_INT,
00250 ADC_SOURCE_VREF_VREF2,
00251 ADC_CONVERSION_TIME_US_4096);
00252
00253 stat = halReadAdcBlocking(id, (int16u *)(&Nvref));
00254 if (stat == ST_ADC_CONVERSION_DONE) {
00255 halStartAdcConversion(id,
00256 ADC_REF_INT,
00257 ADC_SOURCE_VREF2_VREF2,
00258 ADC_CONVERSION_TIME_US_4096);
00259 stat = halReadAdcBlocking(id, (int16u *)(&Nvref2));
00260 }
00261 if (stat == ST_ADC_CONVERSION_DONE) {
00262 adcCalibrated = TRUE;
00263 } else {
00264 adcCalibrated = FALSE;
00265 stat = ST_ERR_FATAL;
00266 }
00267 return stat;
00268
00269 }
00270 #endif
00271 halStartAdcConversion(id,
00272 ADC_REF_INT,
00273 ADC_SOURCE_GND_VREF2,
00274 ADC_CONVERSION_TIME_US_4096);
00275 stat = halReadAdcBlocking(id, (int16u *)(&Nvss));
00276 if (stat == ST_ADC_CONVERSION_DONE) {
00277 halStartAdcConversion(id,
00278 ADC_REF_INT,
00279 ADC_SOURCE_VREG2_VREF2,
00280 ADC_CONVERSION_TIME_US_4096);
00281 stat = halReadAdcBlocking(id, (int16u *)(&Nvdd));
00282 }
00283 if (stat == ST_ADC_CONVERSION_DONE) {
00284 Nvdd -= Nvss;
00285 adcCalibrated = TRUE;
00286 } else {
00287 adcCalibrated = FALSE;
00288 stat = ST_ERR_FATAL;
00289 }
00290 return stat;
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300 int16s halConvertValueToVolts(int16u value)
00301 {
00302 int32s N;
00303 int16s V;
00304 int32s nvalue;
00305
00306 if (!adcCalibrated) {
00307 halAdcCalibrate(ADC_USER_LQI);
00308 }
00309 if (adcCalibrated) {
00310
00311
00312
00313
00314
00315
00316
00317 #ifdef ENABLE_ADC_EXTENDED_RANGE_BROKEN
00318 if(halAdcGetRange()){
00319
00320 N = (((int32s)value + Nvref - 2*Nvref2) << 16)/(2*(Nvref-Nvref2));
00321
00322
00323 V = (int16s)((N*12000L) >> 16);
00324 if (V > 21000) {
00325 V = 21000;
00326 }
00327
00328 }
00329 else {
00330 #endif
00331 assert(Nvdd);
00332 nvalue = value - Nvss;
00333
00334 N = ((nvalue << 16) + Nvdd/2) / Nvdd;
00335
00336
00337
00338
00339 V = (int16s)((N*9000L) >> 16);
00340 if (V > 12000) {
00341 V = 12000;
00342 }
00343 #ifdef ENABLE_ADC_EXTENDED_RANGE_BROKEN
00344 }
00345 #endif
00346 } else {
00347 V = -32768;
00348 }
00349 return V;
00350 }