# SFBPower.h

Go to the documentation of this file.

    00001 /*
    00002   SFBPower.h Power control and monitoring routines for the SFB.
    00003   Copyright (C) 2009 The Regents of the University of New Mexico.  All rights reserved.
    00004
    00005   This library is free software; you can redistribute it and/or
    00006   modify it under the terms of the GNU Lesser General Public
    00007   License as published by the Free Software Foundation; either
    00008   version 2.1 of the License, or (at your option) any later version.
    00009
    00010   This library is distributed in the hope that it will be useful,
    00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013   Lesser General Public License for more details.
    00014
    00015   You should have received a copy of the GNU General Public License
    00016   along with this library; if not, write to the Free Software
    00017   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
    00018   USA
    00019
    00020   $Id$
    00021 */
    00022
    00030 #ifndef SFBPOWER_H
    00031 #define SFBPOWER_H
    00032
    00033 #include "SFBTypes.h"     /* For u8 */
    00034 #include "SFBConstants.h" /* For FACE_COUNT */
    00035 #include "SFBAssert.h"    /* For API_ASSERT_MAX */
    00036
    00037 extern int powerDraw();
    00038
    00039 extern int powerDraw(u32 face);
    00040
    00041 extern int rawPower(u32 face);
    00042
    00060 extern s32 faceVoltage(u32 face, bool smoothed = true) ;
    00061
    00079 extern s32 railVoltage(bool smoothed = true) ;
    00080
    00081 extern int rawVoltage();
    00082
    00088 extern void powerOut(u32 face, int on);
    00089
    00096 extern bool isPowerOut(u32 face);
    00097
    00098 extern void powerIn(u32 face, int on);
    00099
    00100 /* Set all outbound power ON */
    00101 extern void initPowerOuts();
    00102
    00107 extern void invalidateCalibrationData();
    00108
    00109 enum ADCSampleIndices {
    00110   NORTH_VSENSE_ADC_IDX,
    00111   SOUTH_VSENSE_ADC_IDX,
    00112   EAST_VSENSE_ADC_IDX,
    00113   WEST_VSENSE_ADC_IDX,
    00114   VEE_VSENSE_ADC_IDX,
    00115   VSENSE_IDX_COUNT,
    00116
    00117   VCC_VSENSE_ADC_IDX = VSENSE_IDX_COUNT,
    00118
    00119   NORTH_ISENSE_ADC_IDX,
    00120   SOUTH_ISENSE_ADC_IDX,
    00121   EAST_ISENSE_ADC_IDX,
    00122   WEST_ISENSE_ADC_IDX,
    00123   ADC_IDX_COUNT
    00124 };
    00125
    00126 #define ADC_NOMINAL_MV_PER_COUNT 3.22581
    00127 #define ADC_FACE_RATIO 10.0
    00128 #define ADC_VCC_RATIO 2.0
    00129
    00130 #define NOMINAL_COUNTS_FOR_MV_FACE(mv) ((u32) (0.5+((mv)/ADC_NOMINAL_MV_PER_COUNT/ADC_FACE_RATIO)))
    00131 #define NOMINAL_COUNTS_FOR_MV_VCC(mv) ((u32) (0.5+((mv)/ADC_NOMINAL_MV_PER_COUNT/ADC_VCC_RATIO)))
    00132 #define NOMINAL_MV_FOR_COUNT_FACE(count) ((u32) (0.5+((count)*ADC_NOMINAL_MV_PER_COUNT*ADC_FACE_RATIO)))
    00133
    00134 #define EXTRA_SLOPE_BITS 6
    00135 #define UNCALIBRATED_SLOPE_FACE ((u32) ((ADC_NOMINAL_MV_PER_COUNT*ADC_FACE_RATIO)*(1<<EXTRA_SLOPE_BITS)))
    00136 #define UNCALIBRATED_CUTOFF 300
    00137 #define UNCALIBRATED_INTERCEPT_FACE (UNCALIBRATED_CUTOFF*UNCALIBRATED_SLOPE_FACE)
    00138
    00139 #define CUTOFF_INDEX 0
    00140 #define CUTOFF_BITS 5
    00141 #define CUTOFF_CENTER 16
    00142 #define CUTOFF_CT_PER_VALUE 10
    00143 #define CUTOFF_OFFSET 300
    00144
    00145 #define INTERCEPT_INDEX (CUTOFF_INDEX+CUTOFF_BITS)
    00146 #define INTERCEPT_BITS 5
    00147 #define INTERCEPT_CENTER 16
    00148 #define INTERCEPT_MV_PER_VALUE 25
    00149 #define INTERCEPT_OFFSET -300
    00150
    00151 #define SLOPE0_INDEX (INTERCEPT_INDEX+INTERCEPT_BITS)
    00152 #define SLOPE0_BITS 7
    00153 #define SLOPE0_CENTER 64
    00154 #define SLOPE0_SCALED_MV_PER_CT_PER_VALUE 10
    00155 #define SLOPE0_OFFSET (UNCALIBRATED_SLOPE_FACE+SLOPE0_CENTER*SLOPE0_SCALED_MV_PER_CT_PER_VALUE)
    00156
    00157 #define SLOPE1_INDEX (SLOPE0_INDEX+SLOPE0_BITS)
    00158 #define SLOPE1_BITS 7
    00159 #define SLOPE1_CENTER 64
    00160 #define SLOPE1_SCALED_MV_PER_CT_PER_VALUE 10
    00161 #define SLOPE1_OFFSET (UNCALIBRATED_SLOPE_FACE+SLOPE1_CENTER*SLOPE1_SCALED_MV_PER_CT_PER_VALUE)
    00162
    00163 struct xcalib {
    00164   u32 cutoff;
    00165   s32 slope[2];
    00166   s32 intercept[2];
    00167
    00168   /* Here for 'default datasheet' behavior */
    00169   void init() {
    00170     init(0, UNCALIBRATED_SLOPE_FACE, UNCALIBRATED_SLOPE_FACE, 0);
    00171   }
    00172
    00173   void init(u32 c, s32 m0, s32 m1, s32 b) {
    00174     cutoff = c;
    00175     slope[0] = m0;
    00176     intercept[0] = ((NOMINAL_MV_FOR_COUNT_FACE(c)+b)<<EXTRA_SLOPE_BITS)-m0*c;
    00177     slope[1] = m1;
    00178     intercept[1] = ((NOMINAL_MV_FOR_COUNT_FACE(c)+b)<<EXTRA_SLOPE_BITS)-m1*c;
    00179   }
    00180 };
    00181 extern xcalib adcCalibs[VSENSE_IDX_COUNT];
    00182
    00183 struct calibData {
    00184
    00185   u32 data;
    00186   inline u32 getBits(u32 bitIdx, u32 bits) {
    00187     return (data>>bitIdx)&((1<<bits)-1);
    00188   }
    00189   void putBits(u32 bitIdx, u32 bits,u32 value) {
    00190     u32 nbits = ((1<<bits)-1);
    00191     data &= ~(nbits<<bitIdx);
    00192     data |= (value&nbits)<<bitIdx;
    00193   }
    00194   void init(u32 cutoff, u32 intercept, u32 slope0, u32 slope1) {
    00195     putBits(CUTOFF_INDEX,CUTOFF_BITS,cutoff);
    00196     putBits(INTERCEPT_INDEX,INTERCEPT_BITS,intercept);
    00197     putBits(SLOPE0_INDEX,SLOPE0_BITS,slope0);
    00198     putBits(SLOPE1_INDEX,SLOPE1_BITS,slope1);
    00199   }
    00200   void getFields(u32 & cutoff, u32 & intercept, u32 & slope0, u32 & slope1) {
    00201     cutoff = getBits(CUTOFF_INDEX,CUTOFF_BITS);
    00202     intercept = getBits(INTERCEPT_INDEX,INTERCEPT_BITS);
    00203     slope0 = getBits(SLOPE0_INDEX,SLOPE0_BITS);
    00204     slope1 = getBits(SLOPE1_INDEX,SLOPE1_BITS);
    00205   }
    00206   inline s32 getValue(u32 bitIdx, u32 bits, s32 center, s32 amtPerValue, s32 offset) {
    00207     s32 value = getBits(bitIdx,bits);
    00208     return (value-center)*amtPerValue+offset;
    00209   }
    00210   s32 getCutoffCt() {
    00211     return getValue(CUTOFF_INDEX,CUTOFF_BITS,CUTOFF_CENTER,CUTOFF_CT_PER_VALUE,CUTOFF_OFFSET);
    00212   }
    00213   s32 getInterceptMv() {
    00214     return
    00215       getValue(INTERCEPT_INDEX,INTERCEPT_BITS,INTERCEPT_CENTER,INTERCEPT_MV_PER_VALUE,INTERCEPT_OFFSET);
    00216   }
    00217   s32 getSlopeScaledMvPerCt(u32 which) ;
    00218
    00219   void initXcalib(xcalib & x) ;
    00220 };
    00221
    00222 extern void initxcalibsFromGene(u32 gene[VSENSE_IDX_COUNT]) ;
    00223
    00226 #define VOLTAGE_CALIBRATION_SIZE_BYTES (VSENSE_IDX_COUNT*3)
    00227
    00228 #define ADC_SCALE_BITS 6   /* This is fixed by the AD0DRx hardware; can't be changed efficiently */
    00229 #define WEIGHT_BITS 5  /* Could be 5 for a ton of smoothing, or 3..1 for less (0 would be redundant) */
    00230 #define UPDATE_SMOOTHED_BUFFER(u16buf,adcScaledData) \
    00231   ((u16buf) = (u16) (((((u32)(u16buf))<<WEIGHT_BITS)-(u16buf)+(adcScaledData))>>WEIGHT_BITS))
    00232
    00233 static inline s32 mapADCCounts(u16 scaledCount, s32 slope, s32 intercept) {
    00234   return (((scaledCount*slope)>>ADC_SCALE_BITS)+intercept)>>EXTRA_SLOPE_BITS;
    00235 }
    00236
    00237 extern void unpackCalibrationData(u32 gene[VSENSE_IDX_COUNT], u8 bytes[VOLTAGE_CALIBRATION_SIZE_BYTES]) ;
    00238
    00239 extern void loadCalibrationData() ;
    00240
    00241 extern u16 adcLatestSample[ADC_IDX_COUNT];
    00242
    00243 extern u16 adcSmooth[ADC_IDX_COUNT];
    00244
    00245 static inline u16 getADCSample(u32 sampleIdx, bool smoothed) {
    00246   API_ASSERT_MAX(sampleIdx,ADC_IDX_COUNT);
    00247   return smoothed?adcSmooth[sampleIdx]:adcLatestSample[sampleIdx];
    00248 }
    00249
    00250 #define POWER_SENSING_FLAG_CODE 0xffff  /* Can't occur in nature: ADC always gives 6 LSBs==0 */
    00251 static inline bool powerSensingEnabled() {
    00252   return adcLatestSample[NORTH_ISENSE_ADC_IDX] != POWER_SENSING_FLAG_CODE;
    00253 }
    00254 extern void setPowerSensingEnabled(bool enable) ;
    00255
    00261 extern void initADC();
    00264 #endif /* SFBPOWER_H */