]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Scan/ADCTest/analog.c
Move matrix information to a cli command
[kiibohd-controller.git] / Scan / ADCTest / analog.c
1 /* Teensyduino Core Library
2  * http://www.pjrc.com/teensy/
3  * Copyright (c) 2013 PJRC.COM, LLC.
4  *
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:
12  *
13  * 1. The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
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.
20  *
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
28  * SOFTWARE.
29  */
30
31 #include <Lib/ScanLib.h>
32
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;
38
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
42
43 #if F_BUS == 48000000
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)
51 #else
52 #error
53 #endif
54
55 void analog_init(void)
56 {
57         uint32_t num;
58
59         VREF_TRM = 0x60;
60         VREF_SC = 0xE1;         // enable 1.2 volt ref
61
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);
68                 #endif
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);
75                 #endif
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);
82                 #endif
83         } else {
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);
89                 #endif
90         }
91
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
96                 #endif
97         } else {
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
101                 #endif
102         }
103
104         num = analog_num_average;
105         if (num <= 1) {
106                 ADC0_SC3 = ADC_SC3_CAL;  // begin cal
107                 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
108                 ADC1_SC3 = ADC_SC3_CAL;  // begin cal
109                 #endif
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);
114                 #endif
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);
119                 #endif
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);
124                 #endif
125         } else {
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);
129                 #endif
130         }
131         calibrating = 1;
132 }
133
134 static void wait_for_cal(void)
135 {
136         uint16_t sum;
137
138         //serial_print("wait_for_cal\n");
139 #if defined(_mk20dx128_)
140         while (ADC0_SC3 & ADC_SC3_CAL) {
141                 // wait
142         }
143 #elif defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
144         while ((ADC0_SC3 & ADC_SC3_CAL) || (ADC1_SC3 & ADC_SC3_CAL)) {
145                 // wait
146         }
147 #endif
148         __disable_irq();
149         if (calibrating) {
150                 //serial_print("\n");
151                 sum = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0;
152                 sum = (sum / 2) | 0x8000;
153                 ADC0_PG = sum;
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;
159                 ADC0_MG = sum;
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;
166                 ADC1_PG = sum;
167                 sum = ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0;
168                 sum = (sum / 2) | 0x8000;
169                 ADC1_MG = sum;
170 #endif
171                 calibrating = 0;
172         }
173         __enable_irq();
174 }
175
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
179
180
181 #define DEFAULT         0
182 #define INTERNAL        2
183 #define INTERNAL1V2     2
184 #define INTERNAL1V1     2
185 #define EXTERNAL        0
186
187 void analogReference(uint8_t type)
188 {
189         if (type) {
190                 // internal reference requested
191                 if (!analog_reference_internal) {
192                         analog_reference_internal = 1;
193                         if (calibrating) {
194                                 ADC0_SC3 = 0; // cancel cal
195 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
196                                 ADC1_SC3 = 0; // cancel cal
197 #endif
198                         }
199                         analog_init();
200                 }
201         } else {
202                 // vcc or external reference requested
203                 if (analog_reference_internal) {
204                         analog_reference_internal = 0;
205                         if (calibrating) {
206                                 ADC0_SC3 = 0; // cancel cal
207 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
208                                 ADC1_SC3 = 0; // cancel cal
209 #endif
210                         }
211                         analog_init();
212                 }
213         }
214 }
215
216
217 void analogReadRes(unsigned int bits)
218 {
219         unsigned int config;
220
221         if (bits >= 13) {
222                 if (bits > 16) bits = 16;
223                 config = 16;
224         } else if (bits >= 11) {
225                 config = 12;
226         } else if (bits >= 9) {
227                 config = 10;
228         } else {
229                 config = 8;
230         }
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
235                 analog_init();
236         }
237 }
238
239 void analogReadAveraging(unsigned int num)
240 {
241
242         if (calibrating) wait_for_cal();
243         if (num <= 1) {
244                 num = 0;
245                 ADC0_SC3 = 0;
246         } else if (num <= 4) {
247                 num = 4;
248                 ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0);
249         } else if (num <= 8) {
250                 num = 8;
251                 ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1);
252         } else if (num <= 16) {
253                 num = 16;
254                 ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2);
255         } else {
256                 num = 32;
257                 ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3);
258         }
259         analog_num_average = num;
260 }
261
262 // The SC1A register is used for both software and hardware trigger modes of operation.
263
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
268 };
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
280 };
281 #endif
282
283
284
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;
289 #endif
290
291 int analogRead(uint8_t pin)
292 {
293         int result;
294         uint8_t index, channel;
295
296         //serial_phex(pin);
297         //serial_print(" ");
298
299         if (pin <= 13) {
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
306 #endif
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)
310         } else {
311                 return 0;   // all others are invalid
312         }
313
314         //serial_phex(index);
315         //serial_print(" ");
316
317         channel = channel2sc1a[index];
318         //serial_phex(channel);
319         //serial_print(" ");
320
321         //serial_print("analogRead");
322         //return 0;
323         if (calibrating) wait_for_cal();
324         //pin = 5; // PTD1/SE5b, pin 14, analog 0
325
326 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
327         if (channel & 0x80) goto beginADC1;
328 #endif
329
330         __disable_irq();
331 startADC0:
332         //serial_print("startADC0\n");
333         ADC0_SC1A = channel;
334         analogReadBusyADC0 = 1;
335         __enable_irq();
336         while (1) {
337                 __disable_irq();
338                 if ((ADC0_SC1A & ADC_SC1_COCO)) {
339                         result = ADC0_RA;
340                         analogReadBusyADC0 = 0;
341                         __enable_irq();
342                         result >>= analog_right_shift;
343                         return result;
344                 }
345                 // detect if analogRead was used from an interrupt
346                 // if so, our analogRead got canceled, so it must
347                 // be restarted.
348                 if (!analogReadBusyADC0) goto startADC0;
349                 __enable_irq();
350                 yield();
351         }
352
353 #if defined(_mk20dx256_) || defined(_mk20dx256vlh7_)
354 beginADC1:
355         __disable_irq();
356 startADC1:
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;
361         } else {
362                 ADC1_CFG2 |= ADC_CFG2_MUXSEL;
363         }
364         ADC1_SC1A = channel & 0x3F;
365         analogReadBusyADC1 = 1;
366         __enable_irq();
367         while (1) {
368                 __disable_irq();
369                 if ((ADC1_SC1A & ADC_SC1_COCO)) {
370                         result = ADC1_RA;
371                         analogReadBusyADC1 = 0;
372                         __enable_irq();
373                         result >>= analog_right_shift;
374                         return result;
375                 }
376                 // detect if analogRead was used from an interrupt
377                 // if so, our analogRead got canceled, so it must
378                 // be restarted.
379                 if (!analogReadBusyADC1) goto startADC1;
380                 __enable_irq();
381                 yield();
382         }
383 #endif
384 }
385
386
387
388 void analogWriteDAC0(int val)
389 {
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
394         } else {
395                 DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2
396         }
397         if (val < 0) val = 0;  // TODO: saturate instruction?
398         else if (val > 4095) val = 4095;
399         *(int16_t *)&(DAC0_DAT0L) = val;
400 #endif
401 }
402