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.

134 lines
3.5KB

  1. // Copyright 2011 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. #ifndef AVRLIBX_IO_DAC_H_
  16. #define AVRLIBX_IO_DAC_H_
  17. #include <avr/io.h>
  18. #include "avrlibx/avrlibx.h"
  19. #include "avrlibx/io/gpio.h"
  20. namespace avrlibx {
  21. template<typename Port>
  22. struct DACWrapper { };
  23. #define WRAP_DAC(port) \
  24. template<> \
  25. struct DACWrapper<Port ## port> { \
  26. static inline DAC_t& dac() { return DAC ## port; } \
  27. static inline uint8_t status() { return DAC ## port ## _STATUS; } \
  28. template<int channel> \
  29. struct Channel { \
  30. static inline void Write(uint16_t value) { \
  31. if (channel == 0) { \
  32. DAC ## port ## _CH0DATA = value; \
  33. } else { \
  34. DAC ## port ## _CH1DATA = value; \
  35. } \
  36. } \
  37. static volatile void* dma_data() { return data(); } \
  38. static volatile void* data() { \
  39. if (channel == 0) { \
  40. return &(DAC ## port ## _CH0DATA); \
  41. } else { \
  42. return &(DAC ## port ## _CH1DATA); \
  43. } \
  44. } \
  45. }; \
  46. typedef uint16_t Value; \
  47. };
  48. WRAP_DAC(B)
  49. enum DACReference {
  50. DAC_REF_INTERNAL_1V = 0,
  51. DAC_REF_AVCC = 1,
  52. DAC_REF_PORTA_AREF = 2,
  53. DAC_REF_PORTB_AREF = 3
  54. };
  55. template<
  56. typename Port,
  57. bool ch0 = true,
  58. bool ch1 = false,
  59. DACReference reference = DAC_REF_INTERNAL_1V>
  60. struct DAC {
  61. typedef DACWrapper<Port> dac;
  62. static inline void Init() {
  63. uint8_t ctrl_a = DAC_ENABLE_bm;
  64. if (ch1) {
  65. ctrl_a |= DAC_CH1EN_bm;
  66. }
  67. if (ch0) {
  68. ctrl_a |= DAC_CH0EN_bm;
  69. }
  70. dac::dac().CTRLB = ch0 && !ch1 ? 0 : DAC_CHSEL1_bm;
  71. dac::dac().CTRLC = reference << DAC_REFSEL_gp | 0; // Right-adjust
  72. set_conversion_time(0x06); // 96 CLK between conversions
  73. set_refresh_time(0x01); // Very fast auto refresh for accurate timing.
  74. dac::dac().CTRLA = ctrl_a;
  75. }
  76. static inline void set_conversion_time(uint8_t conversion_time) {
  77. dac::dac().TIMCTRL = (dac::dac().TIMCTRL & ~DAC_CONINTVAL_gm) \
  78. | (conversion_time << DAC_CONINTVAL_gp);
  79. }
  80. static inline void set_refresh_time(uint8_t refresh_time) {
  81. dac::dac().TIMCTRL = (dac::dac().TIMCTRL & ~DAC_REFRESH_gm) \
  82. | (refresh_time << DAC_REFRESH_gp);
  83. }
  84. template<int channel>
  85. struct Channel {
  86. static inline uint8_t writable() {
  87. if (channel == 0) {
  88. return dac::status() & DAC_CH0DRE_bm;
  89. } else {
  90. return dac::status() & DAC_CH1DRE_bm;
  91. }
  92. }
  93. static inline void Write(uint16_t value) {
  94. dac::template Channel<channel>::Write(value);
  95. }
  96. static inline volatile void* dma_data() {
  97. return dac::template Channel<channel>::dma_data();
  98. }
  99. typedef uint16_t Value;
  100. };
  101. static uint8_t writable() {
  102. uint8_t mask = DAC_CH0DRE_bm | DAC_CH1DRE_bm;
  103. return dac::status() & mask == mask;
  104. }
  105. static inline void Wait() {
  106. while (!writable());
  107. }
  108. Channel<0> channel_0;
  109. Channel<1> channel_1;
  110. };
  111. } // namespace avrlibx
  112. #endif // AVRLIBX_IO_DAC_H_