From 9113ede2fb885ede48d55e5fbb013f548adcc891 Mon Sep 17 00:00:00 2001 From: patricklaf Date: Thu, 29 Jun 2023 16:13:43 +0200 Subject: [PATCH] Add SPI slave mode support --- libraries/SPI/src/SPI.cpp | 41 ++++++++++++++++++++--------- libraries/SPI/src/SPI.h | 17 +++++++++++- libraries/SPI/src/utility/spi_com.c | 1 - 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index eab0792182..03f727efaa 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -22,6 +22,7 @@ SPIClass::SPIClass() : _CSPinConfig(NO_CONFIG) _spi.pin_mosi = digitalPinToPinName(MOSI); _spi.pin_sclk = digitalPinToPinName(SCK); _spi.pin_ssel = NC; + _device = SPI_MASTER; } /** @@ -49,6 +50,7 @@ SPIClass::SPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel) : _spi.pin_mosi = digitalPinToPinName(mosi); _spi.pin_sclk = digitalPinToPinName(sclk); _spi.pin_ssel = digitalPinToPinName(ssel); + _device = SPI_MASTER; } /** @@ -56,20 +58,28 @@ SPIClass::SPIClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel) : * @param _pin: chip select pin (optional). If this parameter is filled, * it gives the management of the CS pin to the SPI class. In this case * do not manage the CS pin outside of the SPI class. + * @param device: device mode (optional), master or slave. Default is master. */ -void SPIClass::begin(uint8_t _pin) +void SPIClass::begin(uint8_t _pin, SPIDeviceMode device) { + _device = device; + uint8_t idx = pinIdx(_pin, ADD_NEW_PIN); if (idx >= NB_SPI_SETTINGS) { return; } if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { - pinMode(_pin, OUTPUT); - digitalWrite(_pin, HIGH); + if (_device == SPI_MASTER) { + pinMode(_pin, OUTPUT); + digitalWrite(_pin, HIGH); + } else { + pinMode(_pin, INPUT_PULLUP); + } } _spi.handle.State = HAL_SPI_STATE_RESET; + _spi.handle.Init.Mode = (_device == SPI_MASTER) ? SPI_MODE_MASTER : SPI_MODE_SLAVE; spi_init(&_spi, spiSettings[idx].clk, spiSettings[idx].dMode, spiSettings[idx].bOrder); @@ -106,10 +116,15 @@ void SPIClass::beginTransaction(uint8_t _pin, SPISettings settings) spiSettings[idx].noReceive = settings.noReceive; if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { - pinMode(_pin, OUTPUT); - digitalWrite(_pin, HIGH); + if (_device == SPI_MASTER) { + pinMode(_pin, OUTPUT); + digitalWrite(_pin, HIGH); + } else { + pinMode(_pin, INPUT_PULLUP); + } } + _spi.handle.Init.Mode = (_device == SPI_MASTER) ? SPI_MODE_MASTER : SPI_MODE_SLAVE; spi_init(&_spi, spiSettings[idx].clk, spiSettings[idx].dMode, spiSettings[idx].bOrder); @@ -244,13 +259,13 @@ byte SPIClass::transfer(uint8_t _pin, uint8_t data, SPITransferMode _mode) _CSPinConfig = _pin; } - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { + if ((_device == SPI_MASTER) && (_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { digitalWrite(_pin, LOW); } spi_transfer(&_spi, &data, &rx_buffer, sizeof(uint8_t), SPI_TRANSFER_TIMEOUT, spiSettings[idx].noReceive); - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { + if ((_device == SPI_MASTER) && (_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { digitalWrite(_pin, HIGH); } @@ -292,14 +307,14 @@ uint16_t SPIClass::transfer16(uint8_t _pin, uint16_t data, SPITransferMode _mode data = tmp; } - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { + if ((_device == SPI_MASTER) && (_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { digitalWrite(_pin, LOW); } spi_transfer(&_spi, (uint8_t *)&data, (uint8_t *)&rx_buffer, sizeof(uint16_t), SPI_TRANSFER_TIMEOUT, spiSettings[idx].noReceive); - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { + if ((_device == SPI_MASTER) && (_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { digitalWrite(_pin, HIGH); } @@ -342,14 +357,14 @@ void SPIClass::transfer(uint8_t _pin, void *_buf, size_t _count, SPITransferMode _CSPinConfig = _pin; } - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { + if ((_device == SPI_MASTER) && (_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { digitalWrite(_pin, LOW); } spi_transfer(&_spi, ((uint8_t *)_buf), ((uint8_t *)_buf), _count, SPI_TRANSFER_TIMEOUT, spiSettings[idx].noReceive); - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { + if ((_device == SPI_MASTER) && (_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { digitalWrite(_pin, HIGH); } } @@ -386,14 +401,14 @@ void SPIClass::transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, S _CSPinConfig = _pin; } - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { + if ((_device == SPI_MASTER) && (_pin != CS_PIN_CONTROLLED_BY_USER) && (_spi.pin_ssel == NC)) { digitalWrite(_pin, LOW); } spi_transfer(&_spi, ((uint8_t *)_bufout), ((uint8_t *)_bufin), _count, SPI_TRANSFER_TIMEOUT, spiSettings[idx].noReceive); - if ((_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { + if ((_device == SPI_MASTER) && (_pin != CS_PIN_CONTROLLED_BY_USER) && (_mode == SPI_LAST) && (_spi.pin_ssel == NC)) { digitalWrite(_pin, HIGH); } } diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 7bde790337..41c040c75a 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -53,6 +53,12 @@ enum SPITransferMode { SPI_LAST /* Transfer ended: CS pin released */ }; +// Device mode +enum SPIDeviceMode { + SPI_MASTER, /* Device is master */ + SPI_SLAVE /* Device is slave */ +}; + // Indicates the user controls himself the CS pin outside of the spi class #define CS_PIN_CONTROLLED_BY_USER NUM_DIGITAL_PINS @@ -148,7 +154,7 @@ class SPIClass { _spi.pin_ssel = (ssel); }; - virtual void begin(uint8_t _pin = CS_PIN_CONTROLLED_BY_USER); + virtual void begin(uint8_t _pin = CS_PIN_CONTROLLED_BY_USER, SPIDeviceMode device = SPI_MASTER); void end(void); /* This function should be used to configure the SPI instance in case you @@ -230,9 +236,18 @@ class SPIClass { return &(_spi.handle); } + void attachSlaveInterrupt(uint8_t pin, callback_function_t callback) { + ::attachInterrupt(pin, callback, FALLING); + } + + void detachSlaveInterrupt(uint8_t pin) { + ::detachInterrupt(pin); + } + protected: // spi instance spi_t _spi; + SPIDeviceMode _device; private: /* Contains various spiSettings for the same spi instance. Each spi spiSettings diff --git a/libraries/SPI/src/utility/spi_com.c b/libraries/SPI/src/utility/spi_com.c index a67813e6b7..7c45b20b7a 100644 --- a/libraries/SPI/src/utility/spi_com.c +++ b/libraries/SPI/src/utility/spi_com.c @@ -280,7 +280,6 @@ void spi_init(spi_t *obj, uint32_t speed, spi_mode_e mode, uint8_t msb) /* Fill default value */ handle->Instance = obj->spi; - handle->Init.Mode = SPI_MODE_MASTER; spi_freq = spi_getClkFreqInst(obj->spi); /* For SUBGHZSPI, 'SPI_BAUDRATEPRESCALER_*' == 'SUBGHZSPI_BAUDRATEPRESCALER_*' */