micro-common-internal.c

00001 /*
00002  * File: micro-common-internal.c
00003  * Description: STM32W108 internal, micro specific HAL functions.
00004  * This file is provided for completeness and it should not be modified
00005  * by customers as it comtains code very tightly linked to undocumented
00006  * device features
00007  *
00008  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved.        -->
00009  */
00010 
00011 #include PLATFORM_HEADER
00012 #include "error.h"
00013 #include "hal/micro/micro-common.h"
00014 #include "hal/micro/cortexm3/micro-common.h"
00015 #include "hal/micro/cortexm3/mfg-token.h"
00016 
00017 #define HAL_STANDALONE
00018 #ifdef HAL_STANDALONE
00019 
00020 #define AUXADC_REG (0xC0u)
00021 #define DUMMY                   0
00022 
00023 #define ADC_6MHZ_CLOCK          0
00024 #define ADC_1MHZ_CLOCK          1
00025 
00026 #define ADC_SAMPLE_CLOCKS_32    0
00027 #define ADC_SAMPLE_CLOCKS_64    1
00028 #define ADC_SAMPLE_CLOCKS_128   2
00029 #define ADC_SAMPLE_CLOCKS_256   3
00030 #define ADC_SAMPLE_CLOCKS_512   4
00031 #define ADC_SAMPLE_CLOCKS_1024  5
00032 #define ADC_SAMPLE_CLOCKS_2048  6
00033 #define ADC_SAMPLE_CLOCKS_4096  7
00034 
00035 #define CAL_ADC_CHANNEL_VDD_4   0x00  //VDD_PADS/4
00036 #define CAL_ADC_CHANNEL_VREG_2  0x01  //VREG_OUT/2
00037 #define CAL_ADC_CHANNEL_TEMP    0x02
00038 #define CAL_ADC_CHANNEL_GND     0x03
00039 #define CAL_ADC_CHANNEL_VREF    0x04
00040 #define CAL_ADC_CHANNEL_I       0x06
00041 #define CAL_ADC_CHANNEL_Q       0x07
00042 #define CAL_ADC_CHANNEL_ATEST_A 0x09
00043 
00044 void stCalibrateVref(void)
00045 {
00046   // Calibrate Vref by measuring a known voltage, Vdd/2.
00047   //
00048   // FIXME: add support for calibration if done in boost mode.
00049   extern int16u stmRadioTxPowerMode;
00050   tokTypeMfgAnalogueTrimBoth biasTrim;
00051   
00052   halCommonGetMfgToken(&biasTrim, TOKEN_MFG_ANALOG_TRIM_BOTH);
00053   
00054   if(biasTrim.auxadc == 0xFFFF) {
00055     assert(FALSE);
00056   } else {
00057     //The bias trim token is set, so use the trim directly
00058     int16u temp_value;
00059     int16u mask = 0xFFFF;
00060 
00061     // halClearLed(BOARDLED3);
00062 
00063     while (SCR_BUSY_REG) ;
00064 
00065     SCR_ADDR_REG = AUXADC_REG ;  // prepare the address to write to
00066 
00067     // initiate read (starts on falling edge of SCR_CTRL_SCR_READ)
00068     SCR_CTRL_REG = SCR_CTRL_SCR_READ_MASK;
00069     SCR_CTRL_REG = 0;
00070 
00071     // wait for read to complete
00072     while (SCR_BUSY_REG) ;
00073 
00074     temp_value = SCR_READ_REG & ~mask;
00075     temp_value |= biasTrim.auxadc & mask;
00076     
00077     SCR_WRITE_REG = temp_value;
00078 
00079     // initiate write (starts on falling edge of SCR_CTRL_SCR_WRITE_MASK)
00080     SCR_CTRL_REG = SCR_CTRL_SCR_WRITE_MASK;
00081     SCR_CTRL_REG = 0;
00082 
00083     while (SCR_BUSY_REG) ;
00084     
00085   }
00086 }
00087 
00088 
00089 void calDisableAdc(void) {
00090   // Disable the Calibration ADC to save current.
00091   CAL_ADC_CONFIG &= ~CAL_ADC_CONFIG_CAL_ADC_EN;
00092 }
00093 
00094 
00095 
00096 // These routines maintain the same signature as their hal- counterparts to
00097 // facilitate simple support between phys.
00098 // It is assumed (hoped?) that the compiler will optimize out unused arguments.
00099 StStatus calStartAdcConversion(int8u dummy1, // Not used.
00100                                   int8u dummy2, // Not used.
00101                                   int8u channel,
00102                                   int8u rate,
00103                                   int8u clock) {
00104   // Disable the Calibration ADC interrupt so that we can poll it.
00105   INT_MGMTCFG &= ~INT_MGMTCALADC;
00106 
00107   ATOMIC(
00108     // Enable the Calibration ADC, choose source, set rate, and choose clock.
00109     CAL_ADC_CONFIG =((CAL_ADC_CONFIG_CAL_ADC_EN)                  |
00110                      (channel << CAL_ADC_CONFIG_CAL_ADC_MUX_BIT)  |
00111                      (rate << CAL_ADC_CONFIG_CAL_ADC_RATE_BIT)    |
00112                      (clock << CAL_ADC_CONFIG_CAL_ADC_CLKSEL_BIT) );
00113     // Clear any pending Calibration ADC interrupt.  Since we're atomic, the
00114     // one we're interested in hasn't happened yet (will take ~10us at minimum).
00115     // We're only clearing stale info.
00116     INT_MGMTFLAG = INT_MGMTCALADC;
00117   )
00118   return ST_SUCCESS;
00119 }
00120 
00121 
00122 StStatus calReadAdcBlocking(int8u  dummy,
00123                                int16u *value) {
00124   // Wait for conversion to complete.
00125   while ( ! (INT_MGMTFLAG & INT_MGMTCALADC) );
00126   // Clear the interrupt for this conversion.
00127   INT_MGMTFLAG = INT_MGMTCALADC;
00128   // Get the result.
00129   *value = (int16u)CAL_ADC_DATA;
00130   return ST_SUCCESS;
00131 }
00132 
00133 
00134 
00135 
00136 //Using 6MHz clock reduces resolution but greatly increases conversion speed.
00137 //The sample clocks were chosen based upon empirical evidence and provided
00138 //the fastest conversions with the greatest reasonable accuracy.  Variation
00139 //across successive conversions appears to be +/-20mv of the average
00140 //conversion.  Overall function time is <150us.
00141 int16u stMeasureVddFast(void)
00142 {
00143   int16u value;
00144   int32u Ngnd;
00145   int32u Nreg;
00146   int32u Nvdd;
00147   tokTypeMfgRegVoltage1V8 vregOutTok;
00148   halCommonGetMfgToken(&vregOutTok, TOKEN_MFG_1V8_REG_VOLTAGE);
00149   
00150   //Measure GND
00151   calStartAdcConversion(DUMMY,
00152                         DUMMY,
00153                         CAL_ADC_CHANNEL_GND,
00154                         ADC_SAMPLE_CLOCKS_128,
00155                         ADC_6MHZ_CLOCK);
00156   calReadAdcBlocking(DUMMY, &value);
00157   Ngnd = (int32u)value;
00158   
00159   //Measure VREG_OUT/2
00160   calStartAdcConversion(DUMMY,
00161                         DUMMY,
00162                         CAL_ADC_CHANNEL_VREG_2,
00163                         ADC_SAMPLE_CLOCKS_128,
00164                         ADC_6MHZ_CLOCK);
00165   calReadAdcBlocking(DUMMY, &value);
00166   Nreg = (int32u)value;
00167   
00168   //Measure VDD_PADS/4
00169   calStartAdcConversion(DUMMY,
00170                         DUMMY,
00171                         CAL_ADC_CHANNEL_VDD_4,
00172                         ADC_SAMPLE_CLOCKS_128,
00173                         ADC_6MHZ_CLOCK);
00174   calReadAdcBlocking(DUMMY, &value);
00175   Nvdd = (int32u)value;
00176   
00177   calDisableAdc();
00178   
00179   //Convert the value into mV.  VREG_OUT is ideally 1.8V, but it wont be
00180   //exactly 1.8V.  The actual value is stored in the manufacturing token
00181   //TOKEN_MFG_1V8_REG_VOLTAGE.  The token stores the value in 10^-4, but we
00182   //need 10^-3 so divide by 10.  If this token is not set (0xFFFF), then
00183   //assume 1800mV.
00184   if(vregOutTok == 0xFFFF) {
00185     vregOutTok = 1800;
00186   } else {
00187     vregOutTok /= 10;
00188   }
00189   return ((((((Nvdd-Ngnd)<<16)/(Nreg-Ngnd))*vregOutTok)*2)>>16);
00190 }
00191 #endif
00192 
00193 void halCommonCalibratePads(void)
00194 {
00195   if(stMeasureVddFast() < 2700) {
00196     GPIO_DBGCFG |= GPIO_DBGCFGRSVD;
00197   } else {
00198     GPIO_DBGCFG &= ~GPIO_DBGCFGRSVD;
00199   }
00200 }
00201 
00202 
00203 void halInternalSetRegTrim(boolean boostMode)
00204 {
00205   tokTypeMfgRegTrim regTrim;
00206   int8u trim1V2;
00207   int8u trim1V8;
00208   
00209   halCommonGetMfgToken(&regTrim, TOKEN_MFG_REG_TRIM);
00210   // The compiler can optimize this function a bit more and keep the 
00211   // values in processor registers if we use separate local vars instead
00212   // of just accessing via the structure fields
00213   trim1V8 = regTrim.regTrim1V8;
00214   trim1V2 = regTrim.regTrim1V2;
00215   
00216   //If tokens are erased, default to reasonable values, otherwise use the
00217   //token values.
00218   if((trim1V2 == 0xFF) && (trim1V8 == 0xFF)) {
00219     trim1V8 = 4;
00220     trim1V2 = 0;
00221   }
00222   
00223   //When the radio is in boost mode, we have to increase the 1.8V trim.
00224   if(boostMode) {
00225     trim1V8 += 2;
00226   }
00227   
00228   //Clamp at 7 to ensure we don't exceed max values, accidentally set
00229   //other bits, or wrap values.
00230   if(trim1V8>7) {
00231     trim1V8 = 7;
00232   }
00233   if(trim1V2>7) {
00234     trim1V2 = 7;
00235   }
00236   
00237   VREG_REG = ( (trim1V8<<VREG_VREG_1V8_TRIM_BIT) |
00238                (trim1V2<<VREG_VREG_1V2_TRIM_BIT) );
00239 }
00240 
00241 
00242 // halCommonDelayMicroseconds
00243 // -enables MAC Timer and leaves it enabled.
00244 // -does not touch MAC Timer Compare registers.
00245 // -max delay is 65535 usec.
00246 // NOTE: This function primarily designed for when the chip is running off of
00247 //       the XTAL, which is the most common situation.  When running from
00248 //       OSCHF, though, the clock speed is cut in half, so the input parameter
00249 //       is divided by two.  With respect to accuracy, we're now limited by
00250 //       the accuracy of OSCHF (much lower than XTAL).
00251 void halCommonDelayMicroseconds(int16u us)
00252 {
00253   int32u beginTime = ReadRegister(MAC_TIMER);
00254   
00255   //If we're not using the XTAL, the MAC Timer is running off OSCHF,
00256   //that means the clock is half speed, 6MHz.  We need to halve our delay
00257   //time.
00258   if((OSC24M_CTRL&OSC24M_CTRL_OSC24M_SEL)!=OSC24M_CTRL_OSC24M_SEL) {
00259     us >>= 1;
00260   }
00261     
00262   //we have about 2us of overhead in the calculations
00263   if(us<=2) {
00264     return;
00265   }
00266   
00267   // MAC Timer is enabled in stmRadioInit, which may not have been called yet.
00268   // This algorithm needs the MAC Timer so we enable it here.
00269   MAC_TIMER_CTRL |= MAC_TIMER_CTRL_MAC_TIMER_EN;
00270 
00271   // since our max delay (65535<<1) is less than half the size of the 
00272   //  20 bit mac timer, we can easily just handle the potential for
00273   //  mac timer wrapping by subtracting the time delta and masking out
00274   //  the extra bits
00275   while( ((MAC_TIMER-beginTime)&MAC_TIMER_MAC_TIMER_MASK) < us ) {
00276     ; // spin
00277   }
00278 }
00279 
00280 
00281 //Burning cycles for milliseconds is generally a bad idea, but it is
00282 //necessary in some situations.  If you have to burn more than 65ms of time,
00283 //the halCommonDelayMicroseconds function becomes cumbersome, so this
00284 //function gives you millisecond granularity.
00285 void halCommonDelayMilliseconds(int16u ms)
00286 {
00287   if(ms==0) {
00288     return;
00289   }
00290   
00291   while(ms-->0) {
00292     halCommonDelayMicroseconds(1000);
00293   }
00294 }

Generated on Mon Apr 11 14:23:40 2011 for Contiki 2.5 by  doxygen 1.6.1