Contiki 2.5
micro-common-internal.c
1 /*
2  * File: micro-common-internal.c
3  * Description: STM32W108 internal, micro specific HAL functions.
4  * This file is provided for completeness and it should not be modified
5  * by customers as it comtains code very tightly linked to undocumented
6  * device features
7  *
8  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved. -->
9  */
10 
11 #include PLATFORM_HEADER
12 #include "error.h"
13 #include "hal/micro/micro-common.h"
16 
17 #define HAL_STANDALONE
18 #ifdef HAL_STANDALONE
19 
20 #define AUXADC_REG (0xC0u)
21 #define DUMMY 0
22 
23 #define ADC_6MHZ_CLOCK 0
24 #define ADC_1MHZ_CLOCK 1
25 
26 #define ADC_SAMPLE_CLOCKS_32 0
27 #define ADC_SAMPLE_CLOCKS_64 1
28 #define ADC_SAMPLE_CLOCKS_128 2
29 #define ADC_SAMPLE_CLOCKS_256 3
30 #define ADC_SAMPLE_CLOCKS_512 4
31 #define ADC_SAMPLE_CLOCKS_1024 5
32 #define ADC_SAMPLE_CLOCKS_2048 6
33 #define ADC_SAMPLE_CLOCKS_4096 7
34 
35 #define CAL_ADC_CHANNEL_VDD_4 0x00 //VDD_PADS/4
36 #define CAL_ADC_CHANNEL_VREG_2 0x01 //VREG_OUT/2
37 #define CAL_ADC_CHANNEL_TEMP 0x02
38 #define CAL_ADC_CHANNEL_GND 0x03
39 #define CAL_ADC_CHANNEL_VREF 0x04
40 #define CAL_ADC_CHANNEL_I 0x06
41 #define CAL_ADC_CHANNEL_Q 0x07
42 #define CAL_ADC_CHANNEL_ATEST_A 0x09
43 
44 void stCalibrateVref(void)
45 {
46  // Calibrate Vref by measuring a known voltage, Vdd/2.
47  //
48  // FIXME: add support for calibration if done in boost mode.
49  tokTypeMfgAnalogueTrimBoth biasTrim;
50 
51  halCommonGetMfgToken(&biasTrim, TOKEN_MFG_ANALOG_TRIM_BOTH);
52 
53  if(biasTrim.auxadc == 0xFFFF) {
54  assert(FALSE);
55  } else {
56  //The bias trim token is set, so use the trim directly
57  int16u temp_value;
58  int16u mask = 0xFFFF;
59 
60  // halClearLed(BOARDLED3);
61 
62  while (SCR_BUSY_REG) ;
63 
64  SCR_ADDR_REG = AUXADC_REG ; // prepare the address to write to
65 
66  // initiate read (starts on falling edge of SCR_CTRL_SCR_READ)
67  SCR_CTRL_REG = SCR_CTRL_SCR_READ_MASK;
68  SCR_CTRL_REG = 0;
69 
70  // wait for read to complete
71  while (SCR_BUSY_REG) ;
72 
73  temp_value = SCR_READ_REG & ~mask;
74  temp_value |= biasTrim.auxadc & mask;
75 
76  SCR_WRITE_REG = temp_value;
77 
78  // initiate write (starts on falling edge of SCR_CTRL_SCR_WRITE_MASK)
79  SCR_CTRL_REG = SCR_CTRL_SCR_WRITE_MASK;
80  SCR_CTRL_REG = 0;
81 
82  while (SCR_BUSY_REG) ;
83 
84  }
85 }
86 
87 
88 void calDisableAdc(void) {
89  // Disable the Calibration ADC to save current.
90  CAL_ADC_CONFIG &= ~CAL_ADC_CONFIG_CAL_ADC_EN;
91 }
92 
93 
94 
95 // These routines maintain the same signature as their hal- counterparts to
96 // facilitate simple support between phys.
97 // It is assumed (hoped?) that the compiler will optimize out unused arguments.
98 StStatus calStartAdcConversion(int8u dummy1, // Not used.
99  int8u dummy2, // Not used.
100  int8u channel,
101  int8u rate,
102  int8u clock) {
103  // Disable the Calibration ADC interrupt so that we can poll it.
104  INT_MGMTCFG &= ~INT_MGMTCALADC;
105 
106  ATOMIC(
107  // Enable the Calibration ADC, choose source, set rate, and choose clock.
108  CAL_ADC_CONFIG =((CAL_ADC_CONFIG_CAL_ADC_EN) |
109  (channel << CAL_ADC_CONFIG_CAL_ADC_MUX_BIT) |
110  (rate << CAL_ADC_CONFIG_CAL_ADC_RATE_BIT) |
111  (clock << CAL_ADC_CONFIG_CAL_ADC_CLKSEL_BIT) );
112  // Clear any pending Calibration ADC interrupt. Since we're atomic, the
113  // one we're interested in hasn't happened yet (will take ~10us at minimum).
114  // We're only clearing stale info.
115  INT_MGMTFLAG = INT_MGMTCALADC;
116  )
117  return ST_SUCCESS;
118 }
119 
120 
121 StStatus calReadAdcBlocking(int8u dummy,
122  int16u *value) {
123  // Wait for conversion to complete.
124  while ( ! (INT_MGMTFLAG & INT_MGMTCALADC) );
125  // Clear the interrupt for this conversion.
126  INT_MGMTFLAG = INT_MGMTCALADC;
127  // Get the result.
128  *value = (int16u)CAL_ADC_DATA;
129  return ST_SUCCESS;
130 }
131 
132 
133 
134 
135 //Using 6MHz clock reduces resolution but greatly increases conversion speed.
136 //The sample clocks were chosen based upon empirical evidence and provided
137 //the fastest conversions with the greatest reasonable accuracy. Variation
138 //across successive conversions appears to be +/-20mv of the average
139 //conversion. Overall function time is <150us.
140 int16u stMeasureVddFast(void)
141 {
142  int16u value;
143  int32u Ngnd;
144  int32u Nreg;
145  int32u Nvdd;
146  tokTypeMfgRegVoltage1V8 vregOutTok;
147  halCommonGetMfgToken(&vregOutTok, TOKEN_MFG_1V8_REG_VOLTAGE);
148 
149  //Measure GND
150  calStartAdcConversion(DUMMY,
151  DUMMY,
152  CAL_ADC_CHANNEL_GND,
153  ADC_SAMPLE_CLOCKS_128,
154  ADC_6MHZ_CLOCK);
155  calReadAdcBlocking(DUMMY, &value);
156  Ngnd = (int32u)value;
157 
158  //Measure VREG_OUT/2
159  calStartAdcConversion(DUMMY,
160  DUMMY,
161  CAL_ADC_CHANNEL_VREG_2,
162  ADC_SAMPLE_CLOCKS_128,
163  ADC_6MHZ_CLOCK);
164  calReadAdcBlocking(DUMMY, &value);
165  Nreg = (int32u)value;
166 
167  //Measure VDD_PADS/4
168  calStartAdcConversion(DUMMY,
169  DUMMY,
170  CAL_ADC_CHANNEL_VDD_4,
171  ADC_SAMPLE_CLOCKS_128,
172  ADC_6MHZ_CLOCK);
173  calReadAdcBlocking(DUMMY, &value);
174  Nvdd = (int32u)value;
175 
176  calDisableAdc();
177 
178  //Convert the value into mV. VREG_OUT is ideally 1.8V, but it wont be
179  //exactly 1.8V. The actual value is stored in the manufacturing token
180  //TOKEN_MFG_1V8_REG_VOLTAGE. The token stores the value in 10^-4, but we
181  //need 10^-3 so divide by 10. If this token is not set (0xFFFF), then
182  //assume 1800mV.
183  if(vregOutTok == 0xFFFF) {
184  vregOutTok = 1800;
185  } else {
186  vregOutTok /= 10;
187  }
188  return ((((((Nvdd-Ngnd)<<16)/(Nreg-Ngnd))*vregOutTok)*2)>>16);
189 }
190 #endif
191 
193 {
194  if(stMeasureVddFast() < 2700) {
195  GPIO_DBGCFG |= GPIO_DBGCFGRSVD;
196  } else {
197  GPIO_DBGCFG &= ~GPIO_DBGCFGRSVD;
198  }
199 }
200 
201 
202 void halInternalSetRegTrim(boolean boostMode)
203 {
204  tokTypeMfgRegTrim regTrim;
205  int8u trim1V2;
206  int8u trim1V8;
207 
208  halCommonGetMfgToken(&regTrim, TOKEN_MFG_REG_TRIM);
209  // The compiler can optimize this function a bit more and keep the
210  // values in processor registers if we use separate local vars instead
211  // of just accessing via the structure fields
212  trim1V8 = regTrim.regTrim1V8;
213  trim1V2 = regTrim.regTrim1V2;
214 
215  //If tokens are erased, default to reasonable values, otherwise use the
216  //token values.
217  if((trim1V2 == 0xFF) && (trim1V8 == 0xFF)) {
218  trim1V8 = 4;
219  trim1V2 = 0;
220  }
221 
222  //When the radio is in boost mode, we have to increase the 1.8V trim.
223  if(boostMode) {
224  trim1V8 += 2;
225  }
226 
227  //Clamp at 7 to ensure we don't exceed max values, accidentally set
228  //other bits, or wrap values.
229  if(trim1V8>7) {
230  trim1V8 = 7;
231  }
232  if(trim1V2>7) {
233  trim1V2 = 7;
234  }
235 
236  VREG_REG = ( (trim1V8<<VREG_VREG_1V8_TRIM_BIT) |
237  (trim1V2<<VREG_VREG_1V2_TRIM_BIT) );
238 }
239 
240 
241 // halCommonDelayMicroseconds
242 // -enables MAC Timer and leaves it enabled.
243 // -does not touch MAC Timer Compare registers.
244 // -max delay is 65535 usec.
245 // NOTE: This function primarily designed for when the chip is running off of
246 // the XTAL, which is the most common situation. When running from
247 // OSCHF, though, the clock speed is cut in half, so the input parameter
248 // is divided by two. With respect to accuracy, we're now limited by
249 // the accuracy of OSCHF (much lower than XTAL).
251 {
252  int32u beginTime = ReadRegister(MAC_TIMER);
253 
254  //If we're not using the XTAL, the MAC Timer is running off OSCHF,
255  //that means the clock is half speed, 6MHz. We need to halve our delay
256  //time.
257  if((OSC24M_CTRL&OSC24M_CTRL_OSC24M_SEL)!=OSC24M_CTRL_OSC24M_SEL) {
258  us >>= 1;
259  }
260 
261  //we have about 2us of overhead in the calculations
262  if(us<=2) {
263  return;
264  }
265 
266  // MAC Timer is enabled in stmRadioInit, which may not have been called yet.
267  // This algorithm needs the MAC Timer so we enable it here.
268  MAC_TIMER_CTRL |= MAC_TIMER_CTRL_MAC_TIMER_EN;
269 
270  // since our max delay (65535<<1) is less than half the size of the
271  // 20 bit mac timer, we can easily just handle the potential for
272  // mac timer wrapping by subtracting the time delta and masking out
273  // the extra bits
274  while( ((MAC_TIMER-beginTime)&MAC_TIMER_MAC_TIMER_MASK) < us ) {
275  ; // spin
276  }
277 }
278 
279 
280 //Burning cycles for milliseconds is generally a bad idea, but it is
281 //necessary in some situations. If you have to burn more than 65ms of time,
282 //the halCommonDelayMicroseconds function becomes cumbersome, so this
283 //function gives you millisecond granularity.
285 {
286  if(ms==0) {
287  return;
288  }
289 
290  while(ms-->0) {
292  }
293 }