PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 line
4.9KB

  1. /* Teensy 4.x, 3.x, LC ADC library
  2. * https://github.com/pedvide/ADC
  3. * Copyright (c) 2020 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. #ifndef ADC_VREF_H
  26. #define ADC_VREF_H
  27. #include <Arduino.h>
  28. #include <atomic.h>
  29. #include <settings_defines.h>
  30. #ifdef ADC_USE_INTERNAL_VREF
  31. //! Controls the Teensy internal voltage reference module (VREFV1)
  32. namespace VREF
  33. {
  34. //! Start the 1.2V internal reference (if present)
  35. /** This is called automatically by ADC_Module::setReference(ADC_REFERENCE::REF_1V2)
  36. * Use it to switch on the internal reference on the VREF_OUT pin.
  37. * You can measure it with adc->analogRead(ADC_INTERNAL_SOURCE::VREF_OUT).
  38. * \param mode can be (these are defined in kinetis.h)
  39. * VREF_SC_MODE_LV_BANDGAPONLY (0) for stand-by
  40. * VREF_SC_MODE_LV_HIGHPOWERBUF (1) for high power buffer and
  41. * VREF_SC_MODE_LV_LOWPOWERBUF (2) for low power buffer.
  42. * \param trim adjusts the reference value, from 0 to 0x3F (63). Default is 32.
  43. *
  44. */
  45. inline void start(uint8_t mode = VREF_SC_MODE_LV_HIGHPOWERBUF, uint8_t trim = 0x20)
  46. {
  47. VREF_TRM = VREF_TRM_CHOPEN | (trim & 0x3F); // enable module and set the trimmer to medium (max=0x3F=63)
  48. // enable 1.2 volt ref with all compensations in high power mode
  49. VREF_SC = VREF_SC_VREFEN | VREF_SC_REGEN | VREF_SC_ICOMPEN | VREF_SC_MODE_LV(mode);
  50. // "PMC_REGSC[BGEN] bit must be set if the VREF regulator is
  51. // required to remain operating in VLPx modes."
  52. // Also "If the chop oscillator is to be used in very low power modes,
  53. // the system (bandgap) voltage reference must also be enabled."
  54. // enable bandgap, can be read directly with ADC_INTERNAL_SOURCE::BANDGAP
  55. atomic::setBitFlag(PMC_REGSC, PMC_REGSC_BGBE);
  56. }
  57. //! Set the trim
  58. /** Set the trim, the change in the reference is about 0.5 mV per step.
  59. * \param trim adjusts the reference value, from 0 to 0x3F (63).
  60. */
  61. inline void trim(uint8_t trim)
  62. {
  63. bool chopen = atomic::getBitFlag(VREF_TRM, VREF_TRM_CHOPEN);
  64. VREF_TRM = (chopen ? VREF_TRM_CHOPEN : 0) | (trim & 0x3F);
  65. }
  66. //! Stops the internal reference
  67. /** This is called automatically by ADC_Module::setReference(ref) when ref is any other than REF_1V2
  68. */
  69. __attribute__((always_inline)) inline void stop()
  70. {
  71. VREF_SC = 0;
  72. atomic::clearBitFlag(PMC_REGSC, PMC_REGSC_BGBE);
  73. }
  74. //! Check if the internal reference has stabilized.
  75. /** NOTE: This is valid only when the chop oscillator is not being used.
  76. * By default the chop oscillator IS used, so wait the maximum start-up time of 35 ms (as per datasheet).
  77. * waitUntilStable waits 35 us.
  78. * This should be polled after enabling the reference after reset, after changing
  79. * its buffer mode from VREF_SC_MODE_LV_BANDGAPONLY to any of the buffered modes, or
  80. * after changing the trim.
  81. *
  82. * \return true if the VREF module is already in a stable condition and can be used.
  83. */
  84. __attribute__((always_inline)) inline volatile bool isStable()
  85. {
  86. return atomic::getBitFlag(VREF_SC, VREF_SC_VREFST);
  87. }
  88. //! Check if the internal reference is on.
  89. /**
  90. * \return true if the VREF module is switched on.
  91. */
  92. __attribute__((always_inline)) inline volatile bool isOn()
  93. {
  94. return atomic::getBitFlag(VREF_SC, VREF_SC_VREFEN);
  95. }
  96. //! Wait for the internal reference to stabilize.
  97. /** This function can be called to wait for the internal reference to stabilize.
  98. * It will block until the reference has stabilized, or return immediately if the
  99. * reference is not enabled in the first place.
  100. */
  101. inline void waitUntilStable()
  102. {
  103. delay(35); // see note in isStable()
  104. while (isOn() && !isStable())
  105. {
  106. yield();
  107. }
  108. }
  109. } // namespace VREF
  110. #endif // ADC_USE_INTERNAL_VREF
  111. #endif // ADC_VREF_H