diff --git a/cores/rp2040/Arduino.h b/cores/rp2040/Arduino.h index 8efad0b70..5d850a5b1 100644 --- a/cores/rp2040/Arduino.h +++ b/cores/rp2040/Arduino.h @@ -170,6 +170,9 @@ constexpr uint64_t __bitset(const int (&a)[N], size_t i = 0U) { #define __FIRSTANALOGGPIO 26 #endif +// For peripherals where a pin may be not used +#define NOPIN ((pin_size_t) 0xff) + #ifdef __cplusplus using namespace arduino; #endif diff --git a/cores/rp2040/SerialPIO.h b/cores/rp2040/SerialPIO.h index 3b7d0cf87..fd92d588a 100644 --- a/cores/rp2040/SerialPIO.h +++ b/cores/rp2040/SerialPIO.h @@ -29,7 +29,6 @@ extern "C" typedef struct uart_inst uart_inst_t; class SerialPIO : public arduino::HardwareSerial { public: - static const pin_size_t NOPIN = 0xff; // Use in constructor to disable RX or TX unit SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize = 32); ~SerialPIO(); diff --git a/docs/piouart.rst b/docs/piouart.rst index 78128815c..5e141698f 100644 --- a/docs/piouart.rst +++ b/docs/piouart.rst @@ -12,13 +12,13 @@ are supported, as well as data sizes from 5- to 8-bits. Fifosize, if not specified, defaults to 32 bytes. To instantiate only a serial transmit or receive unit, pass in -``SerialPIO::NOPIN`` as the ``txpin`` or ``rxpin``. +``NOPIN`` as the ``txpin`` or ``rxpin``. For example, to make a transmit-only port on GP16 .. code:: cpp - SerialPIO transmitter( 16, SerialPIO::NOPIN ); + SerialPIO transmitter( 16, NOPIN ); For detailed information about the Serial ports, see the Arduino `Serial Reference `_ . diff --git a/docs/spi.rst b/docs/spi.rst index fdfd80bcc..36942d742 100644 --- a/docs/spi.rst +++ b/docs/spi.rst @@ -16,6 +16,9 @@ SPI pinouts can be set **before SPI.begin()** using the following calls: Note that the ``CS`` pin can be hardware or software controlled by the sketch. When software controlled, the ``setCS()`` call is ignored. +Passing in ``NOPIN`` to either ``setRX`` or ``setTX`` will disable SPI on that +interface, making it behave as a unidirectional (output- or input-only SPI interface. + The Arduino `SPI documentation `_ gives a detailed overview of the library, except for the following RP2040-specific changes: diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index 95935e72e..e06c8843e 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -281,6 +281,11 @@ bool SPIClassRP2040::setRX(pin_size_t pin) { return true; } + if (!_running && (pin == NOPIN)) { + _RX = pin; + return true; + } + if (_running) { panic("FATAL: Attempting to set SPI%s.RX while running", spi_get_index(_spi) ? "1" : ""); } else { @@ -362,6 +367,11 @@ bool SPIClassRP2040::setTX(pin_size_t pin) { return true; } + if (!_running && (pin == NOPIN)) { + _TX = pin; + return true; + } + if (_running) { panic("FATAL: Attempting to set SPI%s.TX while running", spi_get_index(_spi) ? "1" : ""); } else { @@ -372,13 +382,22 @@ bool SPIClassRP2040::setTX(pin_size_t pin) { void SPIClassRP2040::begin(bool hwCS) { DEBUGSPI("SPI::begin(%d), rx=%d, cs=%d, sck=%d, tx=%d\n", hwCS, _RX, _CS, _SCK, _TX); - gpio_set_function(_RX, GPIO_FUNC_SPI); + + if ((_RX == NOPIN) && (_TX == NOPIN)) { + panic("SPI%s: TX and RX assigned to NOPIN", spi_get_index(_spi) ? "1" : ""); + } + + if (_RX != NOPIN) { + gpio_set_function(_RX, GPIO_FUNC_SPI); + } _hwCS = hwCS; if (hwCS) { gpio_set_function(_CS, GPIO_FUNC_SPI); } gpio_set_function(_SCK, GPIO_FUNC_SPI); - gpio_set_function(_TX, GPIO_FUNC_SPI); + if (_TX != NOPIN) { + gpio_set_function(_TX, GPIO_FUNC_SPI); + } // Give a default config in case user doesn't use beginTransaction beginTransaction(_spis); endTransaction(); @@ -391,12 +410,16 @@ void SPIClassRP2040::end() { _initted = false; spi_deinit(_spi); } - gpio_set_function(_RX, GPIO_FUNC_SIO); + if (_RX != NOPIN) { + gpio_set_function(_RX, GPIO_FUNC_SIO); + } if (_hwCS) { gpio_set_function(_CS, GPIO_FUNC_SIO); } gpio_set_function(_SCK, GPIO_FUNC_SIO); - gpio_set_function(_TX, GPIO_FUNC_SIO); + if (_TX != NOPIN) { + gpio_set_function(_TX, GPIO_FUNC_SIO); + } _spis = SPISettings(0, LSBFIRST, SPI_MODE0); } diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 27c299bd0..8d159a8bf 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -31,21 +31,21 @@ class SPIClassRP2040 : public arduino::HardwareSPI { public: /** - @brief Create a PIO-based SPI instance, pins can be changed before begin() call + @brief Create a PIO-based SPI instance, pins can be changed before begin() call - @param [in] spi SPI hardware instance (spi0/spi1) - @param [in] rx MISO GPIO - @param [in] cs CS GPIO - @param [in] sck SCK GPIO - @param [in] tx MOSI GPIO + @param [in] spi SPI hardware instance (spi0/spi1) + @param [in] rx MISO GPIO + @param [in] cs CS GPIO + @param [in] sck SCK GPIO + @param [in] tx MOSI GPIO */ SPIClassRP2040(spi_inst_t *spi, pin_size_t rx, pin_size_t cs, pin_size_t sck, pin_size_t tx); /** - @brief Send an 8-bit byte of data and return read-back 8-bit value + @brief Send an 8-bit byte of data and return read-back 8-bit value - @param [in] data Data to send - @returns Read back byte from SPI interface + @param [in] data Data to send + @returns Read back byte from SPI interface */ byte transfer(uint8_t data) override; @@ -67,11 +67,11 @@ class SPIClassRP2040 : public arduino::HardwareSPI { void transfer(void *buf, size_t count) override; /** - @brief Sends one buffer and receives into another under a single CS. Can set rx or txbuf to nullptr + @brief Sends one buffer and receives into another under a single CS. Can set rx or txbuf to nullptr - @param [in] txbuf Buffer to transmit or nullptr to send 0s - @param [out] rxbuf Buffer to read back into or nullptr to ignore returned data - @param [in] count Numbner of bytes to transmit/receive + @param [in] txbuf Buffer to transmit or nullptr to send 0s + @param [out] rxbuf Buffer to read back into or nullptr to ignore returned data + @param [in] count Numbner of bytes to transmit/receive */ void transfer(const void *txbuf, void *rxbuf, size_t count) override; @@ -108,134 +108,134 @@ class SPIClassRP2040 : public arduino::HardwareSPI { /** - @brief Begin an SPI transaction, sets SPI speed and masks necessary interrupts + @brief Begin an SPI transaction, sets SPI speed and masks necessary interrupts - @param [in] SPISettings SPI configuration parameters, including the clock speed + @param [in] SPISettings SPI configuration parameters, including the clock speed */ void beginTransaction(SPISettings settings) override; /** - @brief Ends an SPI transaction, unmasks and masked GPIO interrupts + @brief Ends an SPI transaction, unmasks and masked GPIO interrupts */ void endTransaction(void) override; /** - @brief Sets the MISO(RX) pin. Call before begin() + @brief Sets the MISO(RX) pin. Call before begin() - @param [in] pin The GPIO number to assign to - @returns True on success + @param [in] pin The GPIO number to assign to or NOPIN + @returns True on success */ bool setRX(pin_size_t pin); /** - @brief Sets the MISO(RX) pin. Call before begin() + @brief Sets the MISO(RX) pin. Call before begin() - @param [in] pin The GPIO number to assign to - @returns True on success + @param [in] pin The GPIO number to assign to + @returns True on success */ inline bool setMISO(pin_size_t pin) { return setRX(pin); } /** - @brief Sets the CS pin. Call before begin() + @brief Sets the CS pin. Call before begin() - @param [in] pin The GPIO number to assign to - @returns True on success + @param [in] pin The GPIO number to assign to + @returns True on success */ bool setCS(pin_size_t pin); /** - @brief Sets the SCK pin. Call before begin() + @brief Sets the SCK pin. Call before begin() - @param [in] pin The GPIO number to assign to - @returns True on success + @param [in] pin The GPIO number to assign to + @returns True on success */ bool setSCK(pin_size_t pin); /** - @brief Sets the MOSI(TX) pin. Call before begin() + @brief Sets the MOSI(TX) pin. Call before begin() - @param [in] pin The GPIO number to assign to - @returns True on success + @param [in] pin The GPIO number to assign to + @returns True on success */ bool setTX(pin_size_t pin); /** - @brief Sets the MOSI(TX) pin. Call before begin() + @brief Sets the MOSI(TX) pin. Call before begin() - @param [in] pin The GPIO number to assign to - @returns True on success + @param [in] pin The GPIO number to assign to or NOPIN + @returns True on success */ inline bool setMOSI(pin_size_t pin) { return setTX(pin); } /** - @brief Call once to init/deinit SPI class, select pins, etc. + @brief Call once to init/deinit SPI class, select pins, etc. */ virtual void begin() override { begin(false); } /** - @brief Call once to init/deinit SPI class, select pins, etc. + @brief Call once to init/deinit SPI class, select pins, etc. - @param [in] hwCS Pass in true to enable HW-controlled CS. Otherwise application needs to assert/deassert CS. + @param [in] hwCS Pass in true to enable HW-controlled CS. Otherwise application needs to assert/deassert CS. */ void begin(bool hwCS); /** - @brief Call to deinit and disable the SPI interface. + @brief Call to deinit and disable the SPI interface. */ void end() override; /** - @brief Deprecated, do not use + @brief Deprecated, do not use - @param [in] order Deprecated + @param [in] order Deprecated */ void setBitOrder(BitOrder order) __attribute__((deprecated)); /** - @brief Deprecated, do not use + @brief Deprecated, do not use - @param [in] order Deprecated + @param [in] order Deprecated */ void setDataMode(uint8_t uc_mode) __attribute__((deprecated)); /** - @brief Deprecated, do not use + @brief Deprecated, do not use - @param [in] order Deprecated + @param [in] order Deprecated */ void setClockDivider(uint8_t uc_div) __attribute__((deprecated)); /** - @brief Ensure specific GPIO interrupt is disabled during and SPI transaction to protect against re-entrancy. Multiple GPIOs supported by multiple calls. + @brief Ensure specific GPIO interrupt is disabled during and SPI transaction to protect against re-entrancy. Multiple GPIOs supported by multiple calls. - @param [in] interruptNumber GPIO pin to mask + @param [in] interruptNumber GPIO pin to mask */ virtual void usingInterrupt(int interruptNumber) override { _helper.usingInterrupt(interruptNumber); } /** - @brief Remove a GPIO from the masked-during-transaction list. + @brief Remove a GPIO from the masked-during-transaction list. - @param [in] interruptNumber GPIO pin to unmask + @param [in] interruptNumber GPIO pin to unmask */ virtual void notUsingInterrupt(int interruptNumber) override { _helper.notUsingInterrupt(interruptNumber); } /** - @brief Deprecated, do not use + @brief Deprecated, do not use */ virtual void attachInterrupt() override __attribute__((deprecated)) { /* noop */ } /** - @brief Deprecated, do not use + @brief Deprecated, do not use */ virtual void detachInterrupt() override __attribute__((deprecated)) { /* noop */ }