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 16 #ifndef AVRLIBX_IO_DAC_H_ 17 #define AVRLIBX_IO_DAC_H_ 18 19 #include <avr/io.h> 20 21 #include "avrlibx/avrlibx.h" 22 #include "avrlibx/io/gpio.h" 23 24 namespace avrlibx { 25 26 template<typename Port> 27 struct DACWrapper { }; 28 29 #define WRAP_DAC(port) \ 30 template<> \ 31 struct DACWrapper<Port ## port> { \ 32 static inline DAC_t& dac() { return DAC ## port; } \ 33 static inline uint8_t status() { return DAC ## port ## _STATUS; } \ 34 template<int channel> \ 35 struct Channel { \ 36 static inline void Write(uint16_t value) { \ 37 if (channel == 0) { \ 38 DAC ## port ## _CH0DATA = value; \ 39 } else { \ 40 DAC ## port ## _CH1DATA = value; \ 41 } \ 42 } \ 43 static volatile void* dma_data() { return data(); } \ 44 static volatile void* data() { \ 45 if (channel == 0) { \ 46 return &(DAC ## port ## _CH0DATA); \ 47 } else { \ 48 return &(DAC ## port ## _CH1DATA); \ 49 } \ 50 } \ 51 }; \ 52 typedef uint16_t Value; \ 53 }; 54 55 WRAP_DAC(B) 56 57 enum DACReference { 58 DAC_REF_INTERNAL_1V = 0, 59 DAC_REF_AVCC = 1, 60 DAC_REF_PORTA_AREF = 2, 61 DAC_REF_PORTB_AREF = 3 62 }; 63 64 template< 65 typename Port, 66 bool ch0 = true, 67 bool ch1 = false, 68 DACReference reference = DAC_REF_INTERNAL_1V> 69 struct DAC { 70 typedef DACWrapper<Port> dac; 71 InitDAC72 static inline void Init() { 73 uint8_t ctrl_a = DAC_ENABLE_bm; 74 if (ch1) { 75 ctrl_a |= DAC_CH1EN_bm; 76 } 77 if (ch0) { 78 ctrl_a |= DAC_CH0EN_bm; 79 } 80 dac::dac().CTRLB = ch0 && !ch1 ? 0 : DAC_CHSEL1_bm; 81 dac::dac().CTRLC = reference << DAC_REFSEL_gp | 0; // Right-adjust 82 set_conversion_time(0x06); // 96 CLK between conversions 83 set_refresh_time(0x01); // Very fast auto refresh for accurate timing. 84 dac::dac().CTRLA = ctrl_a; 85 } 86 set_conversion_timeDAC87 static inline void set_conversion_time(uint8_t conversion_time) { 88 dac::dac().TIMCTRL = (dac::dac().TIMCTRL & ~DAC_CONINTVAL_gm) \ 89 | (conversion_time << DAC_CONINTVAL_gp); 90 } 91 set_refresh_timeDAC92 static inline void set_refresh_time(uint8_t refresh_time) { 93 dac::dac().TIMCTRL = (dac::dac().TIMCTRL & ~DAC_REFRESH_gm) \ 94 | (refresh_time << DAC_REFRESH_gp); 95 } 96 97 template<int channel> 98 struct Channel { writableDAC::Channel99 static inline uint8_t writable() { 100 if (channel == 0) { 101 return dac::status() & DAC_CH0DRE_bm; 102 } else { 103 return dac::status() & DAC_CH1DRE_bm; 104 } 105 } 106 WriteDAC::Channel107 static inline void Write(uint16_t value) { 108 dac::template Channel<channel>::Write(value); 109 } 110 dma_dataDAC::Channel111 static inline volatile void* dma_data() { 112 return dac::template Channel<channel>::dma_data(); 113 } 114 115 typedef uint16_t Value; 116 }; 117 writableDAC118 static uint8_t writable() { 119 uint8_t mask = DAC_CH0DRE_bm | DAC_CH1DRE_bm; 120 return dac::status() & mask == mask; 121 } 122 WaitDAC123 static inline void Wait() { 124 while (!writable()); 125 } 126 127 Channel<0> channel_0; 128 Channel<1> channel_1; 129 }; 130 131 } // namespace avrlibx 132 133 #endif // AVRLIBX_IO_DAC_H_ 134