1 /**************************************************************************/
4 @author K. Townsend (microBuilder.eu)
10 SW-based single-channel A/D conversion. If you wish to convert
11 multiple ADC channels simultaneously, this code will need to be
12 modified to work in BURST mode.
17 #include "core/cpu/cpu.h"
18 #include "core/adc/adc.h"
28 // Get A/D conversion results from A/D channel 0
36 Software License Agreement (BSD License)
38 Copyright (c) 2010, microBuilder SARL
41 Redistribution and use in source and binary forms, with or without
42 modification, are permitted provided that the following conditions are met:
43 1. Redistributions of source code must retain the above copyright
44 notice, this list of conditions and the following disclaimer.
45 2. Redistributions in binary form must reproduce the above copyright
46 notice, this list of conditions and the following disclaimer in the
47 documentation and/or other materials provided with the distribution.
48 3. Neither the name of the copyright holders nor the
49 names of its contributors may be used to endorse or promote products
50 derived from this software without specific prior written permission.
52 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
53 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
54 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
55 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
56 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
58 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
59 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
61 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 /**************************************************************************/
68 static bool _adcInitialised
= false;
69 static uint8_t _adcLastChannel
= 0;
71 /**************************************************************************/
73 @brief Returns the conversion results on the specified ADC channel.
75 This function will manually start an A/D conversion on a single
76 channel and return the results.
79 The A/D channel [0..7] that will be used during the A/D
80 conversion. (Note that only A/D channel's 0..3 are
81 configured by default in adcInit.)
83 @return 0 if an overrun error occured, otherwise a 10-bit value
84 containing the A/D conversion results.
85 @warning Only AD channels 0..3 are configured for A/D in adcInit.
86 If you wish to use A/D pins 4..7 they will also need to
87 be added to the adcInit function.
89 /**************************************************************************/
90 uint32_t adcReadSingle (uint8_t channelNum
)
92 if (!_adcInitialised
) adcInit();
94 uint32_t regVal
, adcData
;
96 /* make sure that channel number is 0..7 */
97 if ( channelNum
>= 8 )
99 // ToDo: Change this to throw an exception back
103 /* Deselect all channels */
104 ADC_AD0CR
&= ~ADC_AD0CR_SEL_MASK
;
106 /* Start converting now on the appropriate channel */
107 ADC_AD0CR
|= ADC_AD0CR_START_STARTNOW
| (1 << channelNum
);
109 /* wait until end of A/D convert */
112 // Get data register results for the requested channel
116 regVal
= (*(pREG32(ADC_AD0DR0
)));
119 regVal
= (*(pREG32(ADC_AD0DR1
)));
122 regVal
= (*(pREG32(ADC_AD0DR2
)));
125 regVal
= (*(pREG32(ADC_AD0DR3
)));
128 regVal
= (*(pREG32(ADC_AD0DR4
)));
131 regVal
= (*(pREG32(ADC_AD0DR5
)));
134 regVal
= (*(pREG32(ADC_AD0DR6
)));
137 regVal
= (*(pREG32(ADC_AD0DR7
)));
140 regVal
= (*(pREG32(ADC_AD0DR0
)));
144 /* read result of A/D conversion */
145 if (regVal
& ADC_DR_DONE
)
152 ADC_AD0CR
&= ~ADC_AD0CR_START_MASK
;
154 /* return 0 if an overrun occurred */
155 if ( regVal
& ADC_DR_OVERRUN
)
160 /* return conversion results */
161 adcData
= (regVal
>> 6) & 0x3FF;
165 /**************************************************************************/
167 @brief Returns the conversion results on the specified ADC channel.
169 This function will manually start an A/D conversion on a single
170 channel and return the results. If ADC Averaging is enabled
171 (via ADC_AVERAGING_ENABLE) the specified number of values will be
172 samples from the ADC and the average value will be returned.
174 @param[in] channelNum
175 The A/D channel [0..7] that will be used during the A/D
176 conversion. (Note that only A/D channel's 0..3 are
177 configured by default in adcInit.)
179 @return 0 if an overrun error occured, otherwise a 10-bit value
180 containing the A/D conversion results.
182 @warning Only AD channels 0..3 are configured for A/D in adcInit.
183 If you wish to use A/D pins 4..7 they will also need to
184 be added to the adcInit function.
186 /**************************************************************************/
187 uint32_t adcRead (uint8_t channelNum
)
189 if (!_adcInitialised
) adcInit();
191 #if ADC_AVERAGING_ENABLE
192 uint32_t adcTotal
, i
;
194 for (i
=0; i
<ADC_AVERAGING_SAMPLES
;i
++)
196 adcTotal
+= adcReadSingle(channelNum
);
198 return adcTotal
/ADC_AVERAGING_SAMPLES
;
200 return adcReadSingle(channelNum
);
204 /**************************************************************************/
206 @brief Initialises the A/D converter and configures channels 0..3
207 for 10-bit, SW-controlled A/D conversion.
211 /**************************************************************************/
214 /* Disable Power down bit to the ADC block. */
215 SCB_PDRUNCFG
&= ~(SCB_PDRUNCFG_ADC
);
217 /* Enable AHB clock to the ADC. */
218 SCB_SYSAHBCLKCTRL
|= (SCB_SYSAHBCLKCTRL_ADC
);
220 /* Digital pins need to have the 'analog' bit set in addition
221 to changing their pin function */
223 /* Set AD0 to analog input */
224 IOCON_JTAG_TDI_PIO0_11
&= ~(IOCON_JTAG_TDI_PIO0_11_ADMODE_MASK
|
225 IOCON_JTAG_TDI_PIO0_11_FUNC_MASK
|
226 IOCON_JTAG_TDI_PIO0_11_MODE_MASK
);
227 IOCON_JTAG_TDI_PIO0_11
|= (IOCON_JTAG_TDI_PIO0_11_FUNC_AD0
&
228 IOCON_JTAG_TDI_PIO0_11_ADMODE_ANALOG
);
230 /* Set AD1 to analog input */
231 IOCON_JTAG_TMS_PIO1_0
&= ~(IOCON_JTAG_TMS_PIO1_0_ADMODE_MASK
|
232 IOCON_JTAG_TMS_PIO1_0_FUNC_MASK
|
233 IOCON_JTAG_TMS_PIO1_0_MODE_MASK
);
234 IOCON_JTAG_TMS_PIO1_0
|= (IOCON_JTAG_TMS_PIO1_0_FUNC_AD1
&
235 IOCON_JTAG_TMS_PIO1_0_ADMODE_ANALOG
);
237 /* Set AD2 to analog input */
238 IOCON_JTAG_TDO_PIO1_1
&= ~(IOCON_JTAG_TDO_PIO1_1_ADMODE_MASK
|
239 IOCON_JTAG_TDO_PIO1_1_FUNC_MASK
|
240 IOCON_JTAG_TDO_PIO1_1_MODE_MASK
);
241 IOCON_JTAG_TDO_PIO1_1
|= (IOCON_JTAG_TDO_PIO1_1_FUNC_AD2
&
242 IOCON_JTAG_TDO_PIO1_1_ADMODE_ANALOG
);
244 /* Set AD3 to analog input */
245 IOCON_JTAG_nTRST_PIO1_2
&= ~(IOCON_JTAG_nTRST_PIO1_2_ADMODE_MASK
|
246 IOCON_JTAG_nTRST_PIO1_2_FUNC_MASK
|
247 IOCON_JTAG_nTRST_PIO1_2_MODE_MASK
);
248 IOCON_JTAG_nTRST_PIO1_2
|= (IOCON_JTAG_nTRST_PIO1_2_FUNC_AD3
&
249 IOCON_JTAG_nTRST_PIO1_2_ADMODE_ANALOG
);
251 /* Note that in SW mode only one channel can be selected at a time (AD0 in this case)
252 To select multiple channels, ADC_AD0CR_BURST_HWSCANMODE must be used */
253 ADC_AD0CR
= (ADC_AD0CR_SEL_AD0
| /* SEL=1,select channel 0 on ADC0 */
254 (((CFG_CPU_CCLK
/ SCB_SYSAHBCLKDIV
) / 1000000 - 1 ) << 8) | /* CLKDIV = Fpclk / 1000000 - 1 */
255 ADC_AD0CR_BURST_SWMODE
| /* BURST = 0, no BURST, software controlled */
256 ADC_AD0CR_CLKS_10BITS
| /* CLKS = 0, 11 clocks/10 bits */
257 ADC_AD0CR_START_NOSTART
| /* START = 0 A/D conversion stops */
258 ADC_AD0CR_EDGE_RISING
); /* EDGE = 0 (CAP/MAT signal falling, trigger A/D conversion) */
260 /* Set initialisation flag */
261 _adcInitialised
= true;
263 /* Set last channel flag to 0 (initialised above) */