| 
							- // Copyright 2009 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/>.
 - //
 - // -----------------------------------------------------------------------------
 - //
 - // Fast SPI communication (using the hardware implementation). This will take
 - // ownership of the pins 11 (data output),  12 (data input) and 13 (clock), +
 - // a user-definable pin for slave selection. Pin 10 should be kept as an output
 - // pin, since the SPI master/slave mode is based upon the value of this pin.
 - 
 - #ifndef AVRLIB_SPI_H_
 - #define AVRLIB_SPI_H_
 - 
 - #include "avrlib/avrlib.h"
 - #include "avrlib/gpio.h"
 - #include "avrlib/serial.h"
 - 
 - namespace avrlib {
 - 
 - IORegister(SPSR);
 - typedef BitInRegister<SPSRRegister, SPI2X> DoubleSpeed;
 - typedef BitInRegister<SPSRRegister, SPIF> TransferComplete;
 - 
 - template<typename SlaveSelect,
 -          DataOrder order = MSB_FIRST,
 -          uint8_t speed = 4>
 - class SpiMaster {
 -  public:
 -   enum {
 -     buffer_size = 0,
 -     data_size = 8
 -   };
 - 
 -   static void Init() {
 -     SpiSCK::set_mode(DIGITAL_OUTPUT);
 -     SpiMOSI::set_mode(DIGITAL_OUTPUT);
 -     SpiMISO::set_mode(DIGITAL_INPUT);
 -     SpiSS::set_mode(DIGITAL_OUTPUT);  // I'm a master!
 -     SpiSS::High();
 -     SlaveSelect::set_mode(DIGITAL_OUTPUT);
 -     SlaveSelect::High();
 - 
 -     // SPI enabled, configured as master.
 -     uint8_t configuration = _BV(SPE) | _BV(MSTR);
 -     if (order == LSB_FIRST) {
 -       configuration |= _BV(DORD);
 -     }
 -     DoubleSpeed::clear();
 -     switch (speed) {
 -       case 2:
 -         DoubleSpeed::set();
 -       case 4:
 -         break;
 -       case 8:
 -         DoubleSpeed::set();
 -       case 16:
 -         configuration |= _BV(SPR0);
 -         break;
 -       case 32:
 -         DoubleSpeed::set();
 -       case 64:
 -         configuration |= _BV(SPR1);
 -         break;
 -       case 128:
 -         configuration |= _BV(SPR0);
 -         configuration |= _BV(SPR1);
 -         break;
 -     }
 -     SPCR = configuration;
 -   }
 -   
 -   static inline void PullUpMISO() {
 -     SpiMISO::High();
 -   }
 -   
 -   static inline void Begin() {
 -     SlaveSelect::Low();
 -   }
 - 
 -   static inline void End() {
 -     SlaveSelect::High();
 -   }
 -   
 -   static inline void Strobe() {
 -     SlaveSelect::High();
 -     SlaveSelect::Low();
 -   }
 - 
 -   static inline void Write(uint8_t v) {
 -     Begin();
 -     Send(v);
 -     End();
 -   }
 -   
 -   static inline uint8_t Read() {
 -     Begin();
 -     uint8_t result = Receive();
 -     End();
 -     return result;
 -   }
 -   
 -   static inline void Send(uint8_t v) {
 -     Overwrite(v);
 -     Wait();
 -   }
 -   
 -   static inline uint8_t Receive() {
 -     Send(0xff);
 -     return ImmediateRead();
 -   }
 -   
 -   static inline uint8_t ImmediateRead() {
 -     return SPDR;
 -   }
 -   
 -   static inline void Wait() {
 -     while (!TransferComplete::value());
 -   }
 -   
 -   static inline void OptimisticWait() {
 -     Wait();
 -   }
 -   
 -   static inline void Overwrite(uint8_t v) {
 -     SPDR = v;
 -   }
 - 
 -   static inline void WriteWord(uint8_t a, uint8_t b) {
 -     Begin();
 -     Send(a);
 -     Send(b);
 -     End();
 -   }
 - };
 - 
 - template<DataOrder order = MSB_FIRST,
 -          bool enable_interrupt = false>
 - class SpiSlave {
 -  public:
 -   enum {
 -     buffer_size = 128,
 -     data_size = 8
 -   };
 - 
 -   static void Init() {
 -     SpiSCK::set_mode(DIGITAL_INPUT);
 -     SpiMOSI::set_mode(DIGITAL_INPUT);
 -     SpiMISO::set_mode(DIGITAL_OUTPUT);
 -     SpiSS::set_mode(DIGITAL_INPUT);  // Ohhh mistress, ohhhh!
 - 
 -     // SPI enabled, configured as master.
 -     uint8_t configuration = _BV(SPE);
 -     if (order == LSB_FIRST) {
 -       configuration |= _BV(DORD);
 -     }
 -     if (enable_interrupt) {
 -       configuration |= _BV(SPIE);
 -     }
 -     SPCR = configuration;
 -   }
 -   
 -   static inline void Reply(uint8_t value) {
 -     SPDR = value;
 -   }
 -   
 -   static inline uint8_t readable() {
 -     return TransferComplete::value();
 -   }
 -   
 -   static inline uint8_t ImmediateRead() {
 -     return SPDR;
 -   }
 -   
 -   static inline uint8_t Read() {
 -     while (!readable());
 -     return ImmediateRead();
 -   }
 - };
 - 
 - template<typename XckPort,
 -          typename TxPort,
 -          typename RxPort,
 -          typename PrescalerRegister,
 -          typename ControlRegisterB,
 -          uint8_t BFlags,
 -          typename ControlRegisterC,
 -          uint8_t CFlags,
 -          typename TxReadyBit,
 -          typename DataRegister>
 - struct UartSpiPort {
 -   static inline uint8_t tx_ready() { return TxReadyBit::value(); }
 -   static inline uint8_t data() { return *DataRegister::ptr(); }
 -   static inline void set_data(uint8_t value) { *DataRegister::ptr() = value; }
 -   static inline void Setup(uint16_t rate) {
 -     *PrescalerRegister::ptr() = 0;
 -     XckPort::set_mode(DIGITAL_OUTPUT);
 -     TxPort::set_mode(DIGITAL_OUTPUT);
 -     RxPort::set_mode(DIGITAL_INPUT);
 -     *ControlRegisterC::ptr() = CFlags;
 -     *ControlRegisterB::ptr() = BFlags;
 -     *PrescalerRegister::ptr() = rate;
 -   }
 - };
 - 
 - #ifdef HAS_USART0
 - 
 - typedef UartSpiPort<
 -     UartSpi0XCK,
 -     UartSpi0TX,
 -     UartSpi0RX,
 -     UBRR0Register,
 -     UCSR0BRegister,
 -     _BV(RXEN0) | _BV(TXEN0),
 -     UCSR0CRegister,
 -     _BV(UMSEL01) | _BV(UMSEL00),
 -     BitInRegister<UCSR0ARegister, UDRE0>,
 -     UDR0Register> UartSpiPort0;
 - 
 - #endif  // HAS_USART0
 - 
 - #ifdef HAS_USART1
 - 
 - typedef UartSpiPort<
 -     UartSpi1XCK,
 -     UartSpi1TX,
 -     UartSpi1RX,
 -     UBRR1Register,
 -     UCSR1BRegister,
 -     _BV(RXEN1) | _BV(TXEN1),
 -     UCSR1CRegister,
 -     _BV(UMSEL11) | _BV(UMSEL10),
 -     BitInRegister<UCSR1ARegister, UDRE1>,
 -     UDR1Register> UartSpiPort1;
 - 
 - #endif  // HAS_USART1
 - 
 - template<typename Port, typename SlaveSelect, uint8_t speed = 2>
 - class UartSpiMaster {
 -  public:
 -   enum {
 -     buffer_size = 0,
 -     data_size = 8
 -   };
 - 
 -   static void Init() {
 -     SlaveSelect::set_mode(DIGITAL_OUTPUT);
 -     SlaveSelect::High();
 -     Port::Setup((speed / 2) - 1);
 -   }
 - 
 -   static inline void Begin() {
 -     SlaveSelect::Low();
 -   }
 - 
 -   static inline void End() {
 -     SlaveSelect::High();
 -   }
 -   
 -   static inline void Strobe() {
 -     SlaveSelect::High();
 -     SlaveSelect::Low();
 -   }
 - 
 -   static inline void Write(uint8_t v) {
 -     Begin();
 -     Send(v);
 -     End();
 -   }
 -   
 -   static inline void Send(uint8_t v) {
 -     Overwrite(v);
 -     Wait();
 -   }
 - 
 -   static inline void Wait() {
 -     while (!Port::tx_ready());
 -   }
 -   
 -   static inline void OptimisticWait() { }
 -   
 -   static inline void Overwrite(uint8_t v) {
 -     Port::set_data(v);
 -   }
 -   
 -   static inline void WriteWord(uint8_t a, uint8_t b) {
 -     Begin();
 -     Send(a);
 -     Send(b);
 -     End();
 -   }
 - };
 - 
 - #define SPI_RECEIVE ISR(SPI_STC_vect)
 - 
 - }  // namespace avrlib
 - 
 - #endif AVRLIB_SPI_H_
 
 
  |