ADC  8.0
Analog to Digital Conversor library for the Teensy 4 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 
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 
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::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 (QuadTimer)
Definition: ADC_Module.h:579
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:241
ADC_Module::getTimerFrequency
uint32_t getTimerFrequency()
Return the default timer's (QuadTimer) frequency.
Definition: ADC_Module.h:587
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 (QuadTimer) triggering the ADC at the frequency.
Definition: ADC_Module.h:570
ADC_Module::ADC_Config::savedHC0
uint32_t savedHC0
ADC registers.
Definition: ADC_Module.h:603
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:169
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