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