Contiki 3.x
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  uint16_t temp_value;
58  uint16_t 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(uint8_t dummy1, // Not used.
99  uint8_t dummy2, // Not used.
100  uint8_t channel,
101  uint8_t rate,
102  uint8_t 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(uint8_t dummy,
122  uint16_t *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 = (uint16_t)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 uint16_t stMeasureVddFast(void)
141 {
142  uint16_t value;
143  uint32_t Ngnd;
144  uint32_t Nreg;
145  uint32_t 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 = (uint32_t)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 = (uint32_t)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 = (uint32_t)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  uint8_t trim1V2;
206  uint8_t 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).
250 void halCommonDelayMicroseconds(uint16_t us)
251 {
252  uint32_t 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.
284 void halCommonDelayMilliseconds(uint16_t ms)
285 {
286  if(ms==0) {
287  return;
288  }
289 
290  while(ms-->0) {
292  }
293 }
void halCommonCalibratePads(void)
Calibrates the GPIO pads.
Cortex-M3 Manufacturing token system.
void halCommonDelayMicroseconds(uint16_t us)
Blocks the current thread of execution for the specified amount of time, in microseconds.
uint16_t stMeasureVddFast(void)
Takes a fast ADC measurement of VDD_PADS in millivolts.
Utility and convenience functions for STM32W108 microcontroller, common to both the full and minimal ...
void halInternalSetRegTrim(boolean boostMode)
Sets the trim values for the 1.8V and 1.2V regulators based upon manufacturing configuration.
Minimal Hal functions common across all microcontroller-specific files.
void halCommonDelayMilliseconds(uint16_t ms)
Blocks the current thread of execution for the specified amount of time, in milliseconds.
#define FALSE
An alias for zero, used for clarity.
#define ATOMIC(blah)
A block of code may be made atomic by wrapping it with this macro.
Definition: gnu.h:459