Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6124069

Browse files
committedNov 9, 2023
chore(SPI): clean up internal CS pin managements
To be aligned with Arduino API. Only Hardware CS pin support kept. Allows to save memory space and increase execution speed. Fixes #257. Signed-off-by: Frederic Pillon <[email protected]>
1 parent 93ec4f5 commit 6124069

File tree

3 files changed

+126
-457
lines changed

3 files changed

+126
-457
lines changed
 

‎libraries/SPI/README.md

Lines changed: 43 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,63 @@
11
## SPI
22

3-
STM32 SPI library has been modified with the possibility to manage several CS pins without to stop the SPI interface.
3+
STM32 SPI library has been modified with the possibility to manage hardware CS pin linked to the SPI peripheral.
44
_We do not describe here the [SPI Arduino API](https://www.arduino.cc/en/Reference/SPI) but the functionalities added._
55

6-
We give to the user 3 possibilities about the management of the CS pin:
7-
1. the CS pin is managed directly by the user code before to transfer the data (like the Arduino SPI library)
8-
2. the user gives the CS pin number to the library API and the library manages itself the CS pin (see example below)
9-
3. the user uses a hardware CS pin linked to the SPI peripheral
6+
User have 2 possibilities about the management of the CS pin:
7+
* the CS pin is managed directly by the user code before to transfer the data (like the Arduino SPI library)
8+
* the user uses a hardware CS pin linked to the SPI peripheral
109

11-
### New API functions
10+
### New SPISetting parameter
1211

13-
* **`SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel)`**: alternative class constructor
14-
_Params_ SPI mosi pin
15-
_Params_ SPI miso pin
16-
_Params_ SPI sclk pin
17-
_Params_ (optional) SPI ssel pin. This pin must be an hardware CS pin. If you configure this pin, the chip select will be managed by the SPI peripheral. Do not use API functions with CS pin in parameter.
12+
* `noReceive`: value can be `SPI_TRANSMITRECEIVE` or `SPI_TRANSMITONLY`. It allows to skip receive data after transmitting. Default `SPI_TRANSMITRECEIVE`.
1813

19-
* **`void SPIClass::begin(uint8_t _pin)`**: initialize the SPI interface and add a CS pin
20-
_Params_ spi CS pin to be managed by the SPI library
14+
### New API functions
2115

22-
* **`void beginTransaction(uint8_t pin, SPISettings settings)`**: allows to configure the SPI with other parameter. These new parameter are saved this an associated CS pin.
23-
_Params_ SPI CS pin to be managed by the SPI library
24-
_Params_ SPI settings
16+
* `SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel)`: alternative class constructor
17+
_Params_ SPI `mosi` pin
18+
_Params_ SPI `miso` pin
19+
_Params_ SPI `sclk` pin
20+
_Params_ (optional) SPI `ssel` pin. This pin must be an hardware CS pin. If you configure this pin, the chip select will be managed by the SPI peripheral.
2521

26-
* **`void endTransaction(uint8_t pin)`**: removes a CS pin and the SPI settings associated
27-
_Params_ SPI CS pin managed by the SPI library
22+
* `SPI_HandleTypeDef *getHandle(void)`: Could be used to mix Arduino API and STM32Cube HAL API (ex: DMA). **Use at your own risk.**
2823

29-
**_Note 1_** The following functions must be called after initialization of the SPI instance with `begin()` or `beginTransaction()`.
30-
If you have several device to manage, you can call `beginTransaction()` several time with different CS pin in parameter.
31-
Then you can call the following functions with different CS pin without call again `beginTransaction()` (until you call `end()` or `endTransaction()`).
3224

33-
**_Note 2_** If the mode is set to `SPI_CONTINUE`, the CS pin is kept enabled. Be careful in case you use several CS pin.
25+
##### Example
3426

35-
* **`byte transfer(uint8_t pin, uint8_t _data, SPITransferMode _mode = SPI_LAST)`**: write/read one byte
36-
_Params_ SPI CS pin managed by the SPI library
37-
_Params_ data to write
38-
_Params_ (optional) if `SPI_LAST` CS pin is reset, `SPI_CONTINUE` the CS pin is kept enabled.
39-
_Return_ byte received
27+
This is an example of the use of the hardware CS pin linked to the SPI peripheral:
4028

41-
* **`uint16_t transfer16(uint8_t pin, uint16_t _data, SPITransferMode _mode = SPI_LAST)`**: write/read half-word
42-
_Params_ SPI CS pin managed by the SPI library
43-
_Params_ 16bits data to write
44-
_Params_ (optional) if `SPI_LAST` CS pin is reset, `SPI_CONTINUE` the CS pin is kept enabled.
45-
_Return_ 16bits data received
29+
```C++
30+
#include <SPI.h>
31+
// MOSI MISO SCLK SSEL
32+
SPIClass SPI_3(PC12, PC11, PC10, PC9);
33+
34+
void setup() {
35+
SPI_3.begin(); // Enable the SPI_3 instance with default SPISsettings
36+
SPI_3.beginTransaction(settings); // Configure the SPI_3 instance with other settings
37+
SPI_3.transfer(0x52); // Transfers data to the first device
38+
SPI_3.end() //SPI_3 instance is disabled
39+
}
40+
```
4641
47-
* **`void transfer(uint8_t pin, void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST)`**: write/read several bytes. Only one buffer used to write and read the data
48-
_Params_ SPI CS pin managed by the SPI library
49-
_Params_ pointer to data to write. The data will be replaced by the data read.
50-
_Params_ number of data to write/read.
51-
_Params_ (optional) if `SPI_LAST` CS pin is reset, `SPI_CONTINUE` the CS pin is kept enabled.
42+
#### Change default `SPI` instance pins
43+
It is also possible to change the default pins used by the `SPI` instance using above API:
5244
53-
* **`void transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode = SPI_LAST)`**: write/read several bytes. One buffer for the output data and one for the input data
54-
_Params_ SPI CS pin managed by the SPI library
55-
_Params_ pointer to data to write.
56-
_Params_ pointer where to store the data read.
57-
_Params_ number of data to write/read.
58-
_Params_ (optional) if `SPI_LAST` CS pin is reset, `SPI_CONTINUE` the CS pin is kept enabled.
45+
[[/img/Warning-icon.png|alt="Warning"]] **Have to be called before `begin()`.**
5946
60-
### Example
47+
* `void setMISO(uint32_t miso)`
48+
* `void setMOSI(uint32_t mosi)`
49+
* `void setSCLK(uint32_t sclk)`
50+
* `void setSSEL(uint32_t ssel)`
51+
* `void setMISO(PinName miso)`
52+
* `void setMOSI(PinName mosi)`
53+
* `void setSCLK(PinName sclk)`
54+
* `void setSSEL(PinName ssel)`
6155
62-
This is an example of the use of the CS pin management:
56+
**_Note 1_** Using `setSSEL()` allows to enable hardware CS pin management linked to the SPI peripheral.
6357
58+
##### Example:
6459
```C++
65-
SPI.begin(2); //Enables the SPI instance with default settings and attaches the CS pin
66-
SPI.beginTransaction(1, settings); //Attaches another CS pin and configure the SPI instance with other settings
67-
SPI.transfer(1, 0x52); //Transfers data to the first device
68-
SPI.transfer(2, 0xA4); //Transfers data to the second device. The SPI instance is configured with the right settings
69-
SPI.end() //SPI instance is disabled
60+
SPI.setMISO(PC_4); // using pin name PY_n
61+
SPI.setMOSI(PC2); // using pin number PYn
62+
SPI.begin(2);
7063
```

‎libraries/SPI/src/SPI.cpp

Lines changed: 63 additions & 257 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ SPIClass SPI;
1616
/**
1717
* @brief Default constructor. Uses pin configuration of variant.h.
1818
*/
19-
SPIClass::SPIClass() : _CSPinConfig(NO_CONFIG)
19+
SPIClass::SPIClass()
2020
{
2121
_spi.pin_miso = digitalPinToPinName(MISO);
2222
_spi.pin_mosi = digitalPinToPinName(MOSI);
@@ -43,7 +43,7 @@ SPIClass::SPIClass() : _CSPinConfig(NO_CONFIG)
4343
* another CS pin and don't pass a CS pin as parameter to any functions
4444
* of the class.
4545
*/
46-
SPIClass::SPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel) : _CSPinConfig(NO_CONFIG)
46+
SPIClass::SPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel)
4747
{
4848
_spi.pin_miso = digitalPinToPinName(miso);
4949
_spi.pin_mosi = digitalPinToPinName(mosi);
@@ -53,70 +53,38 @@ SPIClass::SPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel) :
5353

5454
/**
5555
* @brief Initialize the SPI instance.
56-
* @param _pin: chip select pin (optional). If this parameter is filled,
57-
* it gives the management of the CS pin to the SPI class. In this case
58-
* do not manage the CS pin outside of the SPI class.
5956
*/
60-
void SPIClass::begin(uint8_t _pin)
57+
void SPIClass::begin(void)
6158
{
62-
uint8_t idx = pinIdx(_pin, ADD_NEW_PIN);
63-
if (idx >= NB_SPI_SETTINGS) {
64-
return;
65-
}
66-
67-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) {
68-
pinMode(_pin, OUTPUT);
69-
digitalWrite(_pin, HIGH);
70-
}
71-
7259
_spi.handle.State = HAL_SPI_STATE_RESET;
73-
spi_init(&_spi, spiSettings[idx].clk,
74-
spiSettings[idx].dMode,
75-
spiSettings[idx].bOrder);
76-
_CSPinConfig = _pin;
60+
spi_init(&_spi, _spiSettings.clk,
61+
_spiSettings.dMode,
62+
_spiSettings.bOrder);
7763
}
7864

7965
/**
8066
* @brief This function should be used to configure the SPI instance in case you
8167
* don't use the default parameters set by the begin() function.
82-
* @param _pin: CS pin (optional). This pin will be attached with the settings.
8368
* @param settings: SPI settings(clock speed, bit order, data mode).
84-
* @Note For each SPI instance you are able to manage until NB_SPI_SETTINGS
85-
* devices attached to the same SPI peripheral. You need to indicate the
86-
* CS pin used to the transfer() function and the SPI instance will be
87-
* configured with the right settings.
8869
*/
89-
void SPIClass::beginTransaction(uint8_t _pin, SPISettings settings)
70+
void SPIClass::beginTransaction(SPISettings settings)
9071
{
91-
uint8_t idx = pinIdx(_pin, ADD_NEW_PIN);
92-
if (idx >= NB_SPI_SETTINGS) {
93-
return;
94-
}
95-
96-
spiSettings[idx].clk = settings.clk;
97-
spiSettings[idx].dMode = settings.dMode;
98-
spiSettings[idx].bOrder = settings.bOrder;
99-
spiSettings[idx].noReceive = settings.noReceive;
100-
101-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) {
102-
pinMode(_pin, OUTPUT);
103-
digitalWrite(_pin, HIGH);
104-
}
105-
106-
spi_init(&_spi, spiSettings[idx].clk,
107-
spiSettings[idx].dMode,
108-
spiSettings[idx].bOrder);
109-
_CSPinConfig = _pin;
72+
_spiSettings.clk = settings.clk;
73+
_spiSettings.dMode = settings.dMode;
74+
_spiSettings.bOrder = settings.bOrder;
75+
_spiSettings.noReceive = settings.noReceive;
76+
77+
spi_init(&_spi, _spiSettings.clk,
78+
_spiSettings.dMode,
79+
_spiSettings.bOrder);
11080
}
11181

11282
/**
113-
* @brief Remove the CS pin and the settings associated to the SPI instance.
114-
* @param _pin: CS pin (optional)
83+
* @brief End the transaction after beginTransaction usage
11584
*/
116-
void SPIClass::endTransaction(uint8_t _pin)
85+
void SPIClass::endTransaction(void)
11786
{
118-
RemovePin(_pin);
119-
_CSPinConfig = NO_CONFIG;
87+
12088
}
12189

12290
/**
@@ -125,34 +93,25 @@ void SPIClass::endTransaction(uint8_t _pin)
12593
void SPIClass::end()
12694
{
12795
spi_deinit(&_spi);
128-
RemoveAllPin();
129-
_CSPinConfig = NO_CONFIG;
13096
}
13197

13298
/**
13399
* @brief Deprecated function.
134100
* Configure the bit order: MSB first or LSB first.
135-
* @param _pin: CS pin associated to a configuration (optional).
136101
* @param _bitOrder: MSBFIRST or LSBFIRST
137102
*/
138-
void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder)
103+
void SPIClass::setBitOrder(BitOrder bitOrder)
139104
{
140-
uint8_t idx = pinIdx(_pin, GET_IDX);
141-
if (idx >= NB_SPI_SETTINGS) {
142-
return;
143-
}
144-
145-
spiSettings[idx].bOrder = _bitOrder;
105+
_spiSettings.bOrder = bitOrder;
146106

147-
spi_init(&_spi, spiSettings[idx].clk,
148-
spiSettings[idx].dMode,
149-
spiSettings[idx].bOrder);
107+
spi_init(&_spi, _spiSettings.clk,
108+
_spiSettings.dMode,
109+
_spiSettings.bOrder);
150110
}
151111

152112
/**
153113
* @brief Deprecated function.
154114
* Configure the data mode (clock polarity and clock phase)
155-
* @param _pin: CS pin associated to a configuration (optional).
156115
* @param _mode: SPI_MODE0, SPI_MODE1, SPI_MODE2 or SPI_MODE3
157116
* @note
158117
* Mode Clock Polarity (CPOL) Clock Phase (CPHA)
@@ -161,142 +120,75 @@ void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder)
161120
* SPI_MODE2 1 0
162121
* SPI_MODE3 1 1
163122
*/
164-
void SPIClass::setDataMode(uint8_t _pin, uint8_t _mode)
123+
void SPIClass::setDataMode(uint8_t _mode)
165124
{
166-
uint8_t idx = pinIdx(_pin, GET_IDX);
167-
if (idx >= NB_SPI_SETTINGS) {
168-
return;
169-
}
170-
171125
if (SPI_MODE0 == _mode) {
172-
spiSettings[idx].dMode = SPI_MODE_0;
126+
_spiSettings.dMode = SPI_MODE_0;
173127
} else if (SPI_MODE1 == _mode) {
174-
spiSettings[idx].dMode = SPI_MODE_1;
128+
_spiSettings.dMode = SPI_MODE_1;
175129
} else if (SPI_MODE2 == _mode) {
176-
spiSettings[idx].dMode = SPI_MODE_2;
130+
_spiSettings.dMode = SPI_MODE_2;
177131
} else if (SPI_MODE3 == _mode) {
178-
spiSettings[idx].dMode = SPI_MODE_3;
132+
_spiSettings.dMode = SPI_MODE_3;
179133
}
180134

181-
spi_init(&_spi, spiSettings[idx].clk,
182-
spiSettings[idx].dMode,
183-
spiSettings[idx].bOrder);
135+
spi_init(&_spi, _spiSettings.clk,
136+
_spiSettings.dMode,
137+
_spiSettings.bOrder);
184138
}
185139

186140
/**
187141
* @brief Deprecated function.
188142
* Configure the clock speed
189-
* @param _pin: CS pin associated to a configuration (optional).
190143
* @param _divider: the SPI clock can be divided by values from 1 to 255.
191144
* If 0, default SPI speed is used.
192145
*/
193-
void SPIClass::setClockDivider(uint8_t _pin, uint8_t _divider)
146+
void SPIClass::setClockDivider(uint8_t _divider)
194147
{
195-
uint8_t idx = pinIdx(_pin, GET_IDX);
196-
if (idx >= NB_SPI_SETTINGS) {
197-
return;
198-
}
199148
if (_divider == 0) {
200-
spiSettings[idx].clk = SPI_SPEED_CLOCK_DEFAULT;
149+
_spiSettings.clk = SPI_SPEED_CLOCK_DEFAULT;
201150
} else {
202151
/* Get clk freq of the SPI instance and compute it */
203-
spiSettings[idx].clk = spi_getClkFreq(&_spi) / _divider;
152+
_spiSettings.clk = spi_getClkFreq(&_spi) / _divider;
204153
}
205154

206-
spi_init(&_spi, spiSettings[idx].clk,
207-
spiSettings[idx].dMode,
208-
spiSettings[idx].bOrder);
155+
spi_init(&_spi, _spiSettings.clk,
156+
_spiSettings.dMode,
157+
_spiSettings.bOrder);
209158
}
210159

211160
/**
212161
* @brief Transfer one byte on the SPI bus.
213162
* begin() or beginTransaction() must be called at least once before.
214-
* @param _pin: CS pin to select a device (optional). If the previous transfer
215-
* used another CS pin then the SPI instance will be reconfigured.
216163
* @param data: byte to send.
217-
* @param _mode: (optional) can be SPI_CONTINUE in case of multiple successive
218-
* send or SPI_LAST to indicate the end of send.
219-
* If the _mode is set to SPI_CONTINUE, keep the SPI instance alive.
220-
* That means the CS pin is not reset. Be careful in case you use
221-
* several CS pin.
222164
* @return byte received from the slave.
223165
*/
224-
byte SPIClass::transfer(uint8_t _pin, uint8_t data, SPITransferMode _mode)
166+
byte SPIClass::transfer(uint8_t data)
225167
{
226168
uint8_t rx_buffer = 0;
227-
228-
uint8_t idx = pinIdx(_pin, GET_IDX);
229-
if (idx >= NB_SPI_SETTINGS) {
230-
return rx_buffer;
231-
}
232-
233-
if (_pin != _CSPinConfig) {
234-
spi_init(&_spi, spiSettings[idx].clk,
235-
spiSettings[idx].dMode,
236-
spiSettings[idx].bOrder);
237-
_CSPinConfig = _pin;
238-
}
239-
240-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) {
241-
digitalWrite(_pin, LOW);
242-
}
243-
244-
spi_transfer(&_spi, &data, &rx_buffer, sizeof(uint8_t), SPI_TRANSFER_TIMEOUT, spiSettings[idx].noReceive);
245-
246-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) {
247-
digitalWrite(_pin, HIGH);
248-
}
249-
169+
spi_transfer(&_spi, &data, &rx_buffer, sizeof(uint8_t), SPI_TRANSFER_TIMEOUT, _spiSettings.noReceive);
250170
return rx_buffer;
251171
}
252172

253173
/**
254174
* @brief Transfer two bytes on the SPI bus in 16 bits format.
255175
* begin() or beginTransaction() must be called at least once before.
256-
* @param _pin: CS pin to select a device (optional). If the previous transfer
257-
* used another CS pin then the SPI instance will be reconfigured.
258176
* @param data: bytes to send.
259-
* @param _mode: (optional) can be SPI_CONTINUE in case of multiple successive
260-
* send or SPI_LAST to indicate the end of send.
261-
* If the _mode is set to SPI_CONTINUE, keep the SPI instance alive.
262-
* That means the CS pin is not reset. Be careful in case you use
263-
* several CS pin.
264177
* @return bytes received from the slave in 16 bits format.
265178
*/
266-
uint16_t SPIClass::transfer16(uint8_t _pin, uint16_t data, SPITransferMode _mode)
179+
uint16_t SPIClass::transfer16(uint16_t data)
267180
{
268181
uint16_t rx_buffer = 0;
269182
uint16_t tmp;
270183

271-
uint8_t idx = pinIdx(_pin, GET_IDX);
272-
if (idx >= NB_SPI_SETTINGS) {
273-
return rx_buffer;
274-
}
275-
276-
if (_pin != _CSPinConfig) {
277-
spi_init(&_spi, spiSettings[idx].clk,
278-
spiSettings[idx].dMode,
279-
spiSettings[idx].bOrder);
280-
_CSPinConfig = _pin;
281-
}
282-
283-
if (spiSettings[idx].bOrder) {
184+
if (_spiSettings.bOrder) {
284185
tmp = ((data & 0xff00) >> 8) | ((data & 0xff) << 8);
285186
data = tmp;
286187
}
287-
288-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) {
289-
digitalWrite(_pin, LOW);
290-
}
291-
292188
spi_transfer(&_spi, (uint8_t *)&data, (uint8_t *)&rx_buffer, sizeof(uint16_t),
293-
SPI_TRANSFER_TIMEOUT, spiSettings[idx].noReceive);
294-
295-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) {
296-
digitalWrite(_pin, HIGH);
297-
}
189+
SPI_TRANSFER_TIMEOUT, _spiSettings.noReceive);
298190

299-
if (spiSettings[idx].bOrder) {
191+
if (_spiSettings.bOrder) {
300192
tmp = ((rx_buffer & 0xff00) >> 8) | ((rx_buffer & 0xff) << 8);
301193
rx_buffer = tmp;
302194
}
@@ -307,87 +199,31 @@ uint16_t SPIClass::transfer16(uint8_t _pin, uint16_t data, SPITransferMode _mode
307199
/**
308200
* @brief Transfer several bytes. Only one buffer used to send and receive data.
309201
* begin() or beginTransaction() must be called at least once before.
310-
* @param _pin: CS pin to select a device (optional). If the previous transfer
311-
* used another CS pin then the SPI instance will be reconfigured.
312202
* @param _buf: pointer to the bytes to send. The bytes received are copy in
313203
* this buffer.
314204
* @param _count: number of bytes to send/receive.
315-
* @param _mode: (optional) can be SPI_CONTINUE in case of multiple successive
316-
* send or SPI_LAST to indicate the end of send.
317-
* If the _mode is set to SPI_CONTINUE, keep the SPI instance alive.
318-
* That means the CS pin is not reset. Be careful in case you use
319-
* several CS pin.
320205
*/
321-
void SPIClass::transfer(uint8_t _pin, void *_buf, size_t _count, SPITransferMode _mode)
206+
void SPIClass::transfer(void *_buf, size_t _count)
322207
{
323-
if ((_count == 0) || (_buf == NULL)) {
324-
return;
325-
}
326-
uint8_t idx = pinIdx(_pin, GET_IDX);
327-
if (idx >= NB_SPI_SETTINGS) {
328-
return;
329-
}
330-
if (_pin != _CSPinConfig) {
331-
332-
spi_init(&_spi, spiSettings[idx].clk,
333-
spiSettings[idx].dMode,
334-
spiSettings[idx].bOrder);
335-
_CSPinConfig = _pin;
336-
}
337-
338-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) {
339-
digitalWrite(_pin, LOW);
340-
}
341-
342-
spi_transfer(&_spi, ((uint8_t *)_buf), ((uint8_t *)_buf), _count,
343-
SPI_TRANSFER_TIMEOUT, spiSettings[idx].noReceive);
344-
345-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) {
346-
digitalWrite(_pin, HIGH);
208+
if ((_count != 0) && (_buf != NULL)) {
209+
spi_transfer(&_spi, ((uint8_t *)_buf), ((uint8_t *)_buf), _count,
210+
SPI_TRANSFER_TIMEOUT, _spiSettings.noReceive);
347211
}
348212
}
349213

350214
/**
351215
* @brief Transfer several bytes. One buffer contains the data to send and
352216
* another one will contains the data received. begin() or
353217
* beginTransaction() must be called at least once before.
354-
* @param _pin: CS pin to select a device (optional). If the previous transfer
355-
* used another CS pin then the SPI instance will be reconfigured.
356218
* @param _bufout: pointer to the bytes to send.
357219
* @param _bufin: pointer to the bytes received.
358220
* @param _count: number of bytes to send/receive.
359-
* @param _mode: (optional) can be SPI_CONTINUE in case of multiple successive
360-
* send or SPI_LAST to indicate the end of send.
361-
* If the _mode is set to SPI_CONTINUE, keep the SPI instance alive.
362-
* That means the CS pin is not reset. Be careful in case you use
363-
* several CS pin.
364221
*/
365-
void SPIClass::transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode)
222+
void SPIClass::transfer(void *_bufout, void *_bufin, size_t _count)
366223
{
367-
if ((_count == 0) || (_bufout == NULL) || (_bufin == NULL)) {
368-
return;
369-
}
370-
uint8_t idx = pinIdx(_pin, GET_IDX);
371-
if (idx >= NB_SPI_SETTINGS) {
372-
return;
373-
}
374-
375-
if (_pin != _CSPinConfig) {
376-
spi_init(&_spi, spiSettings[idx].clk,
377-
spiSettings[idx].dMode,
378-
spiSettings[idx].bOrder);
379-
_CSPinConfig = _pin;
380-
}
381-
382-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) {
383-
digitalWrite(_pin, LOW);
384-
}
385-
386-
spi_transfer(&_spi, ((uint8_t *)_bufout), ((uint8_t *)_bufin), _count,
387-
SPI_TRANSFER_TIMEOUT, spiSettings[idx].noReceive);
388-
389-
if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) {
390-
digitalWrite(_pin, HIGH);
224+
if ((_count != 0) && (_bufout != NULL) && (_bufin != NULL)) {
225+
spi_transfer(&_spi, ((uint8_t *)_bufout), ((uint8_t *)_bufin), _count,
226+
SPI_TRANSFER_TIMEOUT, _spiSettings.noReceive);
391227
}
392228
}
393229

@@ -416,68 +252,38 @@ void SPIClass::detachInterrupt(void)
416252
}
417253

418254
#if defined(SUBGHZSPI_BASE)
419-
void SUBGHZSPIClass::begin(uint8_t _pin)
255+
void SUBGHZSPIClass::begin()
420256
{
421-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
422-
LL_PWR_UnselectSUBGHZSPI_NSS();
423-
}
424-
SPIClass::begin(CS_PIN_CONTROLLED_BY_USER);
257+
SPIClass::begin();
425258
}
426259

427-
void SUBGHZSPIClass::beginTransaction(uint8_t _pin, SPISettings settings)
260+
void SUBGHZSPIClass::beginTransaction(SPISettings settings)
428261
{
429-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
430-
LL_PWR_UnselectSUBGHZSPI_NSS();
431-
}
432-
SPIClass::beginTransaction(CS_PIN_CONTROLLED_BY_USER, settings);
262+
SPIClass::beginTransaction(settings);
433263
}
434264

435-
byte SUBGHZSPIClass::transfer(uint8_t _pin, uint8_t _data, SPITransferMode _mode)
265+
byte SUBGHZSPIClass::transfer(uint8_t _data)
436266
{
437267
byte res;
438-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
439-
LL_PWR_SelectSUBGHZSPI_NSS();
440-
}
441-
res = SPIClass::transfer(CS_PIN_CONTROLLED_BY_USER, _data, _mode);
442-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
443-
LL_PWR_UnselectSUBGHZSPI_NSS();
444-
}
268+
res = SPIClass::transfer(_data);
445269
return res;
446270
}
447271

448-
uint16_t SUBGHZSPIClass::transfer16(uint8_t _pin, uint16_t _data, SPITransferMode _mode)
272+
uint16_t SUBGHZSPIClass::transfer16(uint16_t _data)
449273
{
450274
uint16_t rx_buffer = 0;
451-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
452-
LL_PWR_SelectSUBGHZSPI_NSS();
453-
}
454-
SPIClass::transfer16(CS_PIN_CONTROLLED_BY_USER, _data, _mode);
455-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
456-
LL_PWR_UnselectSUBGHZSPI_NSS();
457-
}
275+
rx_buffer = SPIClass::transfer16(_data);
458276
return rx_buffer;
459277
}
460278

461-
void SUBGHZSPIClass::transfer(uint8_t _pin, void *_buf, size_t _count, SPITransferMode _mode)
279+
void SUBGHZSPIClass::transfer(void *_buf, size_t _count)
462280
{
463-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
464-
LL_PWR_SelectSUBGHZSPI_NSS();
465-
}
466-
SPIClass::transfer(CS_PIN_CONTROLLED_BY_USER, _buf, _count, _mode);
467-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
468-
LL_PWR_UnselectSUBGHZSPI_NSS();
469-
}
281+
SPIClass::transfer(_buf, _count);
470282
}
471283

472-
void SUBGHZSPIClass::transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode)
284+
void SUBGHZSPIClass::transfer(void *_bufout, void *_bufin, size_t _count)
473285
{
474-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
475-
LL_PWR_SelectSUBGHZSPI_NSS();
476-
}
477-
SPIClass::transfer(CS_PIN_CONTROLLED_BY_USER, _bufout, _bufin, _count, _mode);
478-
if (_pin != CS_PIN_CONTROLLED_BY_USER) {
479-
LL_PWR_UnselectSUBGHZSPI_NSS();
480-
}
286+
SPIClass::transfer(_bufout, _bufin, _count);
481287
}
482288

483289
void SUBGHZSPIClass::enableDebugPins(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel)

‎libraries/SPI/src/SPI.h

Lines changed: 20 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -47,36 +47,15 @@ extern "C" {
4747
#define SPI_TRANSMITRECEIVE 0x0
4848
#define SPI_TRANSMITONLY 0x1
4949

50-
// Transfer mode
51-
enum SPITransferMode {
52-
SPI_CONTINUE, /* Transfer not finished: CS pin kept active */
53-
SPI_LAST /* Transfer ended: CS pin released */
54-
};
55-
56-
// Indicates the user controls himself the CS pin outside of the spi class
57-
#define CS_PIN_CONTROLLED_BY_USER NUM_DIGITAL_PINS
58-
59-
// Indicates there is no configuration selected
60-
#define NO_CONFIG ((int16_t)(-1))
61-
6250
// Defines a default timeout delay in milliseconds for the SPI transfer
6351
#ifndef SPI_TRANSFER_TIMEOUT
6452
#define SPI_TRANSFER_TIMEOUT 1000
6553
#endif
6654

67-
/*
68-
* Defines the number of settings saved per SPI instance. Must be in range 1 to 254.
69-
* Can be redefined in variant.h
70-
*/
71-
#ifndef NB_SPI_SETTINGS
72-
#define NB_SPI_SETTINGS 4
73-
#endif
74-
7555
class SPISettings {
7656
public:
7757
constexpr SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, bool noRecv = SPI_TRANSMITRECEIVE)
78-
: pinCS(-1),
79-
clk(clock),
58+
: clk(clock),
8059
bOrder(bitOrder),
8160
dMode((spi_mode_e)(
8261
(SPI_MODE0 == dataMode) ? SPI_MODE_0 :
@@ -88,14 +67,12 @@ class SPISettings {
8867
noReceive(noRecv)
8968
{ }
9069
constexpr SPISettings()
91-
: pinCS(-1),
92-
clk(SPI_SPEED_CLOCK_DEFAULT),
70+
: clk(SPI_SPEED_CLOCK_DEFAULT),
9371
bOrder(MSBFIRST),
9472
dMode(SPI_MODE_0),
9573
noReceive(SPI_TRANSMITRECEIVE)
9674
{ }
9775
private:
98-
int16_t pinCS; //CS pin associated to the configuration
9976
uint32_t clk; //specifies the spi bus maximum clock speed
10077
BitOrder bOrder; //bit order (MSBFirst or LSBFirst)
10178
spi_mode_e dMode; //one of the data mode
@@ -148,76 +125,29 @@ class SPIClass {
148125
_spi.pin_ssel = (ssel);
149126
};
150127

151-
virtual void begin(uint8_t _pin = CS_PIN_CONTROLLED_BY_USER);
128+
virtual void begin();
152129
void end(void);
153130

154131
/* This function should be used to configure the SPI instance in case you
155132
* don't use default parameters.
156-
* You can attach another CS pin to the SPI instance and each CS pin can be
157-
* attach with specific SPI settings.
158133
*/
159-
virtual void beginTransaction(uint8_t pin, SPISettings settings);
160-
void beginTransaction(SPISettings settings)
161-
{
162-
beginTransaction(CS_PIN_CONTROLLED_BY_USER, settings);
163-
}
164-
165-
void endTransaction(uint8_t pin);
166-
void endTransaction(void)
167-
{
168-
endTransaction(CS_PIN_CONTROLLED_BY_USER);
169-
}
134+
void beginTransaction(SPISettings settings);
135+
virtual void endTransaction(void);
170136

171137
/* Transfer functions: must be called after initialization of the SPI
172138
* instance with begin() or beginTransaction().
173-
* You can specify the CS pin to use.
174139
*/
175-
virtual byte transfer(uint8_t pin, uint8_t _data, SPITransferMode _mode = SPI_LAST);
176-
virtual uint16_t transfer16(uint8_t pin, uint16_t _data, SPITransferMode _mode = SPI_LAST);
177-
virtual void transfer(uint8_t pin, void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST);
178-
virtual void transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode = SPI_LAST);
179-
180-
// Transfer functions when user controls himself the CS pin.
181-
byte transfer(uint8_t _data, SPITransferMode _mode = SPI_LAST)
182-
{
183-
return transfer(CS_PIN_CONTROLLED_BY_USER, _data, _mode);
184-
}
185-
186-
uint16_t transfer16(uint16_t _data, SPITransferMode _mode = SPI_LAST)
187-
{
188-
return transfer16(CS_PIN_CONTROLLED_BY_USER, _data, _mode);
189-
}
190-
191-
void transfer(void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST)
192-
{
193-
transfer(CS_PIN_CONTROLLED_BY_USER, _buf, _count, _mode);
194-
}
195-
196-
void transfer(void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode = SPI_LAST)
197-
{
198-
transfer(CS_PIN_CONTROLLED_BY_USER, _bufout, _bufin, _count, _mode);
199-
}
140+
virtual byte transfer(uint8_t _data);
141+
virtual uint16_t transfer16(uint16_t _data);
142+
virtual void transfer(void *_buf, size_t _count);
143+
virtual void transfer(void *_bufout, void *_bufin, size_t _count);
200144

201145
/* These methods are deprecated and kept for compatibility.
202146
* Use SPISettings with SPI.beginTransaction() to configure SPI parameters.
203147
*/
204-
void setBitOrder(uint8_t _pin, BitOrder);
205-
void setBitOrder(BitOrder _order)
206-
{
207-
setBitOrder(CS_PIN_CONTROLLED_BY_USER, _order);
208-
}
209-
210-
void setDataMode(uint8_t _pin, uint8_t);
211-
void setDataMode(uint8_t _mode)
212-
{
213-
setDataMode(CS_PIN_CONTROLLED_BY_USER, _mode);
214-
}
215-
216-
void setClockDivider(uint8_t _pin, uint8_t);
217-
void setClockDivider(uint8_t _div)
218-
{
219-
setClockDivider(CS_PIN_CONTROLLED_BY_USER, _div);
220-
}
148+
void setBitOrder(BitOrder);
149+
void setDataMode(uint8_t);
150+
void setClockDivider(uint8_t);
221151

222152
// Not implemented functions. Kept for backward compatibility.
223153
void usingInterrupt(uint8_t interruptNumber);
@@ -235,68 +165,8 @@ class SPIClass {
235165
spi_t _spi;
236166

237167
private:
238-
/* Contains various spiSettings for the same spi instance. Each spi spiSettings
239-
is associated to a CS pin. */
240-
SPISettings spiSettings[NB_SPI_SETTINGS];
241-
242-
// Use to know which configuration is selected.
243-
int16_t _CSPinConfig;
244-
245-
typedef enum {
246-
GET_IDX = 0,
247-
ADD_NEW_PIN = 1
248-
} pin_option_t;
249-
250-
uint8_t pinIdx(uint8_t _pin, pin_option_t option)
251-
{
252-
uint8_t i;
253-
254-
if ((_pin > NUM_DIGITAL_PINS) && (!digitalPinIsValid(_pin))) {
255-
return NB_SPI_SETTINGS;
256-
}
257-
258-
for (i = 0; i < NB_SPI_SETTINGS; i++) {
259-
if (_pin == spiSettings[i].pinCS) {
260-
return i;
261-
}
262-
}
263-
264-
if (option == ADD_NEW_PIN) {
265-
for (i = 0; i < NB_SPI_SETTINGS; i++) {
266-
if (spiSettings[i].pinCS == -1) {
267-
spiSettings[i].pinCS = _pin;
268-
return i;
269-
}
270-
}
271-
}
272-
return i;
273-
}
274-
275-
void RemovePin(uint8_t _pin)
276-
{
277-
if ((_pin > NUM_DIGITAL_PINS) && (!digitalPinIsValid(_pin))) {
278-
return;
279-
}
280-
281-
for (uint8_t i = 0; i < NB_SPI_SETTINGS; i++) {
282-
if (spiSettings[i].pinCS == _pin) {
283-
spiSettings[i].pinCS = -1;
284-
spiSettings[i].clk = SPI_SPEED_CLOCK_DEFAULT;
285-
spiSettings[i].bOrder = MSBFIRST;
286-
spiSettings[i].dMode = SPI_MODE_0;
287-
}
288-
}
289-
}
290-
291-
void RemoveAllPin(void)
292-
{
293-
for (uint8_t i = 0; i < NB_SPI_SETTINGS; i++) {
294-
spiSettings[i].pinCS = -1;
295-
spiSettings[i].clk = SPI_SPEED_CLOCK_DEFAULT;
296-
spiSettings[i].bOrder = MSBFIRST;
297-
spiSettings[i].dMode = SPI_MODE_0;
298-
}
299-
}
168+
/* Current SPISettings */
169+
SPISettings _spiSettings = SPISettings();
300170
};
301171

302172
extern SPIClass SPI;
@@ -309,12 +179,12 @@ class SUBGHZSPIClass : public SPIClass {
309179
_spi.spi = SUBGHZSPI;
310180
}
311181

312-
void begin(uint8_t _pin = CS_PIN_CONTROLLED_BY_USER);
313-
void beginTransaction(uint8_t pin, SPISettings settings);
314-
byte transfer(uint8_t pin, uint8_t _data, SPITransferMode _mode = SPI_LAST);
315-
uint16_t transfer16(uint8_t pin, uint16_t _data, SPITransferMode _mode = SPI_LAST);
316-
void transfer(uint8_t pin, void *_buf, size_t _count, SPITransferMode _mode = SPI_LAST);
317-
void transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode = SPI_LAST);
182+
void begin();
183+
void beginTransaction(SPISettings settings);
184+
byte transfer(uint8_t _data);
185+
uint16_t transfer16(uint16_t _data);
186+
void transfer(void *_buf, size_t _count);
187+
void transfer(void *_bufout, void *_bufin, size_t _count);
318188
void enableDebugPins(uint32_t mosi = DEBUG_SUBGHZSPI_MOSI, uint32_t miso = DEBUG_SUBGHZSPI_MISO, uint32_t sclk = DEBUG_SUBGHZSPI_SCLK, uint32_t ssel = DEBUG_SUBGHZSPI_SS);
319189

320190
using SPIClass::beginTransaction;

0 commit comments

Comments
 (0)
Please sign in to comment.