Adafruit Bus IO Library
Adafruit_SPIDevice.h
1 #ifndef Adafruit_SPIDevice_h
2 #define Adafruit_SPIDevice_h
3 
4 #include <Arduino.h>
5 
6 #if !defined(SPI_INTERFACES_COUNT) || \
7  (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0))
8 // HW SPI available
9 #include <SPI.h>
10 #define BUSIO_HAS_HW_SPI
11 #else
12 // SW SPI ONLY
13 enum { SPI_MODE0, SPI_MODE1, SPI_MODE2, _SPI_MODE4 };
14 typedef uint8_t SPIClass;
15 #endif
16 
17 // some modern SPI definitions don't have BitOrder enum
18 #if (defined(__AVR__) && !defined(ARDUINO_ARCH_MEGAAVR)) || \
19  defined(ESP8266) || defined(TEENSYDUINO) || defined(SPARK) || \
20  defined(ARDUINO_ARCH_SPRESENSE) || defined(MEGATINYCORE) || \
21  defined(DXCORE) || defined(ARDUINO_AVR_ATmega4809) || \
22  defined(ARDUINO_AVR_ATmega4808) || defined(ARDUINO_AVR_ATmega3209) || \
23  defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || \
24  defined(ARDUINO_AVR_ATmega1608) || defined(ARDUINO_AVR_ATmega809) || \
25  defined(ARDUINO_AVR_ATmega808) || defined(ARDUINO_ARCH_ARC32) || \
26  defined(ARDUINO_ARCH_XMC)
27 
28 typedef enum _BitOrder {
29  SPI_BITORDER_MSBFIRST = MSBFIRST,
30  SPI_BITORDER_LSBFIRST = LSBFIRST,
31 } BusIOBitOrder;
32 
33 #elif defined(ESP32) || defined(__ASR6501__) || defined(__ASR6502__)
34 
35 // some modern SPI definitions don't have BitOrder enum and have different SPI
36 // mode defines
37 typedef enum _BitOrder {
38  SPI_BITORDER_MSBFIRST = SPI_MSBFIRST,
39  SPI_BITORDER_LSBFIRST = SPI_LSBFIRST,
40 } BusIOBitOrder;
41 
42 #else
43 // Some platforms have a BitOrder enum but its named MSBFIRST/LSBFIRST
44 #define SPI_BITORDER_MSBFIRST MSBFIRST
45 #define SPI_BITORDER_LSBFIRST LSBFIRST
46 typedef BitOrder BusIOBitOrder;
47 #endif
48 
49 #if defined(__IMXRT1062__) // Teensy 4.x
50 // *Warning* I disabled the usage of FAST_PINIO as the set/clear operations
51 // used in the cpp file are not atomic and can effect multiple IO pins
52 // and if an interrupt happens in between the time the code reads the register
53 // and writes out the updated value, that changes one or more other IO pins
54 // on that same IO port, those change will be clobbered when the updated
55 // values are written back. A fast version can be implemented that uses the
56 // ports set and clear registers which are atomic.
57 // typedef volatile uint32_t BusIO_PortReg;
58 // typedef uint32_t BusIO_PortMask;
59 // #define BUSIO_USE_FAST_PINIO
60 
61 #elif defined(__MBED__) || defined(__ZEPHYR__)
62 // Boards based on RTOS cores like mbed or Zephyr are not going to expose the
63 // low level registers needed for fast pin manipulation
64 #undef BUSIO_USE_FAST_PINIO
65 
66 #elif defined(ARDUINO_ARCH_XMC)
67 #undef BUSIO_USE_FAST_PINIO
68 
69 #elif defined(__AVR__) || defined(TEENSYDUINO)
70 typedef volatile uint8_t BusIO_PortReg;
71 typedef uint8_t BusIO_PortMask;
72 #define BUSIO_USE_FAST_PINIO
73 
74 #elif defined(ESP8266) || defined(ESP32) || defined(__SAM3X8E__) || \
75  defined(ARDUINO_ARCH_SAMD)
76 typedef volatile uint32_t BusIO_PortReg;
77 typedef uint32_t BusIO_PortMask;
78 #define BUSIO_USE_FAST_PINIO
79 
80 #elif (defined(__arm__) || defined(ARDUINO_FEATHER52)) && \
81  !defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_SILABS) && \
82  !defined(ARDUINO_UNOR4_MINIMA) && !defined(ARDUINO_UNOR4_WIFI) && \
83  !defined(PORTDUINO)
84 typedef volatile uint32_t BusIO_PortReg;
85 typedef uint32_t BusIO_PortMask;
86 #if !defined(__ASR6501__) && !defined(__ASR6502__)
87 #define BUSIO_USE_FAST_PINIO
88 #endif
89 
90 #else
91 #undef BUSIO_USE_FAST_PINIO
92 #endif
93 
96 public:
97 #ifdef BUSIO_HAS_HW_SPI
98  Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000,
99  BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
100  uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = &SPI);
101 #else
102  Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000,
103  BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
104  uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = nullptr);
105 #endif
106  Adafruit_SPIDevice(int8_t cspin, int8_t sck, int8_t miso, int8_t mosi,
107  uint32_t freq = 1000000,
108  BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST,
109  uint8_t dataMode = SPI_MODE0);
111 
112  bool begin(void);
113  bool read(uint8_t *buffer, size_t len, uint8_t sendvalue = 0xFF);
114  bool write(const uint8_t *buffer, size_t len,
115  const uint8_t *prefix_buffer = nullptr, size_t prefix_len = 0);
116  bool write_then_read(const uint8_t *write_buffer, size_t write_len,
117  uint8_t *read_buffer, size_t read_len,
118  uint8_t sendvalue = 0xFF);
119  bool write_and_read(uint8_t *buffer, size_t len);
120 
121  uint8_t transfer(uint8_t send);
122  void transfer(uint8_t *buffer, size_t len);
123  void beginTransaction(void);
124  void endTransaction(void);
127 
128 private:
129 #ifdef BUSIO_HAS_HW_SPI
130  SPIClass *_spi = nullptr;
131  SPISettings *_spiSetting = nullptr;
132 #else
133  uint8_t *_spi = nullptr;
134  uint8_t *_spiSetting = nullptr;
135 #endif
136  uint32_t _freq;
137  BusIOBitOrder _dataOrder;
138  uint8_t _dataMode;
139  void setChipSelect(int value);
140 
141  int8_t _cs, _sck, _mosi, _miso;
142 #ifdef BUSIO_USE_FAST_PINIO
143  BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort;
144  BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask;
145 #endif
146  bool _begun;
147 };
148 
149 #endif // Adafruit_SPIDevice_h
bool write(const uint8_t *buffer, size_t len, const uint8_t *prefix_buffer=nullptr, size_t prefix_len=0)
Write a buffer or two to the SPI device, with transaction management.
Definition: Adafruit_SPIDevice.cpp:343
void beginTransactionWithAssertingCS()
Write a buffer or two to the SPI device, with transaction management.
Definition: Adafruit_SPIDevice.cpp:318
void endTransactionWithDeassertingCS()
Manually end a transaction (calls endTransaction if hardware SPI) with deasserting the CS pin...
Definition: Adafruit_SPIDevice.cpp:327
bool write_and_read(uint8_t *buffer, size_t len)
Write some data and read some data at the same time from SPI into the same buffer, with transaction management. This is basicaly a wrapper for transfer() with CS-pin and transaction management. This /does/ transmit-receive at the same time!
Definition: Adafruit_SPIDevice.cpp:502
uint8_t transfer(uint8_t send)
Transfer (send/receive) one byte over hard/soft SPI, without transaction management.
Definition: Adafruit_SPIDevice.cpp:273
~Adafruit_SPIDevice()
Release memory allocated in constructors.
Definition: Adafruit_SPIDevice.cpp:82
bool begin(void)
Initializes SPI bus and sets CS pin high.
Definition: Adafruit_SPIDevice.cpp:92
void endTransaction(void)
Manually end a transaction (calls endTransaction if hardware SPI)
Definition: Adafruit_SPIDevice.cpp:294
bool read(uint8_t *buffer, size_t len, uint8_t sendvalue=0xFF)
Read from SPI into a buffer from the SPI device, with transaction management.
Definition: Adafruit_SPIDevice.cpp:402
Adafruit_SPIDevice(int8_t cspin, uint32_t freq=1000000, BusIOBitOrder dataOrder=SPI_BITORDER_MSBFIRST, uint8_t dataMode=SPI_MODE0, SPIClass *theSPI=&SPI)
Create an SPI device with the given CS pin and settings.
Definition: Adafruit_SPIDevice.cpp:14
Definition: Adafruit_SPIDevice.h:95
void beginTransaction(void)
Manually begin a transaction (calls beginTransaction if hardware SPI)
Definition: Adafruit_SPIDevice.cpp:283
bool write_then_read(const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, uint8_t sendvalue=0xFF)
Write some data, then read some data from SPI into another buffer, with transaction management...
Definition: Adafruit_SPIDevice.cpp:438