Krolyxon
Commit 1d55752

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8Adafruit BusIOAdafruit_SPIDevice.cpp

512 lines · 14.0 KB · C++

1#include "Adafruit_SPIDevice.h"
2
3// #define DEBUG_SERIAL Serial
4
5#ifdef BUSIO_USE_FAST_PINIO
6#define BUSIO_SET_CLOCK_LOW() (*clkPort = *clkPort & ~clkPinMask)
7#define BUSIO_SET_CLOCK_HIGH() (*clkPort = *clkPort | clkPinMask)
8#define BUSIO_READ_MISO() (*misoPort & misoPinMask)
9#define BUSIO_WRITE_MOSI(value) \
10 do { \
11 if (value) \
12 *mosiPort = *mosiPort | mosiPinMask; \
13 else \
14 *mosiPort = *mosiPort & ~mosiPinMask; \
15 } while (0)
16#else
17#define BUSIO_SET_CLOCK_LOW() digitalWrite(_sck, LOW)
18#define BUSIO_SET_CLOCK_HIGH() digitalWrite(_sck, HIGH)
19#define BUSIO_READ_MISO() digitalRead(_miso)
20#define BUSIO_WRITE_MOSI(value) digitalWrite(_mosi, value)
21#endif
22
23/*!
24 * @brief Create an SPI device with the given CS pin and settings
25 * @param cspin The arduino pin number to use for chip select
26 * @param freq The SPI clock frequency to use, defaults to 1MHz
27 * @param dataOrder The SPI data order to use for bits within each byte,
28 * defaults to SPI_BITORDER_MSBFIRST
29 * @param dataMode The SPI mode to use, defaults to SPI_MODE0
30 * @param theSPI The SPI bus to use, defaults to &theSPI
31 */
32Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, uint32_t freq,
33 BusIOBitOrder dataOrder,
34 uint8_t dataMode, SPIClass *theSPI) {
35#ifdef BUSIO_HAS_HW_SPI
36 _cs = cspin;
37 _sck = _mosi = _miso = -1;
38 _spi = theSPI;
39 _begun = false;
40 _spiSetting = new SPISettings(freq, dataOrder, dataMode);
41 _freq = freq;
42 _dataOrder = dataOrder;
43 _dataMode = dataMode;
44#else
45 // unused, but needed to suppress compiler warns
46 (void)cspin;
47 (void)freq;
48 (void)dataOrder;
49 (void)dataMode;
50 (void)theSPI;
51#endif
52}
53
54/*!
55 * @brief Create an SPI device with the given CS pin and settings
56 * @param cspin The arduino pin number to use for chip select
57 * @param sckpin The arduino pin number to use for SCK
58 * @param misopin The arduino pin number to use for MISO, set to -1 if not
59 * used
60 * @param mosipin The arduino pin number to use for MOSI, set to -1 if not
61 * used
62 * @param freq The SPI clock frequency to use, defaults to 1MHz
63 * @param dataOrder The SPI data order to use for bits within each byte,
64 * defaults to SPI_BITORDER_MSBFIRST
65 * @param dataMode The SPI mode to use, defaults to SPI_MODE0
66 */
67Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, int8_t sckpin,
68 int8_t misopin, int8_t mosipin,
69 uint32_t freq, BusIOBitOrder dataOrder,
70 uint8_t dataMode) {
71 _cs = cspin;
72 _sck = sckpin;
73 _miso = misopin;
74 _mosi = mosipin;
75
76#ifdef BUSIO_USE_FAST_PINIO
77 csPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(cspin));
78 csPinMask = digitalPinToBitMask(cspin);
79 if (mosipin != -1) {
80 mosiPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(mosipin));
81 mosiPinMask = digitalPinToBitMask(mosipin);
82 }
83 if (misopin != -1) {
84 misoPort = (BusIO_PortReg *)portInputRegister(digitalPinToPort(misopin));
85 misoPinMask = digitalPinToBitMask(misopin);
86 }
87 clkPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(sckpin));
88 clkPinMask = digitalPinToBitMask(sckpin);
89#endif
90
91 _freq = freq;
92 _dataOrder = dataOrder;
93 _dataMode = dataMode;
94 _begun = false;
95}
96
97/*!
98 * @brief Release memory allocated in constructors
99 */
100Adafruit_SPIDevice::~Adafruit_SPIDevice() {
101 if (_spiSetting)
102 delete _spiSetting;
103}
104
105/*!
106 * @brief Initializes SPI bus and sets CS pin high
107 * @return Always returns true because there's no way to test success of SPI
108 * init
109 */
110bool Adafruit_SPIDevice::begin(void) {
111 if (_cs != -1) {
112 pinMode(_cs, OUTPUT);
113 digitalWrite(_cs, HIGH);
114 }
115
116 if (_spi) { // hardware SPI
117#ifdef BUSIO_HAS_HW_SPI
118 _spi->begin();
119#endif
120 } else {
121 pinMode(_sck, OUTPUT);
122
123 if ((_dataMode == SPI_MODE0) || (_dataMode == SPI_MODE1)) {
124 // idle low on mode 0 and 1
125 digitalWrite(_sck, LOW);
126 } else {
127 // idle high on mode 2 or 3
128 digitalWrite(_sck, HIGH);
129 }
130 if (_mosi != -1) {
131 pinMode(_mosi, OUTPUT);
132 digitalWrite(_mosi, HIGH);
133 }
134 if (_miso != -1) {
135 pinMode(_miso, INPUT);
136 }
137 }
138
139 _begun = true;
140 return true;
141}
142
143/*!
144 * @brief Transfer (send/receive) a buffer over hard/soft SPI, without
145 * transaction management
146 * @param buffer The buffer to send and receive at the same time
147 * @param len The number of bytes to transfer
148 */
149void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) {
150 //
151 // HARDWARE SPI
152 //
153 if (_spi) {
154#ifdef BUSIO_HAS_HW_SPI
155#if defined(SPARK)
156 _spi->transfer(buffer, buffer, len, nullptr);
157#elif defined(STM32)
158 for (size_t i = 0; i < len; i++) {
159 _spi->transfer(buffer[i]);
160 }
161#else
162 _spi->transfer(buffer, len);
163#endif
164 return;
165#endif
166 }
167
168 //
169 // SOFTWARE SPI
170 //
171 uint8_t startbit;
172 if (_dataOrder == SPI_BITORDER_LSBFIRST) {
173 startbit = 0x1;
174 } else {
175 startbit = 0x80;
176 }
177
178 bool towrite, lastmosi = !(buffer[0] & startbit);
179 uint8_t bitdelay_us = (1000000 / _freq) / 2;
180
181 for (size_t i = 0; i < len; i++) {
182 uint8_t reply = 0;
183 uint8_t send = buffer[i];
184
185 /*
186 Serial.print("\tSending software SPI byte 0x");
187 Serial.print(send, HEX);
188 Serial.print(" -> 0x");
189 */
190
191 // Serial.print(send, HEX);
192 for (uint8_t b = startbit; b != 0;
193 b = (_dataOrder == SPI_BITORDER_LSBFIRST) ? b << 1 : b >> 1) {
194
195 if (bitdelay_us) {
196 delayMicroseconds(bitdelay_us);
197 }
198
199 if (_dataMode == SPI_MODE0 || _dataMode == SPI_MODE2) {
200 towrite = send & b;
201 if ((_mosi != -1) && (lastmosi != towrite)) {
202 BUSIO_WRITE_MOSI(towrite);
203 lastmosi = towrite;
204 }
205
206 BUSIO_SET_CLOCK_HIGH();
207
208 if (bitdelay_us) {
209 delayMicroseconds(bitdelay_us);
210 }
211
212 if (_miso != -1) {
213 if (BUSIO_READ_MISO())
214 reply |= b;
215 }
216
217 BUSIO_SET_CLOCK_LOW();
218
219 } else if (_dataMode == SPI_MODE3) {
220
221 if (_mosi != -1) { // transmit on falling edge
222 BUSIO_WRITE_MOSI(send & b);
223 }
224
225 BUSIO_SET_CLOCK_LOW();
226
227 if (bitdelay_us) {
228 delayMicroseconds(bitdelay_us);
229 }
230
231 BUSIO_SET_CLOCK_HIGH();
232
233 if (bitdelay_us) {
234 delayMicroseconds(bitdelay_us);
235 }
236
237 if (_miso != -1) { // read on rising edge
238 if (BUSIO_READ_MISO()) {
239 reply |= b;
240 }
241 }
242
243 } else { // || _dataMode == SPI_MODE1)
244
245 BUSIO_SET_CLOCK_HIGH();
246
247 if (bitdelay_us) {
248 delayMicroseconds(bitdelay_us);
249 }
250
251 if (_mosi != -1) {
252 BUSIO_WRITE_MOSI(send & b);
253 }
254
255 BUSIO_SET_CLOCK_LOW();
256
257 if (_miso != -1) {
258 if (BUSIO_READ_MISO()) {
259 reply |= b;
260 }
261 }
262 }
263 }
264 if (_miso != -1) {
265 buffer[i] = reply;
266 }
267 }
268 return;
269}
270
271/*!
272 * @brief Transfer (send/receive) one byte over hard/soft SPI, without
273 * transaction management
274 * @param send The byte to send
275 * @return The byte received while transmitting
276 */
277uint8_t Adafruit_SPIDevice::transfer(uint8_t send) {
278 uint8_t data = send;
279 transfer(&data, 1);
280 return data;
281}
282
283/*!
284 * @brief Manually begin a transaction (calls beginTransaction if hardware
285 * SPI)
286 */
287void Adafruit_SPIDevice::beginTransaction(void) {
288 if (_spi) {
289#ifdef BUSIO_HAS_HW_SPI
290 _spi->beginTransaction(*_spiSetting);
291#endif
292 }
293}
294
295/*!
296 * @brief Manually end a transaction (calls endTransaction if hardware SPI)
297 */
298void Adafruit_SPIDevice::endTransaction(void) {
299 if (_spi) {
300#ifdef BUSIO_HAS_HW_SPI
301 _spi->endTransaction();
302#endif
303 }
304}
305
306/*!
307 * @brief Assert/Deassert the CS pin if it is defined
308 * @param value The state the CS is set to
309 */
310void Adafruit_SPIDevice::setChipSelect(int value) {
311 if (_cs != -1) {
312 digitalWrite(_cs, value);
313 }
314}
315
316/*!
317 * @brief Write a buffer or two to the SPI device, with transaction
318 * management.
319 * @brief Manually begin a transaction (calls beginTransaction if hardware
320 * SPI) with asserting the CS pin
321 */
322void Adafruit_SPIDevice::beginTransactionWithAssertingCS() {
323 beginTransaction();
324 setChipSelect(LOW);
325}
326
327/*!
328 * @brief Manually end a transaction (calls endTransaction if hardware SPI)
329 * with deasserting the CS pin
330 */
331void Adafruit_SPIDevice::endTransactionWithDeassertingCS() {
332 setChipSelect(HIGH);
333 endTransaction();
334}
335
336/*!
337 * @brief Write a buffer or two to the SPI device, with transaction
338 * management.
339 * @param buffer Pointer to buffer of data to write
340 * @param len Number of bytes from buffer to write
341 * @param prefix_buffer Pointer to optional array of data to write before
342 * buffer.
343 * @param prefix_len Number of bytes from prefix buffer to write
344 * @return Always returns true because there's no way to test success of SPI
345 * writes
346 */
347bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len,
348 const uint8_t *prefix_buffer,
349 size_t prefix_len) {
350 beginTransactionWithAssertingCS();
351
352 // do the writing
353#if defined(ARDUINO_ARCH_ESP32)
354 if (_spi) {
355 if (prefix_len > 0) {
356 _spi->transferBytes((uint8_t *)prefix_buffer, nullptr, prefix_len);
357 }
358 if (len > 0) {
359 _spi->transferBytes((uint8_t *)buffer, nullptr, len);
360 }
361 } else
362#endif
363 {
364 for (size_t i = 0; i < prefix_len; i++) {
365 transfer(prefix_buffer[i]);
366 }
367 for (size_t i = 0; i < len; i++) {
368 transfer(buffer[i]);
369 }
370 }
371 endTransactionWithDeassertingCS();
372
373#ifdef DEBUG_SERIAL
374 DEBUG_SERIAL.print(F("\tSPIDevice Wrote: "));
375 if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
376 for (uint16_t i = 0; i < prefix_len; i++) {
377 DEBUG_SERIAL.print(F("0x"));
378 DEBUG_SERIAL.print(prefix_buffer[i], HEX);
379 DEBUG_SERIAL.print(F(", "));
380 }
381 }
382 for (uint16_t i = 0; i < len; i++) {
383 DEBUG_SERIAL.print(F("0x"));
384 DEBUG_SERIAL.print(buffer[i], HEX);
385 DEBUG_SERIAL.print(F(", "));
386 if (i % 32 == 31) {
387 DEBUG_SERIAL.println();
388 }
389 }
390 DEBUG_SERIAL.println();
391#endif
392
393 return true;
394}
395
396/*!
397 * @brief Read from SPI into a buffer from the SPI device, with transaction
398 * management.
399 * @param buffer Pointer to buffer of data to read into
400 * @param len Number of bytes from buffer to read.
401 * @param sendvalue The 8-bits of data to write when doing the data read,
402 * defaults to 0xFF
403 * @return Always returns true because there's no way to test success of SPI
404 * writes
405 */
406bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) {
407 memset(buffer, sendvalue, len); // clear out existing buffer
408
409 beginTransactionWithAssertingCS();
410 transfer(buffer, len);
411 endTransactionWithDeassertingCS();
412
413#ifdef DEBUG_SERIAL
414 DEBUG_SERIAL.print(F("\tSPIDevice Read: "));
415 for (uint16_t i = 0; i < len; i++) {
416 DEBUG_SERIAL.print(F("0x"));
417 DEBUG_SERIAL.print(buffer[i], HEX);
418 DEBUG_SERIAL.print(F(", "));
419 if (len % 32 == 31) {
420 DEBUG_SERIAL.println();
421 }
422 }
423 DEBUG_SERIAL.println();
424#endif
425
426 return true;
427}
428
429/*!
430 * @brief Write some data, then read some data from SPI into another buffer,
431 * with transaction management. The buffers can point to same/overlapping
432 * locations. This does not transmit-receive at the same time!
433 * @param write_buffer Pointer to buffer of data to write from
434 * @param write_len Number of bytes from buffer to write.
435 * @param read_buffer Pointer to buffer of data to read into.
436 * @param read_len Number of bytes from buffer to read.
437 * @param sendvalue The 8-bits of data to write when doing the data read,
438 * defaults to 0xFF
439 * @return Always returns true because there's no way to test success of SPI
440 * writes
441 */
442bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer,
443 size_t write_len, uint8_t *read_buffer,
444 size_t read_len, uint8_t sendvalue) {
445 beginTransactionWithAssertingCS();
446 // do the writing
447#if defined(ARDUINO_ARCH_ESP32)
448 if (_spi) {
449 if (write_len > 0) {
450 _spi->transferBytes((uint8_t *)write_buffer, nullptr, write_len);
451 }
452 } else
453#endif
454 {
455 for (size_t i = 0; i < write_len; i++) {
456 transfer(write_buffer[i]);
457 }
458 }
459
460#ifdef DEBUG_SERIAL
461 DEBUG_SERIAL.print(F("\tSPIDevice Wrote: "));
462 for (uint16_t i = 0; i < write_len; i++) {
463 DEBUG_SERIAL.print(F("0x"));
464 DEBUG_SERIAL.print(write_buffer[i], HEX);
465 DEBUG_SERIAL.print(F(", "));
466 if (write_len % 32 == 31) {
467 DEBUG_SERIAL.println();
468 }
469 }
470 DEBUG_SERIAL.println();
471#endif
472
473 // do the reading
474 for (size_t i = 0; i < read_len; i++) {
475 read_buffer[i] = transfer(sendvalue);
476 }
477
478#ifdef DEBUG_SERIAL
479 DEBUG_SERIAL.print(F("\tSPIDevice Read: "));
480 for (uint16_t i = 0; i < read_len; i++) {
481 DEBUG_SERIAL.print(F("0x"));
482 DEBUG_SERIAL.print(read_buffer[i], HEX);
483 DEBUG_SERIAL.print(F(", "));
484 if (read_len % 32 == 31) {
485 DEBUG_SERIAL.println();
486 }
487 }
488 DEBUG_SERIAL.println();
489#endif
490
491 endTransactionWithDeassertingCS();
492
493 return true;
494}
495
496/*!
497 * @brief Write some data and read some data at the same time from SPI
498 * into the same buffer, with transaction management. This is basicaly a wrapper
499 * for transfer() with CS-pin and transaction management. This /does/
500 * transmit-receive at the same time!
501 * @param buffer Pointer to buffer of data to write/read to/from
502 * @param len Number of bytes from buffer to write/read.
503 * @return Always returns true because there's no way to test success of SPI
504 * writes
505 */
506bool Adafruit_SPIDevice::write_and_read(uint8_t *buffer, size_t len) {
507 beginTransactionWithAssertingCS();
508 transfer(buffer, len);
509 endTransactionWithDeassertingCS();
510
511 return true;
512}