Skip to content

Commit

Permalink
Add SPI slave mode support
Browse files Browse the repository at this point in the history
  • Loading branch information
patricklaf committed Jun 29, 2023
1 parent 1c9f884 commit 9113ede
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 15 deletions.
41 changes: 28 additions & 13 deletions libraries/SPI/src/SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -49,27 +50,36 @@ 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;
}

/**
* @brief Initialize the SPI instance.
* @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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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);
}
}
Expand Down
17 changes: 16 additions & 1 deletion libraries/SPI/src/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion libraries/SPI/src/utility/spi_com.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_*' */
Expand Down

0 comments on commit 9113ede

Please sign in to comment.