ADC: ADC_Module.h Source File

ADC 8.0 Analog to Digital Conversor library for the Teensy 3.5 microprocessor

ADC_Module.h
1 /* Teensy 4, 3.x, LC ADC library
2 * https://github.com/pedvide/ADC
3 * Copyright (c) 2019 Pedro Villanueva
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 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 /* ADC_Module.h: Declarations of the fuctions of a Teensy 3.x, LC ADC module
27 *
28 */
29
36 #ifndef ADC_MODULE_H
37 #define ADC_MODULE_H
38
39 #include <Arduino.h>
40 #include <settings_defines.h>
41 #include <atomic.h>
42
43 using ADC_Error::ADC_ERROR;
44 using namespace ADC_settings;
45
46
47 // debug mode: blink the led light
48 #define ADC_debug 0
49
50
54 class ADC_Module {
55
56 public:
57
58 #if ADC_DIFF_PAIRS > 0
59
63 struct ADC_NLIST {
65 uint8_t pin, sc1a;
66 };
67 #endif
68
70 #if ADC_DIFF_PAIRS > 0
71
78 ADC_Module(uint8_t ADC_number,
79 const uint8_t* const a_channel2sc1a,
80 const ADC_NLIST* const a_diff_table,
81 ADC_REGS_t &a_adc_regs);
82 #else
83
89 ADC_Module(uint8_t ADC_number,
90 const uint8_t* const a_channel2sc1a,
91 ADC_REGS_t &a_adc_regs);
92 #endif
93
94
96
99 void recalibrate();
100
102 void calibrate();
103
105 void wait_for_cal();
106
107
109
111
116 void setReference(ADC_REFERENCE ref_type);
117
118
120
129 void setResolution(uint8_t bits);
130
132
135 uint8_t getResolution();
136
138
141 uint32_t getMaxValue();
142
143
145
162 void setConversionSpeed(ADC_CONVERSION_SPEED speed);
163
164
166
175 void setSamplingSpeed(ADC_SAMPLING_SPEED speed);
176
177
179
184 void setAveraging(uint8_t num);
185
186
188
193 void enableInterrupts(void (*isr)(void), uint8_t priority=255);
194
196 void disableInterrupts();
197
198
199 #ifdef ADC_USE_DMA
200
204 void enableDMA();
205
207 void disableDMA();
208 #endif
209
210
212
219 void enableCompare(int16_t compValue, bool greaterThan);
220
222
232 void enableCompareRange(int16_t lowerLimit, int16_t upperLimit, bool insideRange, bool inclusive);
233
235 void disableCompare();
236
237
238 #ifdef ADC_USE_PGA
239
244 void enablePGA(uint8_t gain);
245
247
250 uint8_t getPGA();
251
253 void disablePGA();
254 #endif
255
256
258 void continuousMode() __attribute__((always_inline)) {
259 #ifdef ADC_TEENSY_4
260 atomic::setBitFlag(adc_regs.GC, ADC_GC_ADCO);
261 #else
262 atomic::setBitFlag(adc_regs.SC3, ADC_SC3_ADCO);
263 #endif
264 }
266 void singleMode() __attribute__((always_inline)) {
267 #ifdef ADC_TEENSY_4
268 atomic::clearBitFlag(adc_regs.GC, ADC_GC_ADCO);
269 #else
270 atomic::clearBitFlag(adc_regs.SC3, ADC_SC3_ADCO);
271 #endif
272 }
273
275 void singleEndedMode() __attribute__((always_inline)) {
276 #ifdef ADC_TEENSY_4
277 // Teensy 4 is always single-ended
278 #else
279 atomic::clearBitFlag(adc_regs.SC1A, ADC_SC1_DIFF);
280 #endif
281 }
282 #if ADC_DIFF_PAIRS > 0
283 void differentialMode() __attribute__((always_inline)) {
285 atomic::setBitFlag(adc_regs.SC1A, ADC_SC1_DIFF);
286 }
287 #endif
288
290 void setSoftwareTrigger() __attribute__((always_inline)) {
291 #ifdef ADC_TEENSY_4
292 atomic::clearBitFlag(adc_regs.CFG, ADC_CFG_ADTRG);
293 #else
294 atomic::clearBitFlag(adc_regs.SC2, ADC_SC2_ADTRG);
295 #endif
296 }
297
299 void setHardwareTrigger() __attribute__((always_inline)) {
300 #ifdef ADC_TEENSY_4
301 atomic::setBitFlag(adc_regs.CFG, ADC_CFG_ADTRG);
302 #else
303 atomic::setBitFlag(adc_regs.SC2, ADC_SC2_ADTRG);
304 #endif
305 }
306
307
309
311
314 volatile bool isConverting() __attribute__((always_inline)) {
315 #ifdef ADC_TEENSY_4
316 return atomic::getBitFlag(adc_regs.GS, ADC_GS_ADACT);
317 #else
318 //return (ADC_SC2_adact);
319 return atomic::getBitFlag(adc_regs.SC2, ADC_SC2_ADACT);
320 //return ((adc_regs.SC2) & ADC_SC2_ADACT) >> 7;
321 #endif
322 }
323
325
330 volatile bool isComplete() __attribute__((always_inline)) {
331 #ifdef ADC_TEENSY_4
332 return atomic::getBitFlag(adc_regs.HS, ADC_HS_COCO0);
333 #else
334 //return (ADC_SC1A_coco);
335 return atomic::getBitFlag(adc_regs.SC1A, ADC_SC1_COCO);
336 //return ((adc_regs.SC1A) & ADC_SC1_COCO) >> 7;
337 #endif
338 }
339
340 #if ADC_DIFF_PAIRS > 0
341
345 volatile bool isDifferential() __attribute__((always_inline)) {
346 //return ((adc_regs.SC1A) & ADC_SC1_DIFF) >> 5;
347 return atomic::getBitFlag(adc_regs.SC1A, ADC_SC1_DIFF);
348 }
349 #endif
350
352
355 volatile bool isContinuous() __attribute__((always_inline)) {
356 #ifdef ADC_TEENSY_4
357 return atomic::getBitFlag(adc_regs.GC, ADC_GC_ADCO);
358 #else
359 //return (ADC_SC3_adco);
360 return atomic::getBitFlag(adc_regs.SC3, ADC_SC3_ADCO);
361 //return ((adc_regs.SC3) & ADC_SC3_ADCO) >> 3;
362 #endif
363 }
364
365 #ifdef ADC_USE_PGA
366
370 volatile bool isPGAEnabled() __attribute__((always_inline)) {
371 return atomic::getBitFlag(adc_regs.PGA, ADC_PGA_PGAEN);
372 }
373 #endif
374
375
377
379
383 bool checkPin(uint8_t pin);
384
386
391 bool checkDifferentialPins(uint8_t pinP, uint8_t pinN);
392
393
395
397
401 void startReadFast(uint8_t pin); // helper method
402
403 #if ADC_DIFF_PAIRS > 0
404
410 void startDifferentialFast(uint8_t pinP, uint8_t pinN);
411 #endif
412
413
415
417
423 int analogRead(uint8_t pin);
424
426
436 int analogRead(ADC_INTERNAL_SOURCE pin) __attribute__((always_inline)) {
437 return analogRead(static_cast<uint8_t>(pin));
438 }
439
440
441 #if ADC_DIFF_PAIRS > 0
442
450 int analogReadDifferential(uint8_t pinP, uint8_t pinN);
451 #endif
452
453
455
457
462 bool startSingleRead(uint8_t pin);
463
464 #if ADC_DIFF_PAIRS > 0
465
472 bool startSingleDifferential(uint8_t pinP, uint8_t pinN);
473 #endif
474
476
479 int readSingle() __attribute__((always_inline)) {
480 return analogReadContinuous();
481 }
482
483
485
487
491 bool startContinuous(uint8_t pin);
492
493 #if ADC_DIFF_PAIRS > 0
494
500 bool startContinuousDifferential(uint8_t pinP, uint8_t pinN);
501 #endif
502
504
509 int analogReadContinuous() __attribute__((always_inline)) {
510 #ifdef ADC_TEENSY_4
511 return (int16_t)(int32_t)adc_regs.R0;
512 #else
513 return (int16_t)(int32_t)adc_regs.RA;
514 #endif
515 }
516
518 void stopContinuous();
519
521 // The general API is:
522 // void startTimer(uint32_t freq)
523 // void stopTimer()
524 // uint32_t getTimerFrequency()
525 // For each board the best timer method will be selected
526
529 #if defined(ADC_USE_PDB)
530
532
537 void startTimer(uint32_t freq) __attribute__((always_inline)) { startPDB(freq); }
539
543 void startPDB(uint32_t freq);
544
546 void stopTimer() __attribute__((always_inline)) { stopPDB(); }
548 void stopPDB();
549
551
554 uint32_t getTimerFrequency() __attribute__((always_inline)) { return getPDBFrequency(); }
556
559 uint32_t getPDBFrequency();
560
563 #elif defined(ADC_USE_QUAD_TIMER)
564
570 void startTimer(uint32_t freq) __attribute__((always_inline)) { startQuadTimer(freq); }
572
576 void startQuadTimer(uint32_t freq);
577
579 void stopTimer() __attribute__((always_inline)) { stopQuadTimer(); }
581 void stopQuadTimer();
582
584
587 uint32_t getTimerFrequency() __attribute__((always_inline)) { return getQuadTimerFrequency(); }
589
592 uint32_t getQuadTimerFrequency();
593 #endif
594
595
596
598
600 struct ADC_Config {
602 #ifdef ADC_TEENSY_4
603 uint32_t savedHC0, savedCFG, savedGC, savedGS;
604 #else
605 uint32_t savedSC1A, savedSC2, savedSC3, savedCFG1, savedCFG2;
606 #endif
607 } adc_config;
608
610 uint8_t adcWasInUse;
611
615 void saveConfig(ADC_Config* config) {
616 #ifdef ADC_TEENSY_4
617 config->savedHC0 = adc_regs.HC0;
618 config->savedCFG = adc_regs.CFG;
619 config->savedGC = adc_regs.GC;
620 config->savedGS = adc_regs.GS;
621 #else
622 config->savedSC1A = adc_regs.SC1A;
623 config->savedCFG1 = adc_regs.CFG1;
624 config->savedCFG2 = adc_regs.CFG2;
625 config->savedSC2 = adc_regs.SC2;
626 config->savedSC3 = adc_regs.SC3;
627 #endif
628 }
629
633 void loadConfig(const ADC_Config* config) {
634 #ifdef ADC_TEENSY_4
635 adc_regs.HC0 = config->savedHC0;
636 adc_regs.CFG = config->savedCFG;
637 adc_regs.GC = config->savedGC;
638 adc_regs.GS = config->savedGS;
639 #else
640 adc_regs.CFG1 = config->savedCFG1;
641 adc_regs.CFG2 = config->savedCFG2;
642 adc_regs.SC2 = config->savedSC2;
643 adc_regs.SC3 = config->savedSC3;
644 adc_regs.SC1A = config->savedSC1A; // restore last
645 #endif
646 }
647
648
650 uint8_t num_measurements;
651
652
654
656 volatile ADC_ERROR fail_flag;
657
659 void resetError() {
660 ADC_Error::resetError(fail_flag);
661 }
662
663
665 const uint8_t ADC_num;
666
667
668 private:
669
670 // is set to 1 when the calibration procedure is taking place
671 uint8_t calibrating;
672
673 // the first calibration will use 32 averages and lowest speed,
674 // when this calibration is over the averages and speed will be set to default.
675 uint8_t init_calib;
676
677 // resolution
678 uint8_t analog_res_bits;
679
680 // maximum value possible 2^res-1
681 uint32_t analog_max_val;
682
683 // num of averages
684 uint8_t analog_num_average;
685
686 // reference can be internal or external
687 ADC_REF_SOURCE analog_reference_internal;
688
689 #ifdef ADC_USE_PGA
690 // value of the pga
691 uint8_t pga_value;
692 #endif
693
694 // conversion speed
695 ADC_CONVERSION_SPEED conversion_speed;
696
697 // sampling speed
698 ADC_SAMPLING_SPEED sampling_speed;
699
700 // translate pin number to SC1A nomenclature
701 const uint8_t* const channel2sc1a;
702
703 // are interrupts on?
704 bool interrupts_enabled;
705
706
707 // same for differential pins
708 #if ADC_DIFF_PAIRS > 0
709 const ADC_NLIST* const diff_table;
710
712 uint8_t getDifferentialPair(uint8_t pin) {
713 for(uint8_t i=0; i<ADC_DIFF_PAIRS; i++) {
714 if(diff_table[i].pin == pin) {
715 return diff_table[i].sc1a;
716 }
717 }
718 return ADC_SC1A_PIN_INVALID;
719 }
720 #endif
721
722
724 void analog_init();
725
727 void startClock() {
728 #if defined(ADC_TEENSY_4)
729 if (ADC_num == 0) {
730 CCM_CCGR1 |= CCM_CCGR1_ADC1(CCM_CCGR_ON);
731 } else {
732 CCM_CCGR1 |= CCM_CCGR1_ADC2(CCM_CCGR_ON);
733 }
734 #else
735 if (ADC_num == 0) {
736 SIM_SCGC6 |= SIM_SCGC6_ADC0;
737 } else {
738 SIM_SCGC3 |= SIM_SCGC3_ADC1;
739 }
740 #endif
741 }
742
743 // registers point to the correct ADC module
744 typedef volatile uint32_t& reg;
745
746 // registers that control the adc module
747 ADC_REGS_t &adc_regs;
748
749 #ifdef ADC_USE_PDB
750 reg PDB0_CHnC1; // PDB channel 0 or 1
751 #endif
752 #ifdef ADC_TEENSY_4
753 uint8_t XBAR_IN;
754 uint8_t XBAR_OUT;
755 uint8_t QTIMER4_INDEX;
756 uint8_t ADC_ETC_TRIGGER_INDEX;
757 #endif
758 const IRQ_NUMBER_t IRQ_ADC; // IRQ number
759
760 protected:
761
762
763 };
764
765 #endif // ADC_MODULE_H
ADC_Module::isDifferential
volatile bool isDifferential()
Is the ADC in differential mode?
Definition: ADC_Module.h:345
ADC_Module::ADC_Config::savedSC1A
uint32_t savedSC1A
ADC registers.
Definition: ADC_Module.h:605
ADC_Module::loadConfig
void loadConfig(const ADC_Config *config)
Definition: ADC_Module.h:633
ADC_Module::setSoftwareTrigger
void setSoftwareTrigger()
Use software to trigger the ADC, this is the most common setting.
Definition: ADC_Module.h:290
ADC_Module::stopTimer
void stopTimer()
Stop the default timer (PDB)
Definition: ADC_Module.h:546
ADC_Module::saveConfig
void saveConfig(ADC_Config *config)
Definition: ADC_Module.h:615
ADC_Module::resetError
void resetError()
Resets all errors from the ADC, if any.
Definition: ADC_Module.h:659
ADC_settings
Board-dependent settings.
Definition: settings_defines.h:37
ADC_Module::analogReadContinuous
int analogReadContinuous()
Reads the analog value of a continuous conversion.
Definition: ADC_Module.h:509
ADC_Module
Definition: ADC_Module.h:54
ADC_Module::ADC_Config
Store the config of the adc.
Definition: ADC_Module.h:600
ADC_Module::setHardwareTrigger
void setHardwareTrigger()
Use hardware to trigger the ADC.
Definition: ADC_Module.h:299
ADC_Module::readSingle
int readSingle()
Reads the analog value of a single conversion.
Definition: ADC_Module.h:479
ADC_Module::continuousMode
void continuousMode()
Set continuous conversion mode.
Definition: ADC_Module.h:258
ADC_Module::ADC_num
const uint8_t ADC_num
Which adc is this?
Definition: ADC_Module.h:665
ADC_settings::ADC_SAMPLING_SPEED
ADC_SAMPLING_SPEED
Definition: settings_defines.h:514
ADC_settings::ADC_INTERNAL_SOURCE
ADC_INTERNAL_SOURCE
Definition: settings_defines.h:231
ADC_Module::getTimerFrequency
uint32_t getTimerFrequency()
Return the default timer's (PDB) frequency.
Definition: ADC_Module.h:554
ADC_Module::num_measurements
uint8_t num_measurements
Number of measurements that the ADC is performing.
Definition: ADC_Module.h:650
ADC_Error::ADC_ERROR
ADC_ERROR
ADC errors.
Definition: settings_defines.h:566
ADC_Module::isContinuous
volatile bool isContinuous()
Is the ADC in continuous mode?
Definition: ADC_Module.h:355
ADC_Module::singleEndedMode
void singleEndedMode()
Set single-ended conversion mode.
Definition: ADC_Module.h:275
ADC_Module::startTimer
void startTimer(uint32_t freq)
Start the default timer (PDB) triggering the ADC at the frequency.
Definition: ADC_Module.h:537
ADC_Module::isComplete
volatile bool isComplete()
Is an ADC conversion ready?
Definition: ADC_Module.h:330
ADC_settings::ADC_REFERENCE
ADC_REFERENCE
Voltage reference for the ADC.
Definition: settings_defines.h:151
ADC_Module::adcWasInUse
uint8_t adcWasInUse
Was the adc in use before a call?
Definition: ADC_Module.h:610
ADC_settings::ADC_CONVERSION_SPEED
ADC_CONVERSION_SPEED
Definition: settings_defines.h:487
ADC_Module::analogRead
int analogRead(ADC_INTERNAL_SOURCE pin)
Returns the analog value of the special internal source, such as the temperature sensor.
Definition: ADC_Module.h:436
ADC_Module::fail_flag
volatile ADC_ERROR fail_flag
This flag indicates that some kind of error took place.
Definition: ADC_Module.h:656
ADC_Module::singleMode
void singleMode()
Set single-shot conversion mode.
Definition: ADC_Module.h:266
ADC_Module::isConverting
volatile bool isConverting()
Is the ADC converting at the moment?
Definition: ADC_Module.h:314