xref: /btstack/port/archive/msp-exp430f5438-cc2564b/firmware/hal_adc.c (revision 1664436fd643daf66517dc309e6cc72448e8a86d)
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