RF22

- Main Page
- Classes
- Files
- Examples

- File List

SoftwareSPI.h
1 // SoftwareSPI.h
2 // Author: Chris Lapa (chris@lapa.com.au)
3 // Copyright (C) 2014 Chris Lapa
4
5 #ifndef SOFTWARESPI_H
6 #define SOFTWARESPI_H
7
8 #include "GenericSPI.h"
9
10 // These defs cause trouble on some versions of Arduino
11 #undef round
12 #undef double
13
14 #include <SPI.h>
15
16
17 /////////////////////////////////////////////////////////////////////
18 /// \class SoftwareSPIClass SoftwareSPI.h <SoftwareSPI.h>
19 /// \brief Encapsulate a software SPI interface
20 ///
21 /// This concrete subclass of GenericSPIClass enapsulates the SPI interface
22 class SoftwareSPIClass : public GenericSPIClass
23 {
24
25 public:
26
27 /// Transfer a single octet to and from the SPI interface
28 /// \param[in] data The octet to send
29 /// \return The octet read from SPI while the data octet was sent
30 uint8_t transfer(uint8_t data)
31 {
32 uint8_t readData;
33 uint8_t writeData;
34 uint8_t builtReturn;
35 uint8_t mask;
36
37 if (_bitOrder == MSBFIRST)
38 {
39 mask = 0x80;
40 }
41 else
42 {
43 mask = 0x01;
44 }
45 builtReturn = 0;
46 readData = 0;
47
48 for (uint8_t count=0; count<8; count++)
49 {
50 if (data & mask)
51 {
52 writeData = HIGH;
53 }
54 else
55 {
56 writeData = LOW;
57 }
58
59
60 if (_clockPhase == 1)
61 {
62 // CPHA=1, miso/mosi changing state now
63 digitalWrite(_mosi, writeData);
64 digitalWrite(_sck, ~_clockPolarity);
65 delayPeriod();
66
67 // CPHA=1, miso/mosi stable now
68 readData = digitalRead(_miso);
69 digitalWrite(_sck, _clockPolarity);
70 delayPeriod();
71 }
72 else
73 {
74 // CPHA=0, miso/mosi changing state now
75 digitalWrite(_mosi, writeData);
76 digitalWrite(_sck, _clockPolarity);
77 delayPeriod();
78
79 // CPHA=0, miso/mosi stable now
80 readData = digitalRead(_miso);
81 digitalWrite(_sck, ~_clockPolarity);
82 delayPeriod();
83 }
84
85
86 if (_bitOrder == MSBFIRST)
87 {
88 mask >>= 1;
89 builtReturn |= (readData << (7 - count));
90 }
91 else
92 {
93 mask <<= 1;
94 builtReturn |= (readData << count);
95 }
96 }
97
98 digitalWrite(_sck, _clockPolarity);
99
100 return builtReturn;
101 }
102
103 /// Not implemented.
104 void attachInterrupt() { }
105
106 /// Not implemented.
107 void detachInterrupt() { }
108
109 /// Initialise the SPI library
110 void begin()
111 {
112 _clockPolarity = LOW;
113 _clockPhase = 0;
114 _bitOrder = MSBFIRST;
115 _delayCounts = SPI_CLOCK_DIV4;
116 }
117
118 /// Disables the SPI bus usually, in this case
119 /// there is no hardware controller to disable.
120 void end() { }
121
122 /// Sets the pins used by this SoftwareSPIClass instance.
123 /// \param[in] miso master in slave out pin used
124 /// \param[in] mosi master out slave in pin used
125 /// \param[in] sck clock pin used
126 void setPins(uint8_t miso, uint8_t mosi, uint8_t sck)
127 {
128 _miso = miso;
129 _mosi = mosi;
130 _sck = sck;
131
132 pinMode(_miso, INPUT);
133 pinMode(_mosi, OUTPUT);
134 pinMode(_sck, OUTPUT);
135 digitalWrite(_sck, _clockPolarity);
136 }
137
138 /// Sets the bit order the SPI interface will use
139 /// Sets the order of the bits shifted out of and into the SPI bus, either
140 /// LSBFIRST (least-significant bit first) or MSBFIRST (most-significant bit first).
141 /// \param[in] bitOrder Bit order to be used: LSBFIRST or MSBFIRST
142 void setBitOrder(uint8_t bitOrder)
143 {
144 _bitOrder = bitOrder;
145 }
146
147 /// Sets the SPI data mode: that is, clock polarity and phase.
148 /// See the Wikipedia article on SPI for details.
149 /// \param[in] mode The mode to use: SPI_MODE0 SPI_MODE1 SPI_MODE2 SPI_MODE3
150 void setDataMode(uint8_t mode)
151 {
152 if (mode == SPI_MODE0 ||
153 mode == SPI_MODE1)
154 {
155 _clockPolarity = LOW;
156 }
157 else
158 {
159 _clockPhase = HIGH;
160 }
161
162 if (mode == SPI_MODE0 ||
163 mode == SPI_MODE2)
164 {
165 _clockPhase = 0;
166 }
167 else
168 {
169 _clockPhase = 1;
170 }
171
172 digitalWrite(_sck, _clockPolarity);
173 }
174
175 /// Sets the SPI clock divider relative to the system clock.
176 /// In this case, the software SPI does a basic delay in a loop for whatever
177 /// rate is set too.
178 /// The default setting is SPI_CLOCK_DIV4,
179 /// \param[in] rate The data rate to use: one of SPI_CLOCK_
180 void setClockDivider(uint8_t rate)
181 {
182 _delayCounts = rate;
183 }
184
185 private:
186
187 /// Delay routine for bus timing.
188 void delayPeriod()
189 {
190 for (volatile uint8_t count; count<_delayCounts; count++)
191 {
192 __asm__ __volatile__ ("nop");
193 }
194 }
195
196
197 private:
198 uint8_t _miso;
199 uint8_t _mosi;
200 uint8_t _sck;
201 uint8_t _bitOrder;
202 uint8_t _delayCounts;
203 uint8_t _clockPolarity;
204 uint8_t _clockPhase;
205 };
206
207 #endif
SoftwareSPIClass::setDataMode
void setDataMode(uint8_t mode)
Definition: SoftwareSPI.h:150
SoftwareSPIClass::setPins
void setPins(uint8_t miso, uint8_t mosi, uint8_t sck)
Definition: SoftwareSPI.h:126
SoftwareSPIClass::begin
void begin()
Initialise the SPI library.
Definition: SoftwareSPI.h:110
SoftwareSPIClass::setClockDivider
void setClockDivider(uint8_t rate)
Definition: SoftwareSPI.h:180
SoftwareSPIClass
Encapsulate a software SPI interface.
Definition: SoftwareSPI.h:22
SoftwareSPIClass::transfer
uint8_t transfer(uint8_t data)
Definition: SoftwareSPI.h:30
SoftwareSPIClass::detachInterrupt
void detachInterrupt()
Not implemented.
Definition: SoftwareSPI.h:107
SoftwareSPIClass::setBitOrder
void setBitOrder(uint8_t bitOrder)
Definition: SoftwareSPI.h:142
GenericSPIClass
Base class for SPI interfaces.
Definition: GenericSPI.h:28
SoftwareSPIClass::end
void end()
there is no hardware controller to disable.
Definition: SoftwareSPI.h:120
SoftwareSPIClass::attachInterrupt
void attachInterrupt()
Not implemented.
Definition: SoftwareSPI.h:104