\
uint8_t DMARxBuffer::read_ptr_ = 0;
template \
typename P::Value DMARxBuffer::buffer_[b];
// Uses DMA to automatically feed data to a peripheral.
template<
uint8_t channel_index,
uint16_t buffer_size,
typename Destination,
typename Trigger,
bool one_shot = false>
class DMATxBuffer {
private:
typedef DMAChannel Channel;
typedef typename Destination::Value Value;
public:
DMATxBuffer() { }
static inline void Init() {
DMA_CTRL = 0x80;
uint8_t address_control = 0;
address_control |= DMA_CH_SRCRELOAD_BLOCK_gc;
address_control |= DMA_CH_DESTRELOAD_BURST_gc;
address_control |= DMA_CH_SRCDIR_INC_gc;
address_control |= DMA_CH_DESTDIR_INC_gc;
Channel::channel().ADDRCTRL = address_control;
Channel::channel().REPCNT = one_shot ? 1 : 0;
Channel::channel().TRFCNT = buffer_size * sizeof(Value);
uint32_t source = (uint32_t)(&buffer_);
uint32_t destination = (uint32_t)(Destination::dma_data());
Channel::channel().SRCADDR0 = (source >> 0) & 0xff;
Channel::channel().SRCADDR1 = (source >> 8) & 0xff;
Channel::channel().SRCADDR2 = (source >> 16) & 0xff;
Channel::channel().DESTADDR0 = (destination >> 0) & 0xff;
Channel::channel().DESTADDR1 = (destination >> 8) & 0xff;
Channel::channel().DESTADDR2 = (destination >> 16) & 0xff;
Channel::channel().TRIGSRC = Trigger::dma_tx_trigger();
Channel::channel().CTRLA = DMA_CH_REPEAT_bm | DMA_CH_SINGLE_bm;
if (sizeof(Value) == 2) {
Channel::channel().CTRLA |= DMA_CH_BURSTLEN_2BYTE_gc;
} else if (sizeof(Value) == 4) {
Channel::channel().CTRLA |= DMA_CH_BURSTLEN_4BYTE_gc;
} else if (sizeof(Value) == 8) {
Channel::channel().CTRLA |= DMA_CH_BURSTLEN_8BYTE_gc;
}
}
static inline uint8_t writable() {
uint8_t read_ptr = buffer_size - Channel::channel().TRFCNTL / sizeof(Value);
return (read_ptr - write_ptr_ - 1) & (buffer_size - 1);
}
static inline void Write(Value v) {
while (!writable());
Overwrite(v);
}
static inline void Overwrite(Value v) {
uint8_t w = write_ptr_;
buffer_[w] = v;
write_ptr_ = (w + 1) & (buffer_size - 1);
}
static inline void Start() {
Channel::channel().CTRLA |= DMA_CH_ENABLE_bm;
}
static inline void Stop() {
Channel::channel().CTRLA &= ~DMA_CH_ENABLE_bm;
}
private:
static uint8_t write_ptr_;
static Value buffer_[buffer_size];
DISALLOW_COPY_AND_ASSIGN(DMATxBuffer);
};
template \
uint8_t DMATxBuffer::write_ptr_ = 0;
template \
typename D::Value DMATxBuffer::buffer_[b];
} // namespace avrlibx
#endif // AVRLIBX_IO_DMA_H_