|
- // SoftwareSPI.cpp
- // Author: Chris Lapa (chris@lapa.com.au)
- // Copyright (C) 2014 Chris Lapa
- // Contributed by Chris Lapa
-
- #include <RHSoftwareSPI.h>
-
- RHSoftwareSPI::RHSoftwareSPI(Frequency frequency, BitOrder bitOrder, DataMode dataMode)
- :
- RHGenericSPI(frequency, bitOrder, dataMode)
- {
- setPins(12, 11, 13);
- }
-
- // Caution: on Arduino Uno and many other CPUs, digitalWrite is quite slow, taking about 4us
- // digitalWrite is also slow, taking about 3.5us
- // resulting in very slow SPI bus speeds using this technique, up to about 120us per octet of transfer
- uint8_t RHSoftwareSPI::transfer(uint8_t data)
- {
- uint8_t readData;
- uint8_t writeData;
- uint8_t builtReturn;
- uint8_t mask;
-
- if (_bitOrder == BitOrderMSBFirst)
- {
- mask = 0x80;
- }
- else
- {
- mask = 0x01;
- }
- builtReturn = 0;
- readData = 0;
-
- for (uint8_t count=0; count<8; count++)
- {
- if (data & mask)
- {
- writeData = HIGH;
- }
- else
- {
- writeData = LOW;
- }
-
- if (_clockPhase == 1)
- {
- // CPHA=1, miso/mosi changing state now
- digitalWrite(_mosi, writeData);
- digitalWrite(_sck, ~_clockPolarity);
- delayPeriod();
-
- // CPHA=1, miso/mosi stable now
- readData = digitalRead(_miso);
- digitalWrite(_sck, _clockPolarity);
- delayPeriod();
- }
- else
- {
- // CPHA=0, miso/mosi changing state now
- digitalWrite(_mosi, writeData);
- digitalWrite(_sck, _clockPolarity);
- delayPeriod();
-
- // CPHA=0, miso/mosi stable now
- readData = digitalRead(_miso);
- digitalWrite(_sck, ~_clockPolarity);
- delayPeriod();
- }
-
- if (_bitOrder == BitOrderMSBFirst)
- {
- mask >>= 1;
- builtReturn |= (readData << (7 - count));
- }
- else
- {
- mask <<= 1;
- builtReturn |= (readData << count);
- }
- }
-
- digitalWrite(_sck, _clockPolarity);
-
- return builtReturn;
- }
-
- /// Initialise the SPI library
- void RHSoftwareSPI::begin()
- {
- if (_dataMode == DataMode0 ||
- _dataMode == DataMode1)
- {
- _clockPolarity = LOW;
- }
- else
- {
- _clockPolarity = HIGH;
- }
-
- if (_dataMode == DataMode0 ||
- _dataMode == DataMode2)
- {
- _clockPhase = 0;
- }
- else
- {
- _clockPhase = 1;
- }
- digitalWrite(_sck, _clockPolarity);
-
- // Caution: these counts assume that digitalWrite is very fast, which is usually not true
- switch (_frequency)
- {
- case Frequency1MHz:
- _delayCounts = 8;
- break;
-
- case Frequency2MHz:
- _delayCounts = 4;
- break;
-
- case Frequency4MHz:
- _delayCounts = 2;
- break;
-
- case Frequency8MHz:
- _delayCounts = 1;
- break;
-
- case Frequency16MHz:
- _delayCounts = 0;
- break;
- }
- }
-
- /// Disables the SPI bus usually, in this case
- /// there is no hardware controller to disable.
- void RHSoftwareSPI::end() { }
-
- /// Sets the pins used by this SoftwareSPIClass instance.
- /// \param[in] miso master in slave out pin used
- /// \param[in] mosi master out slave in pin used
- /// \param[in] sck clock pin used
- void RHSoftwareSPI::setPins(uint8_t miso, uint8_t mosi, uint8_t sck)
- {
- _miso = miso;
- _mosi = mosi;
- _sck = sck;
-
- pinMode(_miso, INPUT);
- pinMode(_mosi, OUTPUT);
- pinMode(_sck, OUTPUT);
- digitalWrite(_sck, _clockPolarity);
- }
-
-
- void RHSoftwareSPI::delayPeriod()
- {
- for (uint8_t count = 0; count < _delayCounts; count++)
- {
- __asm__ __volatile__ ("nop");
- }
- }
|