PIC24 Support Libraries
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 "pic24_unittest.h"
40 #include <stdio.h> //for NULL definition
41 
42 /*********************************
43  * Function private to this file *
44  *********************************/
45 
46 
47 /*********************************************************
48  * Public functions intended to be called by other files *
49  *********************************************************/
50 
51 /** Performs an ADC conversion (assumes ADC is initialized properly
52  * to return integer results.
53  * \return Integer value (10- or 12-bit, depending on ADC configuration)
54  * corresponding to the ADC conversion result.
55  */
56 
57 #ifndef BUILT_ON_ESOS // Excluded from ESOS builds due to a busy loop
58 uint16_t convertADC1(void) {
59  uint8_t u8_wdtState;
60 
61  sz_lastTimeoutError = "convertADC1()";
62  u8_wdtState = _SWDTEN; //save WDT state
63  _SWDTEN = 1; //enable WDT since we block
64  SET_SAMP_BIT_ADC1(); //start sampling
65  NOP(); //takes one clock to clear previous DONE flag, delay before checking.
66  WAIT_UNTIL_CONVERSION_COMPLETE_ADC1(); //wait for conversion to finish
67  _SWDTEN = u8_wdtState; //restore WDT
68  sz_lastTimeoutError = NULL; //reset error message
69  return(ADC1BUF0);
70 }
71 #endif
72 
73 /** Configures ADC1 to perform 10-/12-bit conversion on a single channel via
74  * CH0. The sampling is done against the AVDD and AVSS references and
75  * using the internal ADC clock to conserve timer resourses. User can
76  * initiate this manual sampling+conversion by setting the SAMP bit nin
77  * AD1CON1. When the DONE bit in AD1CON1 goes high, the conversion is
78  * done.
79  * \param u16_ch0PositiveMask Mask to select the single analog input to
80  * convert. See AD1CHS0 register and associated <i>defines</i>s in
81  * pic24_adc.h
82  * \param u8_autoSampleTime Number of <i>T</i><sub>AD</sub> periods for
83  * sampling the signal. This value must be 0-31. If greater than
84  * 31, then 31<i>T</i><sub>AD</sub> will be used.
85  * \param u8_use12bit If TRUE, set up the ADC into 12 bit mode, else
86  * use the 10 bit mode.
87  */
88 void configADC1_ManualCH0(uint16_t u16_ch0PositiveMask,
89  uint8_t u8_autoSampleTime,
90  uint8_t u8_use12bit) {
91 
92  if (u8_autoSampleTime > 31) u8_autoSampleTime=31;
93  AD1CON1bits.ADON = 0; // turn off ADC (changing setting while ADON is not allowed)
94 
95  /** Configure the internal ADC **/
96  AD1CON1 = ADC_CLK_AUTO | ADC_AUTO_SAMPLING_OFF;
97 #ifdef _AD12B
98  if (u8_use12bit)
99  AD1CON1bits.AD12B = 1;
100  else
101  AD1CON1bits.AD12B = 0;
102 #else
103  // Some PICs only offer 10-bit mode.
104  ASSERT(u8_use12bit == 0);
105 #endif
106  AD1CON3 = ADC_CONV_CLK_INTERNAL_RC | (u8_autoSampleTime<<8);
107 
108 #if (HARDWARE_PLATFORM == EMBEDDED_C1)
109  AD1CON2 = ADC_VREF_AVDD_EXT; // Brings in VREF on the Embedded board.
110 #else
111  AD1CON2 = ADC_VREF_AVDD_AVSS;
112 #endif
113 
114 #if (defined(__PIC24H__)|| defined(__dsPIC33F__) || defined(__PIC24E__)|| defined(__dsPIC33E__))
115  AD1CHS0 = ADC_CH0_NEG_SAMPLEA_VREFN | u16_ch0PositiveMask;
116 #else
117  AD1CHS = ADC_CH0_NEG_SAMPLEA_VREFN | u16_ch0PositiveMask;
118 #endif
119  AD1CON1bits.ADON = 1; //turn on the ADC
120 }
121 
122 /** Configures ADC1 to perform conversions over a number of scanned
123  * channels to CH0. The sampling is done against the AVDD and AVSS references
124  * and using the internal ADC clock to conserve timer resourses.
125  * Samples are obtained continuously once sampling begins. Triggers ADC
126  * completion interrupts every u8_NumChannels conversion cycles. Results
127  * are written to the first u8_NumChannels locations in the 16 word ADCxBUFn
128  * registers.
129  *
130  * Sampling+conversion will start automatically when ADC is turned on.
131  *
132  * User must provide ISR to copy the 1-16 ADC results from ADC1BUFn before
133  * the next conversion completes. See Chapter 11 in the book for an example
134  * (adc7scan1 project).
135  *
136  * \param u16_ch0ScanMask A bit-mask to select the analog inputs to scan over
137  * and convert. See AD1CSSL register and associated <i>defines</i>s in
138  * pic24_adc.h
139  * \param u8_autoSampleTime Number of <i>T</i><sub>AD</sub> periods for
140  * sampling the signal. This value must be 0-31. If greater than
141  * 31, then 31<i>T</i><sub>AD</sub> will be used.
142  * \param u8_use12bit If TRUE, set up the ADC into 12 bit mode, else
143  * use the 10 bit mode.
144  */
145 void configADC1_AutoScanIrqCH0(uint16_t u16_ch0ScanMask,
146  uint8_t u8_autoSampleTime,
147  uint8_t u8_use12bit) {
148  uint8_t u8_i, u8_nChannels=0;
149  uint16_t u16_mask = 0x0001;
150 
151  // compute the number of Channels the user wants to scan over
152  for (u8_i=0; u8_i<16; u8_i++) {
153  if (u16_ch0ScanMask & u16_mask)
154  u8_nChannels++;
155  u16_mask<<=1;
156  } //end for
157 
158  if (u8_autoSampleTime > 31) u8_autoSampleTime=31;
159 
160  AD1CON1bits.ADON = 0; // turn off ADC (changing setting while ADON is not allowed)
161  /** Configure the internal ADC **/
162  AD1CON1 = ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON;
163 #ifdef _AD12B
164  if (u8_use12bit)
165  AD1CON1bits.AD12B = 1;
166  else
167  AD1CON1bits.AD12B = 0;
168 #else
169  // Some PICs only offer 10-bit mode.
170  ASSERT(u8_use12bit == 0);
171 #endif
172  AD1CON3 = ADC_CONV_CLK_INTERNAL_RC | (u8_autoSampleTime<<8);
173  AD1CON2 = ADC_VREF_AVDD_AVSS | ADC_CONVERT_CH0 | ADC_SCAN_ON | ((u8_nChannels-1)<<2);
174 #if (defined(__PIC24H__)|| defined(__dsPIC33F__) || defined(__PIC24E__)|| defined(__dsPIC33E__))
175  AD1CHS0 = ADC_CH0_NEG_SAMPLEA_VREFN;
176 #else
177  AD1CHS = ADC_CH0_NEG_SAMPLEA_VREFN;
178 #endif
179  AD1CSSL = u16_ch0ScanMask;
180 
181  _AD1IP = 7; // set AD1 interrupt priority
182  _AD1IF = 0; // clear AD1 interrupt flag
183  _AD1IE = 1; // ENABLE AD1 interrupt
184 
185  AD1CON1bits.ADON = 1; // turn on the ADC
186 }
187 
188 
189 /** Configures ADC1 to perform conversions over a number of scanned
190  * channels to CH0. The sampling is done against the AVDD and AVSS references
191  * and using the internal ADC clock to conserve timer resourses.
192  * Samples are obtained continuously once sampling begins. Triggers ADC
193  * completion interrupts every <i>N</i> conversion cycles, where <i>N</i> is
194  * the number of bits set in the scan channel mask argument u16_ch0ScanMask.
195  * Results are written to the first u8_NumChannels locations in the 8 word
196  * <b>alternating halves</b> of the 16 word ADCxBUFn registers.
197  *
198  * User ISR must check the AD1CON2.BUFS bit when responding to copy the 8
199  * words from the correct half of the ADC1BUFn register array. See Chapter
200  * 11 in the book for an example. (adc7scan2 project)
201  *
202  * Sampling+conversion will start automatically when ADC is turned on.
203  *
204  * \param u16_ch0ScanMask A bit-mask to select the analog inputs to scan over
205  * and convert. See AD1CSSL register and associated <i>defines</i>s in
206  * pic24_adc.h
207  * \param u8_autoSampleTime Number of <i>T</i><sub>AD</sub> periods for
208  * sampling the signal. This value must be 0-31. If greater than
209  * 31, then 31<i>T</i><sub>AD</sub> will be used.
210  * \param u8_use12bit If TRUE, set up the ADC into 12 bit mode, else
211  * use the 10 bit mode.
212  */
213 void configADC1_AutoHalfScanIrqCH0(uint16_t u16_ch0ScanMask,
214  uint8_t u8_autoSampleTime,
215  uint8_t u8_use12bit) {
216  uint8_t u8_i, u8_nChannels=0;
217  uint16_t u16_mask = 0x0001;
218 
219  // compute the number of Channels the user wants to scan over
220  for (u8_i=0; u8_i<16; u8_i++) {
221  if (u16_ch0ScanMask & u16_mask)
222  u8_nChannels++;
223  u16_mask<<=1;
224  } //end for
225 
226  if (u8_autoSampleTime > 31) u8_autoSampleTime=31;
227 
228  AD1CON1bits.ADON = 0; // turn off ADC (changing setting while ADON is not allowed)
229  /** Configure the internal ADC **/
230  AD1CON1 = ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON;
231 #ifdef _AD12B
232  if (u8_use12bit)
233  AD1CON1bits.AD12B = 1;
234  else
235  AD1CON1bits.AD12B = 0;
236 #else
237  // Some PICs only offer 10-bit mode.
238  ASSERT(u8_use12bit == 0);
239 #endif
240  AD1CON3 = ADC_CONV_CLK_INTERNAL_RC | (u8_autoSampleTime<<8);
241  AD1CON2 = ADC_VREF_AVDD_AVSS | ADC_CONVERT_CH0 | ADC_ALT_BUF_ON | ADC_SCAN_ON | ((u8_nChannels-1)<<2);
242 #if (defined(__PIC24H__)|| defined(__dsPIC33F__) || defined(__PIC24E__)|| defined(__dsPIC33E__))
243  AD1CHS0 = ADC_CH0_NEG_SAMPLEA_VREFN;
244 #else
245  AD1CHS = ADC_CH0_NEG_SAMPLEA_VREFN;
246 #endif
247  AD1CSSL = u16_ch0ScanMask;
248 
249  _AD1IP = 7; // set AD1 interrupt priority
250  _AD1IF = 0; // clear AD1 interrupt flag
251  _AD1IE = 1; // ENABLE AD1 interrupt
252 
253  AD1CON1bits.ADON = 1; // turn on the ADC
254 }
255 
256 
257 /** Configures ADC1 to perform simultaneous sampling and (sequential) 10bit
258  * conversion on four channels.
259  * Sampling is done against the AVDD and AVSS references. Sample duration
260  * is determined by the Timer2/3. Conversion clock is created from the
261  * internal system instruction clock. This means that this ADC configuration
262  * can NOT be used for sleeping ADC operations.
263  *
264  * ADC completion interrupts notify user when data is ready. Our four channel
265  * conversion values are written into the alternative halves of the ADC1BUF<i>n</i>
266  * registers. ADC ISR must
267  * "restart" the sample (by setting AD1CON1.SAMP bit) before exit.
268  * Sampling will end and conversion will begin on the next Timer2/3 trigger.
269  * Conversion values are written into
270  * the alternative halves of the ADC1BUF<i>n</i> registers.
271  *
272  * Sampling starts when AD1CON1.SAMP bit is written by main.
273  *
274  * User must ........ See Chapter 11 in the book for an example
275  * (adc4simul project).
276  *
277  * \param u8_ch0Select The number of the AN<i>x</i> channel to sample on
278  * CH0 sample-and-hold amplifier. This pin can be the same as a
279  * pin sampled on channels 1, 2, and 3. (See next argument.)
280  * \param u16_ch123SelectMask A bit-mask to select the analog inputs to for
281  * channels 1,2, and 3. See AD1CHS123 register and associated
282  * <i>defines</i>s in pic24_adc.h
283  * \param u16_numTcyMask A bit-mask to select the number of T<sub>CY</sub>
284  * periods used to create one T<sub>CY</sub> period. Note that
285  * T<sub>AD</sub> > 75ns. See AD1CON3 register and associated
286  * <i>defines</i>s in pic24_adc.h
287  */
289  uint16_t u16_ch123SelectMask,
290  uint16_t u16_numTcyMask ) {
291 
292  AD1CON1bits.ADON = 0; // turn off ADC (changing setting while ADON is not allowed)
293  /** Configure the internal ADC **/
294  AD1CON1 = ADC_CLK_TMR | ADC_SAMPLE_SIMULTANEOUS;
295  AD1CON3 = (u16_numTcyMask & 0x00FF);
296  AD1CON2 = ADC_VREF_AVDD_AVSS | ADC_CONVERT_CH0123 | ADC_ALT_BUF_ON;
297 #if (defined(__PIC24H__)|| defined(__dsPIC33F__) || defined(__PIC24E__)|| defined(__dsPIC33E__))
298  AD1CHS0 = ADC_CH0_NEG_SAMPLEA_VREFN | (u8_ch0Select & 0x1F);
299  AD1CHS123 = u16_ch123SelectMask;
300 #else
301  AD1CHS = ADC_CH0_NEG_SAMPLEA_VREFN | (u8_ch0Select & 0x1F);
302  // For PICs that lack this, make sure nothing was selected.
303  ASSERT(u16_ch123SelectMask == 0);
304 #endif
305  AD1CSSL = 0;
306 
307  _AD1IP = 7; // set AD1 interrupt priority
308  _AD1IF = 0; // clear AD1 interrupt flag
309  _AD1IE = 1; // ENABLE AD1 interrupt
310 
311  AD1CON1bits.ADON = 1; // turn on the ADC
312 }
void configADC1_AutoScanIrqCH0(uint16_t u16_ch0ScanMask, uint8_t u8_autoSampleTime, uint8_t u8_use12bit)
Definition: pic24_adc.c:145
void configADC1_ManualCH0(uint16_t u16_ch0PositiveMask, uint8_t u8_autoSampleTime, uint8_t u8_use12bit)
Definition: pic24_adc.c:88
uint16_t convertADC1(void)
Definition: pic24_adc.c:58
void configADC1_Simul4ChanIrq(uint8_t u8_ch0Select, uint16_t u16_ch123SelectMask, uint16_t u16_numTcyMask)
Definition: pic24_adc.c:288
static void WAIT_UNTIL_CONVERSION_COMPLETE_ADC1()
Definition: pic24_adc.h:34
_PERSISTENT const char * sz_lastTimeoutError
Definition: pic24_util.c:134
#define ASSERT(test)
void configADC1_AutoHalfScanIrqCH0(uint16_t u16_ch0ScanMask, uint8_t u8_autoSampleTime, uint8_t u8_use12bit)
Definition: pic24_adc.c:213
unsigned char uint8_t
An abbreviation for an 8-bit unsigned integer.
Definition: dataXferImpl.h:194
#define NOP()
Insert a one-cycle nop instruction.
Definition: pic24_chip.h:78