|
- // 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 <http://www.gnu.org/licenses/>.
-
- #ifndef AVRLIBX_IO_DMA_H_
- #define AVRLIBX_IO_DMA_H_
-
- #include <avr/io.h>
-
- #include "avrlibx/avrlibx.h"
-
- namespace avrlibx {
-
- template<uint8_t index>
- struct DMAChannel { };
-
- #define WRAP_DMA_CHANNEL(channel_index) \
- template<> \
- struct DMAChannel<channel_index> { \
- static inline DMA_CH_t& channel() { \
- return DMA.CH ## channel_index; \
- } \
- };
-
- WRAP_DMA_CHANNEL(0)
- WRAP_DMA_CHANNEL(1)
- WRAP_DMA_CHANNEL(2)
- WRAP_DMA_CHANNEL(3)
-
- // Uses DMA to automatically store data from a peripheral to a ring buffer.
- template<
- typename Peripheral,
- uint8_t channel_index,
- uint16_t buffer_size>
- class DMARxBuffer {
- private:
- typedef DMAChannel<channel_index> Channel;
- typedef typename Peripheral::Value Value;
-
- public:
- DMARxBuffer() { }
-
- static inline void Init() {
- DMA_CTRL = 0x80;
- uint8_t address_control = 0;
- address_control |= DMA_CH_SRCRELOAD_BURST_gc;
- address_control |= DMA_CH_DESTRELOAD_BLOCK_gc;
- address_control |= DMA_CH_SRCDIR_INC_gc;
- address_control |= DMA_CH_DESTDIR_INC_gc;
-
- Channel::channel().ADDRCTRL = address_control;
- Channel::channel().REPCNT = 0;
- Channel::channel().TRFCNT = buffer_size * sizeof(Value);
-
- uint32_t source = (uint32_t)(Peripheral::dma_data());
- uint32_t destination = (uint32_t)(&buffer_);
- 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 = Peripheral::dma_rx_trigger();
- Channel::channel().CTRLA = DMA_CH_REPEAT_bm | DMA_CH_SINGLE_bm;
- if (sizeof(Value) == 2) {
- Channel::channel().CTRLA |= 0x01;
- } else if (sizeof(Value) == 4) {
- Channel::channel().CTRLA |= 0x02;
- } else if (sizeof(Value) == 8) {
- Channel::channel().CTRLA |= 0x03;
- }
- }
-
- static inline uint8_t readable() {
- uint8_t write_ptr = buffer_size - \
- Channel::channel().TRFCNTL / sizeof(Value);
- return (write_ptr - read_ptr_) & (buffer_size - 1);
- }
-
- static inline Value ImmediateRead() {
- Value result = buffer_[read_ptr_];
- read_ptr_ = (read_ptr_ + 1) & (buffer_size - 1);
- return result;
- }
-
- static inline Value Read() {
- while (!readable());
- return ImmediateRead();
- }
-
- 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 read_ptr_;
- static Value buffer_[buffer_size];
-
- DISALLOW_COPY_AND_ASSIGN(DMARxBuffer);
- };
-
- template<typename P, uint8_t c, uint16_t b> \
- uint8_t DMARxBuffer<P, c, b>::read_ptr_ = 0;
- template<typename P, uint8_t c, uint16_t b> \
- typename P::Value DMARxBuffer<P, c, b>::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_index> 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 c, uint16_t b, typename D, typename T, bool o> \
- uint8_t DMATxBuffer<c, b, D, T, o>::write_ptr_ = 0;
- template<uint8_t c, uint16_t b, typename D, typename T, bool o> \
- typename D::Value DMATxBuffer<c, b, D, T, o>::buffer_[b];
-
- } // namespace avrlibx
-
- #endif // AVRLIBX_IO_DMA_H_
|