1 /**
2 * @file hal_adc.c
3 *
4 * Copyright 2008 Texas Instruments, Inc.
5 ***************************************************************************/
6
7 #include "hal_adc.h"
8
9 #include <msp430x54x.h>
10 #include "hal_compat.h"
11
12 static int SavedADC12MEM0 = 0, SavedADC12MEM1 = 0, SavedADC12MEM2 = 0;
13 static int Acc_x = 0, Acc_y = 0, Acc_z = 0;
14 static int Acc_x_offset = 0, Acc_y_offset = 0, Acc_z_offset = 0;
15 static long int Vcc = 0, Temperature = 0;
16 static long int temperatureOffset = CELSIUS_OFFSET;
17 static unsigned char conversionType = CELSIUS, adcMode = ADC_OFF_MODE;
18 static unsigned char exit_active_from_ADC12 = 0;
19
20 /************************************************************************
21 * @brief Turns on and initializes ADC12, accelerometer in order to
22 * sample x, y, z-axis inputs.
23 *
24 * @param none
25 *
26 * @return none
27 *************************************************************************/
halAccelerometerInit(void)28 void halAccelerometerInit(void)
29 {
30 adcMode = ADC_ACC_MODE;
31 ACC_PORT_SEL |= ACC_X_PIN + ACC_Y_PIN; //Enable A/D channel inputs
32 ACC_PORT_DIR &= ~(ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN);
33 ACC_PORT_DIR |= ACC_PWR_PIN; //Enable ACC_POWER
34 ACC_PORT_OUT |= ACC_PWR_PIN;
35
36 //Sequence of channels, once, ACLK
37 ADC12CTL0 = ADC12ON + ADC12SHT02 + ADC12MSC;
38 ADC12CTL1 = ADC12SHP + ADC12CONSEQ_1 + ADC12SSEL_0;
39 ADC12CTL2 = ADC12RES_2;
40 ADC12MCTL0 = ACC_X_CHANNEL;
41 ADC12MCTL1 = ACC_Y_CHANNEL;
42 ADC12MCTL2 = ACC_Z_CHANNEL + ADC12EOS;
43
44 // Allow the accelerometer to settle before sampling any data
45
46 // 4.5.3-20110706-2 doesn't allow for 32-bit delay cycles
47 int i;
48 for (i=0;i<10;i++){
49 __delay_cycles(20000);
50 }
51 UCSCTL8 |= MODOSCREQEN;
52 }
53
54 /************************************************************************
55 * @brief Calibrates the offset values for x, y, and z axes.
56 *
57 * @param none
58 *
59 * @return none
60 *************************************************************************/
halAccelerometerCalibrate(void)61 void halAccelerometerCalibrate(void)
62 {
63 unsigned char tempQuit;
64
65 tempQuit = exit_active_from_ADC12;
66 halAdcSetQuitFromISR( 1 );
67 halAdcStartRead();
68
69 __bis_SR_register(LPM3_bits + GIE);
70 __no_operation();
71
72 halAccelerometerReadWithOffset(&Acc_x_offset, &Acc_y_offset, &Acc_z_offset);
73 halAdcSetQuitFromISR( tempQuit );
74 }
75
76 /************************************************************************
77 * @brief Set function for the calibrated offsets for the x, y, and z axes.
78 *
79 * @param x Calibrated offset for the x-axis
80 *
81 * @param y Calibrated offset for the y-axis
82 *
83 * @param z Calibrated offset for the z-axis
84 *
85 * @return none
86 *************************************************************************/
halAccelerometerSetCalibratedOffset(int x,int y,int z)87 void halAccelerometerSetCalibratedOffset( int x, int y, int z )
88 {
89 Acc_x_offset = x;
90 Acc_y_offset = y;
91 Acc_z_offset = z;
92 }
93
94 /************************************************************************
95 * @brief Get function for the x, y, and z axes calibrated offsets
96 *
97 * @param x Pointer to the calibrated offset for the x-axis
98 *
99 * @param y Pointer to the calibrated offset for the y-axis
100 *
101 * @param z Pointer to the calibrated offset for the z-axis
102 *
103 * @return none
104 *************************************************************************/
halAccelerometerGetCalibratedOffset(int * x,int * y,int * z)105 void halAccelerometerGetCalibratedOffset(int *x, int *y, int *z)
106 {
107 *x = Acc_x_offset;
108 *y = Acc_y_offset;
109 *z = Acc_y_offset;
110 }
111
112 /************************************************************************
113 * @brief Get function for the x, y, and z accelerometer samples,
114 * including the calibrated offsets.
115 *
116 * @param x Pointer to the accelerometer reading (x-axis)
117 *
118 * @param y Pointer to the accelerometer reading (y-axis)
119 *
120 * @param z Pointer to the accelerometer reading (z-axis)
121 *
122 * @return none
123 *************************************************************************/
halAccelerometerRead(int * x,int * y,int * z)124 void halAccelerometerRead(int *x, int *y, int *z)
125 {
126 Acc_x = SavedADC12MEM0;
127 Acc_y = SavedADC12MEM1;
128 Acc_z = SavedADC12MEM2;
129
130 *x = Acc_x - Acc_x_offset;
131 *y = Acc_y - Acc_y_offset;
132 *z = Acc_z - Acc_z_offset;
133 }
134
135 /************************************************************************
136 * @brief Get function for the x, y, and z accelerometer samples,
137 * excluding the calibrated offsets.
138 *
139 * @param x Pointer to the accelerometer reading (x-axis)
140 *
141 * @param y Pointer to the accelerometer reading (y-axis)
142 *
143 * @param z Pointer to the accelerometer reading (z-axis)
144 *
145 * @return none
146 *************************************************************************/
halAccelerometerReadWithOffset(int * x,int * y,int * z)147 void halAccelerometerReadWithOffset(int *x, int *y, int *z)
148 {
149 *x = SavedADC12MEM0;
150 *y = SavedADC12MEM1;
151 *z = SavedADC12MEM2;
152 }
153
154 /************************************************************************
155 * @brief Disables the ADC12, accelerometer that sampled x, y, z-axis inputs.
156 *
157 * @param none
158 *
159 * @return none
160 *************************************************************************/
halAccelerometerShutDown(void)161 void halAccelerometerShutDown(void)
162 {
163 //Turn off ADC Module
164 ADC12CTL0 &= ~( ADC12ON + ADC12ENC );
165 ACC_PORT_OUT &= ~ACC_PWR_PIN; //Disable ACC_POWER
166
167 //Disable A/D channel inputs
168 ACC_PORT_SEL &= ~(ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN);
169 ACC_PORT_DIR |= (ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN + ACC_PWR_PIN);
170 ACC_PORT_OUT &= ~(ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN + ACC_PWR_PIN);
171
172 adcMode = ADC_OFF_MODE;
173 }
174
175 /*----------------------------------------------------------------------------*/
176 /************************************************************************
177 * @brief Intializes the ADC12 to sample Temperature and Vcc.
178 *
179 * @param none
180 *
181 * @return none
182 *************************************************************************/
halAdcInitTempVcc(void)183 void halAdcInitTempVcc(void)
184 {
185 //Sequence of channels, once,
186 adcMode = ADC_TEMP_MODE;
187 UCSCTL8 |= MODOSCREQEN;
188 ADC12CTL0 = ADC12ON + ADC12SHT0_15 + ADC12MSC + + ADC12REFON + ADC12REF2_5V;
189 ADC12CTL1 = ADC12SHP + ADC12CONSEQ_1 + ADC12SSEL_0;
190 ADC12CTL2 = ADC12RES_2;
191
192 ADC12MCTL0 = ADC12SREF_1 + TEMP_CHANNEL;
193 ADC12MCTL1 = ADC12SREF_1 + VCC_CHANNEL + ADC12EOS;
194 }
195
196 /************************************************************************
197 * @brief Turns off / disable the ADC12.
198 *
199 * @param none
200 *
201 * @return none
202 *************************************************************************/
halAdcShutDownTempVcc(void)203 void halAdcShutDownTempVcc(void)
204 {
205 ADC12CTL0 &= ~ ( ADC12ON + ADC12ENC + ADC12REFON );
206 adcMode = ADC_OFF_MODE;
207 }
208
209 /************************************************************************
210 * @brief Sets the conversion type to either Farenheit (F) or Celsius (C).
211 *
212 * @param conversion The #define constant CELSIUS or FAHRENHEIT.
213 *
214 * @return none
215 *************************************************************************/
halAdcSetTempConversionType(unsigned char conversion)216 void halAdcSetTempConversionType(unsigned char conversion)
217 {
218 conversionType = conversion;
219 }
220
221 /************************************************************************
222 * @brief Set function for the calibrated temperature offset.
223 *
224 * @param offset The temperature offset.
225 *
226 * @return none
227 *************************************************************************/
halAdcSetTempOffset(long offset)228 void halAdcSetTempOffset(long offset)
229 {
230 temperatureOffset = offset;
231 }
232
233 /************************************************************************
234 * @brief Get function for the current temperature value.
235 *
236 * @param none
237 *
238 * @return The current temperature value.
239 *************************************************************************/
halAdcGetTemp(void)240 int halAdcGetTemp(void)
241 {
242 return Temperature;
243 }
244
245 /************************************************************************
246 * @brief Get function for the current Vcc value.
247 *
248 * @param none
249 *
250 * @return The current Vcc value.
251 *************************************************************************/
halAdcGetVcc(void)252 int halAdcGetVcc(void)
253 {
254 return Vcc;
255 }
256
257 /************************************************************************
258 * @brief Converts the Vcc and Temp readings from the ADC to BCD format.
259 *
260 * @param none
261 *
262 * @return none
263 *************************************************************************/
halAdcConvertTempVccFromADC(void)264 void halAdcConvertTempVccFromADC(void)
265 {
266 long multiplier, offset;
267
268 // Convert Vcc
269 Vcc = SavedADC12MEM1;
270 Vcc = Vcc * 50;
271 Vcc = Vcc / 4096;
272
273 // Convert Temperature
274 if (conversionType == CELSIUS)
275 {
276 multiplier = CELSIUS_MUL;
277 offset = temperatureOffset;
278 }
279 else
280 {
281 multiplier = (long) CELSIUS_MUL * 9 /5 ;
282 offset = (long) temperatureOffset * 9 / 5 - 320;
283 }
284 Temperature = (long) SavedADC12MEM0 * multiplier/4096 - offset;
285 }
286
287 /************************************************************************
288 * @brief Get function for the temperature and Vcc samples in "xxx^C/F" and
289 * "x.xV" format.
290 *
291 * @param TemperatureStr The string that holds the temperature reading
292 *
293 * @param Vcc The string that holds the Vcc reading
294 *
295 * @return none
296 *************************************************************************/
halAdcReadTempVcc(char * TemperatureStr,char * VccStr)297 void halAdcReadTempVcc(char *TemperatureStr, char *VccStr)
298 {
299 unsigned char i, leadingZero = 0;
300 long int dummyTemperature, dummyVcc;
301
302 halAdcConvertTempVccFromADC();
303 dummyTemperature = Temperature;
304 dummyVcc = Vcc;
305 for (i = 0; i < 6; i++)
306 TemperatureStr[i] = '\0';
307 i=0;
308 //Check for negative
309 if (Temperature < 0)
310 {
311 TemperatureStr[i++]='-';
312 Temperature = -Temperature;
313 }
314 TemperatureStr[i] ='0';
315 if (Temperature >= 1000)
316 {
317 TemperatureStr[i]='1';
318 Temperature -=1000;
319 leadingZero = 1;
320 }
321 if (leadingZero == 1)
322 i++;
323 //100s digit
324 TemperatureStr[i] = '0';
325 if (Temperature >= 100)
326 {
327 do
328 {
329 TemperatureStr[i]++;
330 Temperature -=100;
331 }
332 while (Temperature >=100);
333 leadingZero = 1;
334 }
335 if (leadingZero == 1)
336 i++;
337 //10s digit
338 TemperatureStr[i] = '0';
339 if (Temperature >=10)
340 {
341 do
342 {
343 TemperatureStr[i]++;
344 Temperature -=10;
345 }
346 while (Temperature >=10);
347 }
348
349 TemperatureStr[++i] = '^';
350 if (conversionType == CELSIUS)
351 TemperatureStr[++i]='C';
352 else
353 TemperatureStr[++i]='F';
354
355 VccStr[0] = '0';
356 VccStr[2] = '0';
357 while (Vcc >= 10)
358 {
359 VccStr[0]++;
360 Vcc -= 10;
361 }
362 VccStr[2] += Vcc;
363 Temperature = dummyTemperature;
364 Vcc = dummyVcc;
365 }
366
367 /*----------------------------------------------------------------------------*/
368 /************************************************************************
369 * @brief Starts the ADC conversion.
370 *
371 * @param none
372 *
373 * @return none
374 *************************************************************************/
halAdcStartRead(void)375 void halAdcStartRead(void)
376 {
377 ADC12IFG &= ~(BIT1+BIT0); // Clear any pending flags
378
379 if (adcMode == ADC_ACC_MODE)
380 {
381 ADC12CTL0 |= ADC12ENC | ADC12SC ;
382 ADC12IE |= BIT2;
383 }
384 else
385 {
386 ADC12CTL0 |= ADC12REFON; // Turn on ADC12 reference
387
388 // Delay to stabilize ADC12 reference assuming the fastest MCLK of 18 MHz.
389 // 35 us = 1 / 18 MHz * 630
390 __delay_cycles(630);
391
392 ADC12IE |= BIT1; // Enable interrupt
393 ADC12CTL0 |= ADC12ENC | ADC12SC;
394 }
395 }
396
397 /************************************************************************
398 * @brief Sets the flag that causes an exit into active CPU mode from
399 * the ADC12 ISR.
400 *
401 * @param quit
402 *
403 * - 1 - Exit active from ADC12 ISR
404 * - 0 - Remain in LPMx on exit from ADC12ISR
405 *
406 * @return none
407 *************************************************************************/
halAdcSetQuitFromISR(unsigned char quit)408 void halAdcSetQuitFromISR(unsigned char quit)
409 {
410 exit_active_from_ADC12 = quit;
411 }
412
413 /*----------------------------------------------------------------------------*/
414
415 #ifdef __GNUC__
416 __attribute__((interrupt(ADC12_VECTOR)))
417 #endif
418 #ifdef __IAR_SYSTEMS_ICC__
419 #pragma vector=ADC12_VECTOR
420 __interrupt
421 #endif
ADC12_ISR(void)422 void ADC12_ISR(void)
423 {
424 SavedADC12MEM0 = ADC12MEM0; // Store the sampled data
425 SavedADC12MEM1 = ADC12MEM1;
426 SavedADC12MEM2 = ADC12MEM2;
427 ADC12IFG = 0; // Clear the interrupt flags
428 ADC12CTL0 &= ~( ADC12ENC | ADC12SC | ADC12REFON);
429 if (exit_active_from_ADC12) __bic_SR_register_on_exit(LPM3_bits);
430 }
431