// Copyright 2011 Olivier Gillet. // // Author: Olivier Gillet (ol.gillet@gmail.com) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . #ifndef AVRLIBX_IO_DAC_H_ #define AVRLIBX_IO_DAC_H_ #include #include "avrlibx/avrlibx.h" #include "avrlibx/io/gpio.h" namespace avrlibx { template struct DACWrapper { }; #define WRAP_DAC(port) \ template<> \ struct DACWrapper { \ static inline DAC_t& dac() { return DAC ## port; } \ static inline uint8_t status() { return DAC ## port ## _STATUS; } \ template \ struct Channel { \ static inline void Write(uint16_t value) { \ if (channel == 0) { \ DAC ## port ## _CH0DATA = value; \ } else { \ DAC ## port ## _CH1DATA = value; \ } \ } \ static volatile void* dma_data() { return data(); } \ static volatile void* data() { \ if (channel == 0) { \ return &(DAC ## port ## _CH0DATA); \ } else { \ return &(DAC ## port ## _CH1DATA); \ } \ } \ }; \ typedef uint16_t Value; \ }; WRAP_DAC(B) enum DACReference { DAC_REF_INTERNAL_1V = 0, DAC_REF_AVCC = 1, DAC_REF_PORTA_AREF = 2, DAC_REF_PORTB_AREF = 3 }; template< typename Port, bool ch0 = true, bool ch1 = false, DACReference reference = DAC_REF_INTERNAL_1V> struct DAC { typedef DACWrapper dac; static inline void Init() { uint8_t ctrl_a = DAC_ENABLE_bm; if (ch1) { ctrl_a |= DAC_CH1EN_bm; } if (ch0) { ctrl_a |= DAC_CH0EN_bm; } dac::dac().CTRLB = ch0 && !ch1 ? 0 : DAC_CHSEL1_bm; dac::dac().CTRLC = reference << DAC_REFSEL_gp | 0; // Right-adjust set_conversion_time(0x06); // 96 CLK between conversions set_refresh_time(0x01); // Very fast auto refresh for accurate timing. dac::dac().CTRLA = ctrl_a; } static inline void set_conversion_time(uint8_t conversion_time) { dac::dac().TIMCTRL = (dac::dac().TIMCTRL & ~DAC_CONINTVAL_gm) \ | (conversion_time << DAC_CONINTVAL_gp); } static inline void set_refresh_time(uint8_t refresh_time) { dac::dac().TIMCTRL = (dac::dac().TIMCTRL & ~DAC_REFRESH_gm) \ | (refresh_time << DAC_REFRESH_gp); } template struct Channel { static inline uint8_t writable() { if (channel == 0) { return dac::status() & DAC_CH0DRE_bm; } else { return dac::status() & DAC_CH1DRE_bm; } } static inline void Write(uint16_t value) { dac::template Channel::Write(value); } static inline volatile void* dma_data() { return dac::template Channel::dma_data(); } typedef uint16_t Value; }; static uint8_t writable() { uint8_t mask = DAC_CH0DRE_bm | DAC_CH1DRE_bm; return dac::status() & mask == mask; } static inline void Wait() { while (!writable()); } Channel<0> channel_0; Channel<1> channel_1; }; } // namespace avrlibx #endif // AVRLIBX_IO_DAC_H_