PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pic24_adc.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 
31 
32 // Documentation for this file. If the \file tag isn't present,
33 // this file won't be documented.
34 /** \file
35 * Implementation of analog-to-digital converter functions prototyped in pic24_adc.h
36  */
37 
38 #include "pic24_adc.h"
39 #include <stdio.h> //for NULL definition
40 
41 /*********************************
42  * Function private to this file *
43  *********************************/
44 
45 
46 /*********************************************************
47  * Public functions intended to be called by other files *
48  *********************************************************/
49 
50 /** Performs an ADC conversion (assumes ADC is initialized properly
51  * to return integer results.
52  * \return Integer value (10- or 12-bit, depending on ADC configuration)
53  * corresponding to the ADC conversion result.
54  */
56  uint8_t u8_wdtState;
57 
58  sz_lastTimeoutError = "convertADC1()";
59  u8_wdtState = _SWDTEN; //save WDT state
60  _SWDTEN = 1; //enable WDT since we block
61  SET_SAMP_BIT_ADC1(); //start sampling
62  NOP(); //takes one clock to clear previous DONE flag, delay before checking.
63  WAIT_UNTIL_CONVERSION_COMPLETE_ADC1(); //wait for conversion to finish
64  _SWDTEN = u8_wdtState; //restore WDT
65  sz_lastTimeoutError = NULL; //reset error message
66  return(ADC1BUF0);
67 }
68 
69 /** Configures ADC1 to perform 10-/12-bit conversion on a single channel via
70  * CH0. The sampling is done against the AVDD and AVSS references and
71  * using the internal ADC clock to conserve timer resourses. User can
72  * initiate this manual sampling+conversion by setting the SAMP bit nin
73  * AD1CON1. When the DONE bit in AD1CON1 goes high, the conversion is
74  * done.
75  * \param u16_ch0PositiveMask Mask to select the single analog input to
76  * convert. See AD1CHS0 register and associated <i>defines</i>s in
77  * pic24_adc.h
78  * \param u8_autoSampleTime Number of <i>T</i><sub>AD</sub> periods for
79  * sampling the signal. This value must be 0-31. If greater than
80  * 31, then 31<i>T</i><sub>AD</sub> will be used.
81  * \param u8_use12bit If TRUE, set up the ADC into 12 bit mode, else
82  * use the 10 bit mode.
83  */
84 void configADC1_ManualCH0(uint16_t u16_ch0PositiveMask, \
85  uint8_t u8_autoSampleTime, \
86  uint8_t u8_use12bit) {
87 
88  if (u8_autoSampleTime > 31) u8_autoSampleTime=31;
89  AD1CON1bits.ADON = 0; // turn off ADC (changing setting while ADON is not allowed)
90 
91  /** Configure the internal ADC **/
92  AD1CON1 = ADC_CLK_AUTO | ADC_AUTO_SAMPLING_OFF;
93 #ifdef _AD12B
94  if (u8_use12bit)
95  AD1CON1bits.AD12B = 1;
96  else
97  AD1CON1bits.AD12B = 0;
98 #endif
99  AD1CON3 = ADC_CONV_CLK_INTERNAL_RC | (u8_autoSampleTime<<8);
100  AD1CON2 = ADC_VREF_AVDD_AVSS;
101 #if (defined(__PIC24H__)|| defined(__dsPIC33F__) || defined(__PIC24E__)|| defined(__dsPIC33E__))
102  AD1CHS0 = ADC_CH0_NEG_SAMPLEA_VREFN | u16_ch0PositiveMask;
103 #else
104  AD1CHS = ADC_CH0_NEG_SAMPLEA_VREFN | u16_ch0PositiveMask;
105 #endif
106  AD1CON1bits.ADON = 1; //turn on the ADC
107 }
108 
109 /** Configures ADC1 to perform conversions over a number of scanned
110  * channels to CH0. The sampling is done against the AVDD and AVSS references
111  * and using the internal ADC clock to conserve timer resourses.
112  * Samples are obtained continuously once sampling begins. Triggers ADC
113  * completion interrupts every u8_NumChannels conversion cycles. Results
114  * are written to the first u8_NumChannels locations in the 16 word ADCxBUFn
115  * registers.
116  *
117  * Sampling+conversion will start automatically when ADC is turned on.
118  *
119  * User must provide ISR to copy the 1-16 ADC results from ADC1BUFn before
120  * the next conversion completes. See Chapter 11 in the book for an example
121  * (adc7scan1 project).
122  *
123  * \param u16_ch0ScanMask A bit-mask to select the analog inputs to scan over
124  * and convert. See AD1CSSL register and associated <i>defines</i>s in
125  * pic24_adc.h
126  * \param u8_autoSampleTime Number of <i>T</i><sub>AD</sub> periods for
127  * sampling the signal. This value must be 0-31. If greater than
128  * 31, then 31<i>T</i><sub>AD</sub> will be used.
129  * \param u8_use12bit If TRUE, set up the ADC into 12 bit mode, else
130  * use the 10 bit mode.
131  */
132 void configADC1_AutoScanIrqCH0(uint16_t u16_ch0ScanMask, \
133  uint8_t u8_autoSampleTime, \
134  uint8_t u8_use12bit) {
135  uint8_t u8_i, u8_nChannels=0;
136  uint16_t u16_mask = 0x0001;
137 
138  // compute the number of Channels the user wants to scan over
139  for (u8_i=0; u8_i<16; u8_i++) {
140  if (u16_ch0ScanMask & u16_mask)
141  u8_nChannels++;
142  u16_mask<<=1;
143  } //end for
144 
145  if (u8_autoSampleTime > 31) u8_autoSampleTime=31;
146 
147  AD1CON1bits.ADON = 0; // turn off ADC (changing setting while ADON is not allowed)
148  /** Configure the internal ADC **/
149  AD1CON1 = ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON;
150 #ifdef _AD12B
151  if (u8_use12bit)
152  AD1CON1bits.AD12B = 1;
153  else
154  AD1CON1bits.AD12B = 0;
155 #endif
156  AD1CON3 = ADC_CONV_CLK_INTERNAL_RC | (u8_autoSampleTime<<8);
157  AD1CON2 = ADC_VREF_AVDD_AVSS | ADC_CONVERT_CH0 | ADC_SCAN_ON | ((u8_nChannels-1)<<2);
158 #if (defined(__PIC24H__)|| defined(__dsPIC33F__) || defined(__PIC24E__)|| defined(__dsPIC33E__))
159  AD1CHS0 = ADC_CH0_NEG_SAMPLEA_VREFN;
160 #else
161  AD1CHS = ADC_CH0_NEG_SAMPLEA_VREFN;
162 #endif
163  AD1CSSL = u16_ch0ScanMask;
164 
165  _AD1IP = 7; // set AD1 interrupt priority
166  _AD1IF = 0; // clear AD1 interrupt flag
167  _AD1IE = 1; // ENABLE AD1 interrupt
168 
169  AD1CON1bits.ADON = 1; // turn on the ADC
170 }
171 
172 
173 /** Configures ADC1 to perform conversions over a number of scanned
174  * channels to CH0. The sampling is done against the AVDD and AVSS references
175  * and using the internal ADC clock to conserve timer resourses.
176  * Samples are obtained continuously once sampling begins. Triggers ADC
177  * completion interrupts every <i>N</i> conversion cycles, where <i>N</i> is
178  * the number of bits set in the scan channel mask argument u16_ch0ScanMask.
179  * Results are written to the first u8_NumChannels locations in the 8 word
180  * <b>alternating halves</b> of the 16 word ADCxBUFn registers.
181  *
182  * User ISR must check the AD1CON2.BUFS bit when responding to copy the 8
183  * words from the correct half of the ADC1BUFn register array. See Chapter
184  * 11 in the book for an example. (adc7scan2 project)
185  *
186  * Sampling+conversion will start automatically when ADC is turned on.
187  *
188  * \param u16_ch0ScanMask A bit-mask to select the analog inputs to scan over
189  * and convert. See AD1CSSL register and associated <i>defines</i>s in
190  * pic24_adc.h
191  * \param u8_autoSampleTime Number of <i>T</i><sub>AD</sub> periods for
192  * sampling the signal. This value must be 0-31. If greater than
193  * 31, then 31<i>T</i><sub>AD</sub> will be used.
194  * \param u8_use12bit If TRUE, set up the ADC into 12 bit mode, else
195  * use the 10 bit mode.
196  */
198  uint8_t u8_autoSampleTime, \
199  uint8_t u8_use12bit) {
200  uint8_t u8_i, u8_nChannels=0;
201  uint16_t u16_mask = 0x0001;
202 
203  // compute the number of Channels the user wants to scan over
204  for (u8_i=0; u8_i<16; u8_i++) {
205  if (u16_ch0ScanMask & u16_mask)
206  u8_nChannels++;
207  u16_mask<<=1;
208  } //end for
209 
210  if (u8_autoSampleTime > 31) u8_autoSampleTime=31;
211 
212  AD1CON1bits.ADON = 0; // turn off ADC (changing setting while ADON is not allowed)
213  /** Configure the internal ADC **/
214  AD1CON1 = ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON;
215 #ifdef _AD12B
216  if (u8_use12bit)
217  AD1CON1bits.AD12B = 1;
218  else
219  AD1CON1bits.AD12B = 0;
220 #endif
221  AD1CON3 = ADC_CONV_CLK_INTERNAL_RC | (u8_autoSampleTime<<8);
222  AD1CON2 = ADC_VREF_AVDD_AVSS | ADC_CONVERT_CH0 | ADC_ALT_BUF_ON | ADC_SCAN_ON | ((u8_nChannels-1)<<2);
223 #if (defined(__PIC24H__)|| defined(__dsPIC33F__) || defined(__PIC24E__)|| defined(__dsPIC33E__))
224  AD1CHS0 = ADC_CH0_NEG_SAMPLEA_VREFN;
225 #else
226  AD1CHS = ADC_CH0_NEG_SAMPLEA_VREFN;
227 #endif
228  AD1CSSL = u16_ch0ScanMask;
229 
230  _AD1IP = 7; // set AD1 interrupt priority
231  _AD1IF = 0; // clear AD1 interrupt flag
232  _AD1IE = 1; // ENABLE AD1 interrupt
233 
234  AD1CON1bits.ADON = 1; // turn on the ADC
235 }
236 
237 
238 /** Configures ADC1 to perform simultaneous sampling and (sequential) 10bit
239  * conversion on four channels.
240  * Sampling is done against the AVDD and AVSS references. Sample duration
241  * is determined by the Timer2/3. Conversion clock is created from the
242  * internal system instruction clock. This means that this ADC configuration
243  * can NOT be used for sleeping ADC operations.
244  *
245  * ADC completion interrupts notify user when data is ready. Our four channel
246  * conversion values are written into the alternative halves of the ADC1BUF<i>n</i>
247  * registers. ADC ISR must
248  * "restart" the sample (by setting AD1CON1.SAMP bit) before exit.
249  * Sampling will end and conversion will begin on the next Timer2/3 trigger.
250  * Conversion values are written into
251  * the alternative halves of the ADC1BUF<i>n</i> registers.
252  *
253  * Sampling starts when AD1CON1.SAMP bit is written by main.
254  *
255  * User must ........ See Chapter 11 in the book for an example
256  * (adc4simul project).
257  *
258  * \param u8_ch0Select The number of the AN<i>x</i> channel to sample on
259  * CH0 sample-and-hold amplifier. This pin can be the same as a
260  * pin sampled on channels 1, 2, and 3. (See next argument.)
261  * \param u16_ch123SelectMask A bit-mask to select the analog inputs to for
262  * channels 1,2, and 3. See AD1CHS123 register and associated
263  * <i>defines</i>s in pic24_adc.h
264  * \param u16_numTcyMask A bit-mask to select the number of T<sub>CY</sub>
265  * periods used to create one T<sub>CY</sub> period. Note that
266  * T<sub>AD</sub> > 75ns. See AD1CON3 register and associated
267  * <i>defines</i>s in pic24_adc.h
268  */
269 void configADC1_Simul4ChanIrq(uint8_t u8_ch0Select, \
270  uint16_t u16_ch123SelectMask, \
271  uint16_t u16_numTcyMask ) {
272 
273  AD1CON1bits.ADON = 0; // turn off ADC (changing setting while ADON is not allowed)
274  /** Configure the internal ADC **/
275  AD1CON1 = ADC_CLK_TMR | ADC_SAMPLE_SIMULTANEOUS;
276  AD1CON3 = (u16_numTcyMask & 0x00FF);
277  AD1CON2 = ADC_VREF_AVDD_AVSS | ADC_CONVERT_CH0123 | ADC_ALT_BUF_ON;
278 #if (defined(__PIC24H__)|| defined(__dsPIC33F__) || defined(__PIC24E__)|| defined(__dsPIC33E__))
279  AD1CHS0 = ADC_CH0_NEG_SAMPLEA_VREFN | (u8_ch0Select & 0x1F);
280  AD1CHS123 = u16_ch123SelectMask;
281 #else
282  AD1CHS = ADC_CH0_NEG_SAMPLEA_VREFN | (u8_ch0Select & 0x1F);
283 #endif
284  AD1CSSL = 0;
285 
286  _AD1IP = 7; // set AD1 interrupt priority
287  _AD1IF = 0; // clear AD1 interrupt flag
288  _AD1IE = 1; // ENABLE AD1 interrupt
289 
290  AD1CON1bits.ADON = 1; // turn on the ADC
291 }
292 
293 
294 
295