1 /* Teensyduino Core Library
2 * http://www.pjrc.com/teensy/
3 * Copyright (c) 2013 PJRC.COM, LLC.
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * 1. The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * 2. If the Software is incorporated into a build system that allows
17 * selection among a list of target devices, then similar target
18 * devices manufactured by PJRC.COM must be included in the list of
19 * target devices and selectable in the same manner.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
25 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
26 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 #include <Lib/ScanLib.h>
33 static uint8_t calibrating;
34 static uint8_t analog_right_shift = 0;
35 static uint8_t analog_config_bits = 10;
36 static uint8_t analog_num_average = 4;
37 static uint8_t analog_reference_internal = 0;
39 // the alternate clock is connected to OSCERCLK (16 MHz).
40 // datasheet says ADC clock should be 2 to 12 MHz for 16 bit mode
41 // datasheet says ADC clock should be 1 to 18 MHz for 8-12 bit mode
44 #define ADC_CFG1_6MHZ ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1)
45 #define ADC_CFG1_12MHZ ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1)
46 #define ADC_CFG1_24MHZ ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1)
47 #elif F_BUS == 24000000
48 #define ADC_CFG1_6MHZ ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(0)
49 #define ADC_CFG1_12MHZ ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(0)
50 #define ADC_CFG1_24MHZ ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0)
55 void analog_init(void)
60 VREF_SC = 0xE1; // enable 1.2 volt ref
62 if (analog_config_bits == 8) {
63 ADC0_CFG1 = ADC_CFG1_24MHZ + ADC_CFG1_MODE(0);
64 ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
65 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
66 ADC1_CFG1 = ADC_CFG1_24MHZ + ADC_CFG1_MODE(0);
67 ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
69 } else if (analog_config_bits == 10) {
70 ADC0_CFG1 = ADC_CFG1_12MHZ + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP;
71 ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
72 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
73 ADC1_CFG1 = ADC_CFG1_12MHZ + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP;
74 ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
76 } else if (analog_config_bits == 12) {
77 ADC0_CFG1 = ADC_CFG1_12MHZ + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP;
78 ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
79 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
80 ADC1_CFG1 = ADC_CFG1_12MHZ + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP;
81 ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
84 ADC0_CFG1 = ADC_CFG1_12MHZ + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP;
85 ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
86 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
87 ADC1_CFG1 = ADC_CFG1_12MHZ + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP;
88 ADC1_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
92 if (analog_reference_internal) {
93 ADC0_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref
94 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
95 ADC1_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref
98 ADC0_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref
99 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
100 ADC1_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref
104 num = analog_num_average;
106 ADC0_SC3 = ADC_SC3_CAL; // begin cal
107 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
108 ADC1_SC3 = ADC_SC3_CAL; // begin cal
110 } else if (num <= 4) {
111 ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0);
112 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
113 ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0);
115 } else if (num <= 8) {
116 ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1);
117 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
118 ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1);
120 } else if (num <= 16) {
121 ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2);
122 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
123 ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2);
126 ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3);
127 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
128 ADC1_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3);
134 static void wait_for_cal(void)
138 //serial_print("wait_for_cal\n");
139 #if defined(_mk20dx128_)
140 while (ADC0_SC3 & ADC_SC3_CAL) {
143 #elif defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
144 while ((ADC0_SC3 & ADC_SC3_CAL) || (ADC1_SC3 & ADC_SC3_CAL)) {
150 //serial_print("\n");
151 sum = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0;
152 sum = (sum / 2) | 0x8000;
154 //serial_print("ADC0_PG = ");
155 //serial_phex16(sum);
156 //serial_print("\n");
157 sum = ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0;
158 sum = (sum / 2) | 0x8000;
160 //serial_print("ADC0_MG = ");
161 //serial_phex16(sum);
162 //serial_print("\n");
163 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
164 sum = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0;
165 sum = (sum / 2) | 0x8000;
167 sum = ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0;
168 sum = (sum / 2) | 0x8000;
176 // ADCx_SC2[REFSEL] bit selects the voltage reference sources for ADC.
177 // VREFH/VREFL - connected as the primary reference option
178 // 1.2 V VREF_OUT - connected as the VALT reference option
183 #define INTERNAL1V2 2
184 #define INTERNAL1V1 2
187 void analogReference(uint8_t type)
190 // internal reference requested
191 if (!analog_reference_internal) {
192 analog_reference_internal = 1;
194 ADC0_SC3 = 0; // cancel cal
195 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
196 ADC1_SC3 = 0; // cancel cal
202 // vcc or external reference requested
203 if (analog_reference_internal) {
204 analog_reference_internal = 0;
206 ADC0_SC3 = 0; // cancel cal
207 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
208 ADC1_SC3 = 0; // cancel cal
217 void analogReadRes(unsigned int bits)
222 if (bits > 16) bits = 16;
224 } else if (bits >= 11) {
226 } else if (bits >= 9) {
231 analog_right_shift = config - bits;
232 if (config != analog_config_bits) {
233 analog_config_bits = config;
234 if (calibrating) ADC0_SC3 = 0; // cancel cal
239 void analogReadAveraging(unsigned int num)
242 if (calibrating) wait_for_cal();
246 } else if (num <= 4) {
248 ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0);
249 } else if (num <= 8) {
251 ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1);
252 } else if (num <= 16) {
254 ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2);
257 ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3);
259 analog_num_average = num;
262 // The SC1A register is used for both software and hardware trigger modes of operation.
264 #if defined(_mk20dx128_)
265 static const uint8_t channel2sc1a[] = {
266 5, 14, 8, 9, 13, 12, 6, 7, 15, 4,
267 0, 19, 3, 21, 26, 22, 23
269 #elif defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
270 static const uint8_t channel2sc1a[] = {
271 5, 14, 8, 9, 13, 12, 6, 7, 15, 4,
272 0, 19, 3, 19+128, 26, 22, 23,
273 5+192, 5+128, 4+128, 6+128, 7+128, 4+192
274 // A15 26 E1 ADC1_SE5a 5+64
275 // A16 27 C9 ADC1_SE5b 5
276 // A17 28 C8 ADC1_SE4b 4
277 // A18 29 C10 ADC1_SE6b 6
278 // A19 30 C11 ADC1_SE7b 7
279 // A20 31 E0 ADC1_SE4a 4+64
285 // TODO: perhaps this should store the NVIC priority, so it works recursively?
286 static volatile uint8_t analogReadBusyADC0 = 0;
287 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
288 static volatile uint8_t analogReadBusyADC1 = 0;
291 int analogRead(uint8_t pin)
294 uint8_t index, channel;
300 index = pin; // 0-13 refer to A0-A13
301 } else if (pin <= 23) {
302 index = pin - 14; // 14-23 are A0-A9
303 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
304 } else if (pin >= 26 && pin <= 31) {
305 index = pin - 9; // 26-31 are A15-A20
307 } else if (pin >= 34 && pin <= 40) {
308 index = pin - 24; // 34-37 are A10-A13, 38 is temp sensor,
309 // 39 is vref, 40 is unused (A14 on Teensy 3.1)
311 return 0; // all others are invalid
314 //serial_phex(index);
317 channel = channel2sc1a[index];
318 //serial_phex(channel);
321 //serial_print("analogRead");
323 if (calibrating) wait_for_cal();
324 //pin = 5; // PTD1/SE5b, pin 14, analog 0
326 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
327 if (channel & 0x80) goto beginADC1;
332 //serial_print("startADC0\n");
334 analogReadBusyADC0 = 1;
338 if ((ADC0_SC1A & ADC_SC1_COCO)) {
340 analogReadBusyADC0 = 0;
342 result >>= analog_right_shift;
345 // detect if analogRead was used from an interrupt
346 // if so, our analogRead got canceled, so it must
348 if (!analogReadBusyADC0) goto startADC0;
353 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
357 //serial_print("startADC0\n");
358 // ADC1_CFG2[MUXSEL] bit selects between ADCx_SEn channels a and b.
359 if (channel & 0x40) {
360 ADC1_CFG2 &= ~ADC_CFG2_MUXSEL;
362 ADC1_CFG2 |= ADC_CFG2_MUXSEL;
364 ADC1_SC1A = channel & 0x3F;
365 analogReadBusyADC1 = 1;
369 if ((ADC1_SC1A & ADC_SC1_COCO)) {
371 analogReadBusyADC1 = 0;
373 result >>= analog_right_shift;
376 // detect if analogRead was used from an interrupt
377 // if so, our analogRead got canceled, so it must
379 if (!analogReadBusyADC1) goto startADC1;
388 void analogWriteDAC0(int val)
390 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
391 SIM_SCGC2 |= SIM_SCGC2_DAC0;
392 if (analog_reference_internal) {
393 DAC0_C0 = DAC_C0_DACEN; // 1.2V ref is DACREF_1
395 DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2
397 if (val < 0) val = 0; // TODO: saturate instruction?
398 else if (val > 4095) val = 4095;
399 *(int16_t *)&(DAC0_DAT0L) = val;