// 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_