/** * Copyright (c) 2011-2018 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /** * @file * @brief Software SPI. * * @defgroup softSPI Software SPI * @details Software SPI Template Class. * @{ */ #ifndef SoftSPI_h #define SoftSPI_h #include "DigitalPin.h" //------------------------------------------------------------------------------ /** Nop for timing. */ #define nop asm volatile ("nop\n\t") //------------------------------------------------------------------------------ /** Pin Mode for MISO is input.*/ #define MISO_MODE INPUT /** Pullups disabled for MISO are disabled. */ #define MISO_LEVEL false /** Pin Mode for MOSI is output.*/ #define MOSI_MODE OUTPUT /** Pin Mode for SCK is output. */ #define SCK_MODE OUTPUT //------------------------------------------------------------------------------ /** * @class SoftSPI * @brief Fast software SPI. */ template class SoftSPI { public: //---------------------------------------------------------------------------- /** Initialize SoftSPI pins. */ void begin() { fastPinConfig(MisoPin, MISO_MODE, MISO_LEVEL); fastPinConfig(MosiPin, MOSI_MODE, !MODE_CPHA(Mode)); fastPinConfig(SckPin, SCK_MODE, MODE_CPOL(Mode)); } //---------------------------------------------------------------------------- /** Soft SPI receive byte. * @return Data byte received. */ inline __attribute__((always_inline)) uint8_t receive() { uint8_t data = 0; receiveBit(7, &data); receiveBit(6, &data); receiveBit(5, &data); receiveBit(4, &data); receiveBit(3, &data); receiveBit(2, &data); receiveBit(1, &data); receiveBit(0, &data); return data; } //---------------------------------------------------------------------------- /** Soft SPI send byte. * @param[in] data Data byte to send. */ inline __attribute__((always_inline)) void send(uint8_t data) { sendBit(7, data); sendBit(6, data); sendBit(5, data); sendBit(4, data); sendBit(3, data); sendBit(2, data); sendBit(1, data); sendBit(0, data); } //---------------------------------------------------------------------------- /** Soft SPI transfer byte. * @param[in] txData Data byte to send. * @return Data byte received. */ inline __attribute__((always_inline)) uint8_t transfer(uint8_t txData) { uint8_t rxData = 0; transferBit(7, &rxData, txData); transferBit(6, &rxData, txData); transferBit(5, &rxData, txData); transferBit(4, &rxData, txData); transferBit(3, &rxData, txData); transferBit(2, &rxData, txData); transferBit(1, &rxData, txData); transferBit(0, &rxData, txData); return rxData; } private: //---------------------------------------------------------------------------- inline __attribute__((always_inline)) bool MODE_CPHA(uint8_t mode) {return (mode & 1) != 0;} inline __attribute__((always_inline)) bool MODE_CPOL(uint8_t mode) {return (mode & 2) != 0;} inline __attribute__((always_inline)) void receiveBit(uint8_t bit, uint8_t* data) { if (MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); } nop; nop; fastDigitalWrite(SckPin, MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); if (fastDigitalRead(MisoPin)) *data |= 1 << bit; if (!MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, MODE_CPOL(Mode)); } } //---------------------------------------------------------------------------- inline __attribute__((always_inline)) void sendBit(uint8_t bit, uint8_t data) { if (MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); } fastDigitalWrite(MosiPin, data & (1 << bit)); fastDigitalWrite(SckPin, MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); nop; nop; if (!MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, MODE_CPOL(Mode)); } } //---------------------------------------------------------------------------- inline __attribute__((always_inline)) void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData) { if (MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); } fastDigitalWrite(MosiPin, txData & (1 << bit)); fastDigitalWrite(SckPin, MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); if (fastDigitalRead(MisoPin)) *rxData |= 1 << bit; if (!MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, MODE_CPOL(Mode)); } } //---------------------------------------------------------------------------- }; #endif // SoftSPI_h /** @} */