Skip to content

Commit 0f77dab

Browse files
Allow SPI to disable RX or TX pins
Pass in `NOPIN` to `setTX` or `setRX` to make a unidirectional SPI interface. Fixes #3115
1 parent 65dea19 commit 0f77dab

File tree

6 files changed

+85
-57
lines changed

6 files changed

+85
-57
lines changed

cores/rp2040/Arduino.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ constexpr uint64_t __bitset(const int (&a)[N], size_t i = 0U) {
170170
#define __FIRSTANALOGGPIO 26
171171
#endif
172172

173+
// For peripherals where a pin may be not used
174+
#define NOPIN ((pin_size_t) 0xff)
175+
173176
#ifdef __cplusplus
174177
using namespace arduino;
175178
#endif

cores/rp2040/SerialPIO.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ extern "C" typedef struct uart_inst uart_inst_t;
2929

3030
class SerialPIO : public arduino::HardwareSerial {
3131
public:
32-
static const pin_size_t NOPIN = 0xff; // Use in constructor to disable RX or TX unit
3332
SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize = 32);
3433
~SerialPIO();
3534

docs/piouart.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ are supported, as well as data sizes from 5- to 8-bits. Fifosize, if not
1212
specified, defaults to 32 bytes.
1313

1414
To instantiate only a serial transmit or receive unit, pass in
15-
``SerialPIO::NOPIN`` as the ``txpin`` or ``rxpin``.
15+
``NOPIN`` as the ``txpin`` or ``rxpin``.
1616

1717
For example, to make a transmit-only port on GP16
1818

1919
.. code:: cpp
2020
21-
SerialPIO transmitter( 16, SerialPIO::NOPIN );
21+
SerialPIO transmitter( 16, NOPIN );
2222
2323
For detailed information about the Serial ports, see the
2424
Arduino `Serial Reference <https://www.arduino.cc/reference/en/language/functions/communication/serial/>`_ .

docs/spi.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ SPI pinouts can be set **before SPI.begin()** using the following calls:
1616
Note that the ``CS`` pin can be hardware or software controlled by the sketch.
1717
When software controlled, the ``setCS()`` call is ignored.
1818

19+
Passing in ``NOPIN`` to either ``setRX`` or ``setTX`` will disable SPI on that
20+
interface, making it behave as a unidirectional (output- or input-only SPI interface.
21+
1922
The Arduino `SPI documentation <https://docs.arduino.cc/language-reference/en/functions/communication/SPI/>`_ gives
2023
a detailed overview of the library, except for the following RP2040-specific
2124
changes:

libraries/SPI/src/SPI.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,11 @@ bool SPIClassRP2040::setRX(pin_size_t pin) {
281281
return true;
282282
}
283283

284+
if (!_running && (pin == NOPIN)) {
285+
_RX = pin;
286+
return true;
287+
}
288+
284289
if (_running) {
285290
panic("FATAL: Attempting to set SPI%s.RX while running", spi_get_index(_spi) ? "1" : "");
286291
} else {
@@ -362,6 +367,11 @@ bool SPIClassRP2040::setTX(pin_size_t pin) {
362367
return true;
363368
}
364369

370+
if (!_running && (pin == NOPIN)) {
371+
_TX = pin;
372+
return true;
373+
}
374+
365375
if (_running) {
366376
panic("FATAL: Attempting to set SPI%s.TX while running", spi_get_index(_spi) ? "1" : "");
367377
} else {
@@ -372,13 +382,22 @@ bool SPIClassRP2040::setTX(pin_size_t pin) {
372382

373383
void SPIClassRP2040::begin(bool hwCS) {
374384
DEBUGSPI("SPI::begin(%d), rx=%d, cs=%d, sck=%d, tx=%d\n", hwCS, _RX, _CS, _SCK, _TX);
375-
gpio_set_function(_RX, GPIO_FUNC_SPI);
385+
386+
if ((_RX == NOPIN) && (_TX == NOPIN)) {
387+
panic("SPI%s: TX and RX assigned to NOPIN", spi_get_index(_spi) ? "1" : "");
388+
}
389+
390+
if (_RX != NOPIN) {
391+
gpio_set_function(_RX, GPIO_FUNC_SPI);
392+
}
376393
_hwCS = hwCS;
377394
if (hwCS) {
378395
gpio_set_function(_CS, GPIO_FUNC_SPI);
379396
}
380397
gpio_set_function(_SCK, GPIO_FUNC_SPI);
381-
gpio_set_function(_TX, GPIO_FUNC_SPI);
398+
if (_TX != NOPIN) {
399+
gpio_set_function(_TX, GPIO_FUNC_SPI);
400+
}
382401
// Give a default config in case user doesn't use beginTransaction
383402
beginTransaction(_spis);
384403
endTransaction();
@@ -391,12 +410,16 @@ void SPIClassRP2040::end() {
391410
_initted = false;
392411
spi_deinit(_spi);
393412
}
394-
gpio_set_function(_RX, GPIO_FUNC_SIO);
413+
if (_RX != NOPIN) {
414+
gpio_set_function(_RX, GPIO_FUNC_SIO);
415+
}
395416
if (_hwCS) {
396417
gpio_set_function(_CS, GPIO_FUNC_SIO);
397418
}
398419
gpio_set_function(_SCK, GPIO_FUNC_SIO);
399-
gpio_set_function(_TX, GPIO_FUNC_SIO);
420+
if (_TX != NOPIN) {
421+
gpio_set_function(_TX, GPIO_FUNC_SIO);
422+
}
400423
_spis = SPISettings(0, LSBFIRST, SPI_MODE0);
401424
}
402425

libraries/SPI/src/SPI.h

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,21 @@
3131
class SPIClassRP2040 : public arduino::HardwareSPI {
3232
public:
3333
/**
34-
@brief Create a PIO-based SPI instance, pins can be changed before begin() call
34+
@brief Create a PIO-based SPI instance, pins can be changed before begin() call
3535
36-
@param [in] spi SPI hardware instance (spi0/spi1)
37-
@param [in] rx MISO GPIO
38-
@param [in] cs CS GPIO
39-
@param [in] sck SCK GPIO
40-
@param [in] tx MOSI GPIO
36+
@param [in] spi SPI hardware instance (spi0/spi1)
37+
@param [in] rx MISO GPIO
38+
@param [in] cs CS GPIO
39+
@param [in] sck SCK GPIO
40+
@param [in] tx MOSI GPIO
4141
*/
4242
SPIClassRP2040(spi_inst_t *spi, pin_size_t rx, pin_size_t cs, pin_size_t sck, pin_size_t tx);
4343

4444
/**
45-
@brief Send an 8-bit byte of data and return read-back 8-bit value
45+
@brief Send an 8-bit byte of data and return read-back 8-bit value
4646
47-
@param [in] data Data to send
48-
@returns Read back byte from SPI interface
47+
@param [in] data Data to send
48+
@returns Read back byte from SPI interface
4949
*/
5050
byte transfer(uint8_t data) override;
5151

@@ -67,11 +67,11 @@ class SPIClassRP2040 : public arduino::HardwareSPI {
6767
void transfer(void *buf, size_t count) override;
6868

6969
/**
70-
@brief Sends one buffer and receives into another under a single CS. Can set rx or txbuf to nullptr
70+
@brief Sends one buffer and receives into another under a single CS. Can set rx or txbuf to nullptr
7171
72-
@param [in] txbuf Buffer to transmit or nullptr to send 0s
73-
@param [out] rxbuf Buffer to read back into or nullptr to ignore returned data
74-
@param [in] count Numbner of bytes to transmit/receive
72+
@param [in] txbuf Buffer to transmit or nullptr to send 0s
73+
@param [out] rxbuf Buffer to read back into or nullptr to ignore returned data
74+
@param [in] count Numbner of bytes to transmit/receive
7575
*/
7676
void transfer(const void *txbuf, void *rxbuf, size_t count) override;
7777

@@ -108,134 +108,134 @@ class SPIClassRP2040 : public arduino::HardwareSPI {
108108

109109

110110
/**
111-
@brief Begin an SPI transaction, sets SPI speed and masks necessary interrupts
111+
@brief Begin an SPI transaction, sets SPI speed and masks necessary interrupts
112112
113-
@param [in] SPISettings SPI configuration parameters, including the clock speed
113+
@param [in] SPISettings SPI configuration parameters, including the clock speed
114114
*/
115115
void beginTransaction(SPISettings settings) override;
116116

117117
/**
118-
@brief Ends an SPI transaction, unmasks and masked GPIO interrupts
118+
@brief Ends an SPI transaction, unmasks and masked GPIO interrupts
119119
*/
120120
void endTransaction(void) override;
121121

122122
/**
123-
@brief Sets the MISO(RX) pin. Call before begin()
123+
@brief Sets the MISO(RX) pin. Call before begin()
124124
125-
@param [in] pin The GPIO number to assign to
126-
@returns True on success
125+
@param [in] pin The GPIO number to assign to or NOPIN
126+
@returns True on success
127127
*/
128128
bool setRX(pin_size_t pin);
129129

130130
/**
131-
@brief Sets the MISO(RX) pin. Call before begin()
131+
@brief Sets the MISO(RX) pin. Call before begin()
132132
133-
@param [in] pin The GPIO number to assign to
134-
@returns True on success
133+
@param [in] pin The GPIO number to assign to
134+
@returns True on success
135135
*/
136136
inline bool setMISO(pin_size_t pin) {
137137
return setRX(pin);
138138
}
139139

140140
/**
141-
@brief Sets the CS pin. Call before begin()
141+
@brief Sets the CS pin. Call before begin()
142142
143-
@param [in] pin The GPIO number to assign to
144-
@returns True on success
143+
@param [in] pin The GPIO number to assign to
144+
@returns True on success
145145
*/
146146
bool setCS(pin_size_t pin);
147147

148148
/**
149-
@brief Sets the SCK pin. Call before begin()
149+
@brief Sets the SCK pin. Call before begin()
150150
151-
@param [in] pin The GPIO number to assign to
152-
@returns True on success
151+
@param [in] pin The GPIO number to assign to
152+
@returns True on success
153153
*/
154154
bool setSCK(pin_size_t pin);
155155

156156
/**
157-
@brief Sets the MOSI(TX) pin. Call before begin()
157+
@brief Sets the MOSI(TX) pin. Call before begin()
158158
159-
@param [in] pin The GPIO number to assign to
160-
@returns True on success
159+
@param [in] pin The GPIO number to assign to
160+
@returns True on success
161161
*/
162162
bool setTX(pin_size_t pin);
163163

164164
/**
165-
@brief Sets the MOSI(TX) pin. Call before begin()
165+
@brief Sets the MOSI(TX) pin. Call before begin()
166166
167-
@param [in] pin The GPIO number to assign to
168-
@returns True on success
167+
@param [in] pin The GPIO number to assign to or NOPIN
168+
@returns True on success
169169
*/
170170
inline bool setMOSI(pin_size_t pin) {
171171
return setTX(pin);
172172
}
173173

174174
/**
175-
@brief Call once to init/deinit SPI class, select pins, etc.
175+
@brief Call once to init/deinit SPI class, select pins, etc.
176176
*/
177177
virtual void begin() override {
178178
begin(false);
179179
}
180180

181181
/**
182-
@brief Call once to init/deinit SPI class, select pins, etc.
182+
@brief Call once to init/deinit SPI class, select pins, etc.
183183
184-
@param [in] hwCS Pass in true to enable HW-controlled CS. Otherwise application needs to assert/deassert CS.
184+
@param [in] hwCS Pass in true to enable HW-controlled CS. Otherwise application needs to assert/deassert CS.
185185
*/
186186
void begin(bool hwCS);
187187

188188
/**
189-
@brief Call to deinit and disable the SPI interface.
189+
@brief Call to deinit and disable the SPI interface.
190190
*/
191191
void end() override;
192192

193193
/**
194-
@brief Deprecated, do not use
194+
@brief Deprecated, do not use
195195
196-
@param [in] order Deprecated
196+
@param [in] order Deprecated
197197
*/
198198
void setBitOrder(BitOrder order) __attribute__((deprecated));
199199

200200
/**
201-
@brief Deprecated, do not use
201+
@brief Deprecated, do not use
202202
203-
@param [in] order Deprecated
203+
@param [in] order Deprecated
204204
*/
205205
void setDataMode(uint8_t uc_mode) __attribute__((deprecated));
206206

207207
/**
208-
@brief Deprecated, do not use
208+
@brief Deprecated, do not use
209209
210-
@param [in] order Deprecated
210+
@param [in] order Deprecated
211211
*/
212212
void setClockDivider(uint8_t uc_div) __attribute__((deprecated));
213213

214214
/**
215-
@brief Ensure specific GPIO interrupt is disabled during and SPI transaction to protect against re-entrancy. Multiple GPIOs supported by multiple calls.
215+
@brief Ensure specific GPIO interrupt is disabled during and SPI transaction to protect against re-entrancy. Multiple GPIOs supported by multiple calls.
216216
217-
@param [in] interruptNumber GPIO pin to mask
217+
@param [in] interruptNumber GPIO pin to mask
218218
*/
219219
virtual void usingInterrupt(int interruptNumber) override {
220220
_helper.usingInterrupt(interruptNumber);
221221
}
222222

223223
/**
224-
@brief Remove a GPIO from the masked-during-transaction list.
224+
@brief Remove a GPIO from the masked-during-transaction list.
225225
226-
@param [in] interruptNumber GPIO pin to unmask
226+
@param [in] interruptNumber GPIO pin to unmask
227227
*/
228228
virtual void notUsingInterrupt(int interruptNumber) override {
229229
_helper.notUsingInterrupt(interruptNumber);
230230
}
231231

232232
/**
233-
@brief Deprecated, do not use
233+
@brief Deprecated, do not use
234234
*/
235235
virtual void attachInterrupt() override __attribute__((deprecated)) { /* noop */ }
236236

237237
/**
238-
@brief Deprecated, do not use
238+
@brief Deprecated, do not use
239239
*/
240240
virtual void detachInterrupt() override __attribute__((deprecated)) { /* noop */ }
241241

0 commit comments

Comments
 (0)