diff --git a/libraries/SPI/examples/SPIMaster/SPIMaster.ino b/libraries/SPI/examples/SPIMaster/SPIMaster.ino
new file mode 100644
index 0000000000..e42552156e
--- /dev/null
+++ b/libraries/SPI/examples/SPIMaster/SPIMaster.ino
@@ -0,0 +1,205 @@
+/*
+  SPI Master
+
+  This example implements a SPI Master device for the SPI Slave example.
+  The data is transmitted to the SPI Slave and its response received back.
+
+  Every 1000ms the LED state toggles and the latest received data is printed
+  to the Serial port
+
+  The circuit:
+   * A LED to show a heartbeat signal
+   * CS - to digital pin PA4 (SS pin)
+   * SCK - to digital pin PA5 (SCK pin)
+   * MISO - to digital pin PA6 (MISO pin)
+   * MOSI - to digital pin PA7 (MOSI pin)
+
+  Default SPI pin definitions can be found at variants/STM32XXxx/<VARIANT>/variant_generic.h
+
+  created 29 Dec 2021
+  by brainelectronics
+*/
+
+#include <SPI.h>
+
+// PC13 on the Bluepill board
+#define DEBUG_LED         PC13
+
+// comment this line to disable debug output on Serial
+#define DEBUG_OUTPUT
+
+// amount of data to be sent to the SPI Slave device
+#define BUFFER_SIZE       8
+
+uint8_t TX_Buffer[BUFFER_SIZE] = {0};
+uint8_t RX_Buffer[BUFFER_SIZE] = {0};
+uint8_t up_counter = 0;   //< data to be transmitted
+
+uint32_t prevTime = 0;    //< previous timestamp of printing received data
+uint32_t interval = 1000; //< [ms] interval at which to print received data
+
+spi_t _spi;
+
+void setup() {
+  // put your setup code here, to run once:
+  pinMode(DEBUG_LED, OUTPUT);
+
+  // setup serial communication at 115200 baud
+  Serial.begin(115200);
+
+  // setup SPI interface
+  setup_spi();
+}
+
+void setup_spi() {
+  uint32_t clk = SPI_SPEED_CLOCK_DEFAULT;
+
+  // communicating at full clock speed might not work
+  // check the documentation at system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c
+  clk = spi_getClkFreq(&_spi) / SPI_CLOCK_DIV16;
+
+#ifdef DEBUG_OUTPUT
+  Serial.printf("PCLK: %d Hz\n", HAL_RCC_GetPCLK2Freq());
+  // e.g. 48.000.000 Hz if running on the internal oscillator
+  Serial.printf("SPI CLK: %d Hz\n", clk);
+  // becomes 3.000.000 Hz in case PCLK is 48MHz and SPI_CLOCK_DIV16 is used
+#endif
+
+  // set the default CS pin as an output
+  pinMode(PIN_SPI_SS, OUTPUT);
+
+  _spi.pin_mosi = digitalPinToPinName(PIN_SPI_MOSI);
+  _spi.pin_miso = digitalPinToPinName(PIN_SPI_MISO);
+  _spi.pin_sclk = digitalPinToPinName(PIN_SPI_SCK);
+  _spi.pin_ssel = NC;      // in send_and_receive_data function
+
+  _spi.mode = SPI_MASTER;  //< master mode
+
+  _spi.handle.State = HAL_SPI_STATE_RESET;
+
+  spi_init(&_spi, clk, SPI_MODE_0, MSBFIRST);
+
+#ifdef DEBUG_OUTPUT
+  Serial.printf("SPI State: %d\n", _spi.handle.State);
+  // should be in state "1": Peripheral Initialized and ready for use
+#endif
+}
+
+void loop() {
+  uint32_t now = millis();
+
+  if (now > (prevTime + interval))
+  {
+    // save the last time the data has been printed
+    prevTime = now;
+
+    // toggle the LED state
+    digitalWrite(DEBUG_LED, !digitalRead(DEBUG_LED));
+
+#ifdef DEBUG_OUTPUT
+    Serial.printf("HAL_SPI_GetError: %d\n", HAL_SPI_GetError(&(_spi.handle)));
+    Serial.printf("SPI State: %d\n", _spi.handle.State);
+#endif
+
+    // increment counter. This value will be sent to the SPI slave device
+    up_counter++;
+
+    // reset value to zero, just to be save
+    if (up_counter >= 255) {
+      up_counter = 0;
+    }
+
+    // to only send data to the slave device use this function
+    // send_data_to_slave(up_counter);
+
+    // to send data and read the slave device response use this function
+    send_and_receive_data(up_counter);
+  }
+}
+
+void send_data_to_slave(uint8_t data) {
+  uint8_t tmp_data_rx = 0;
+
+  // take the SS pin low to select the chip
+  digitalWrite(PIN_SPI_SS, LOW);
+
+  // transfer the given data 8 times in a row to slave -> Slave BUFFER_SIZE = 8
+  // [1, 1, 1, 1, 1, 1, 1, 1]
+  for (uint8_t i = 0; i < 8; i++)
+  {
+    spi_transfer(&_spi,
+                 &data,
+                 &tmp_data_rx,
+                 sizeof(uint8_t),
+                 SPI_TRANSFER_TIMEOUT,
+                 SPI_TRANSMITONLY);
+  }
+
+  // take the SS pin high to de-select the chip
+  digitalWrite(PIN_SPI_SS, HIGH);
+}
+
+void send_and_receive_data(uint8_t data) {
+  uint8_t tmp_data_rx = 0;
+  uint8_t tmp_data_tx = 0;
+
+  for (uint8_t i = 0; i < BUFFER_SIZE; i++)
+  {
+    TX_Buffer[i] = data + i;
+  }
+  // e.g. [1, 2, 3, 4, 5, 6, 7, 8] if data = 1
+
+  Serial.print("Send data to Slave: ");
+  for (uint8_t i = 0; i < BUFFER_SIZE; i++)
+  {
+    Serial.printf("%d, ", TX_Buffer[i]);
+  }
+  Serial.println();
+
+  // take the CS pin low to select the Slave device
+  digitalWrite(PIN_SPI_SS, LOW);
+
+  for (uint8_t i = 0; i < BUFFER_SIZE; i++)
+  {
+    tmp_data_tx = TX_Buffer[i];
+    spi_transfer(&_spi,
+                 &tmp_data_tx,
+                 &tmp_data_rx,
+                 sizeof(uint8_t),
+                 SPI_TRANSFER_TIMEOUT,
+                 SPI_TRANSMITONLY);
+  }
+
+  // Serial print on slave requires approx. 1 ms
+  // wait for that amount of time until dummy data is sent to the slave in
+  // order to provide a CLK signal for the response of the slave device
+#ifdef DEBUG_OUTPUT
+  delay(2);
+#else
+  delay(1);
+#endif
+
+  tmp_data_tx = 0x0; // dummy data
+  for (uint8_t i = 0; i < BUFFER_SIZE; i++)
+  {
+    spi_transfer(&_spi,
+                 &tmp_data_tx,
+                 &tmp_data_rx,
+                 sizeof(uint8_t),
+                 SPI_TRANSFER_TIMEOUT,
+                 SPI_TRANSMITRECEIVE);
+    RX_Buffer[i] = tmp_data_rx;
+  }
+
+  // take the SS pin high to de-select the slave device again
+  digitalWrite(PIN_SPI_SS, HIGH);
+
+  Serial.print("Received data from Slave: ");
+  for (uint8_t i = 0; i < BUFFER_SIZE; i++)
+  {
+    Serial.printf("%d, ", RX_Buffer[i]);
+    RX_Buffer[i] = 0; // clear buffer entry
+  }
+  // e.g. [2, 3, 4, 5, 6, 7, 8, 9] if data = 1
+  Serial.println();
+}
diff --git a/libraries/SPI/examples/SPISlave/SPISlave.ino b/libraries/SPI/examples/SPISlave/SPISlave.ino
new file mode 100644
index 0000000000..b09fc6965d
--- /dev/null
+++ b/libraries/SPI/examples/SPISlave/SPISlave.ino
@@ -0,0 +1,167 @@
+/*
+  SPI Slave
+
+  This example implements a SPI Slave device for the SPI Master example.
+  The data is received from the SPI Master, incremented by one and sent back.
+
+  Every 1000ms the LED state toggles and the latest received data is printed
+  to the Serial port
+
+  The circuit:
+   * A LED to show a heartbeat signal
+   * CS - to digital pin PA4 (SS pin)
+   * SCK - to digital pin PA5 (SCK pin)
+   * MISO - to digital pin PA6 (MISO pin)
+   * MOSI - to digital pin PA7 (MOSI pin)
+
+  Default SPI pin definitions can be found at variants/STM32XXxx/<VARIANT>/variant_generic.h
+
+  created 29 Dec 2021
+  by brainelectronics
+*/
+
+#include <SPI.h>
+
+// PC13 on the Bluepill board
+#define DEBUG_LED         PC13
+
+// comment this line to disable debug output on Serial
+#define DEBUG_OUTPUT
+
+// amount of data being sent by the SPI Master device
+#define BUFFER_SIZE       8
+
+uint8_t RX_Buffer[BUFFER_SIZE] = {0};
+
+uint32_t prevTime = 0;    //< previous timestamp of printing received data
+uint32_t interval = 1000; //< [ms] interval at which to print received data
+
+volatile uint32_t tmpCounterRx = 0, tmpCounterTx = 0;
+
+spi_t _spi;
+
+void setup() {
+  // put your setup code here, to run once:
+  pinMode(DEBUG_LED, OUTPUT);
+
+  // setup serial communication at 115200 baud
+  Serial.begin(115200);
+
+  // wait for 1 second in order to let the Master be ready before the slave
+  delay(1000);
+
+  // setup SPI interface
+  setup_spi();
+}
+
+void setup_spi() {
+  uint32_t clk = SPI_SPEED_CLOCK_DEFAULT;
+
+  // communicating at full clock speed might not work
+  // check the documentation at system/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c
+  clk = spi_getClkFreq(&_spi) / SPI_CLOCK_DIV16;
+
+#ifdef DEBUG_OUTPUT
+  Serial.printf("PCLK: %d Hz\n", HAL_RCC_GetPCLK2Freq());
+  // e.g. 48.000.000 Hz if running on the internal oscillator
+  Serial.printf("SPI CLK: %d Hz\n", clk);
+  // becomes 3.000.000 Hz in case PCLK is 48MHz and SPI_CLOCK_DIV16 is used
+#endif
+
+  // set the default CS pin as an input
+  pinMode(PIN_SPI_SS, INPUT);
+
+  _spi.pin_mosi = digitalPinToPinName(PIN_SPI_MOSI);
+  _spi.pin_miso = digitalPinToPinName(PIN_SPI_MISO);
+  _spi.pin_sclk = digitalPinToPinName(PIN_SPI_SCK);
+  _spi.pin_ssel = NC;       // set later manually
+
+  _spi.mode = SPI_SLAVE;    //< slave mode
+
+  _spi.handle.State = HAL_SPI_STATE_RESET;
+
+  spi_init(&_spi, clk, SPI_MODE_0, MSBFIRST);
+
+#ifdef DEBUG_OUTPUT
+  Serial.printf("SPI State: %d\n", _spi.handle.State);
+  // should be in state "1": Peripheral Initialized and ready for use
+#endif
+
+  // attach an interrupt as last step to avoid calls before a full SPI setup
+
+  // to receive only data from a Master, use the "receive_data" function
+  // attachInterrupt(PIN_SPI_SS, receive_data, FALLING);
+
+  // to receive data and transmit a response back to the Master use this
+  attachInterrupt(PIN_SPI_SS, receive_and_respond_data, FALLING);
+}
+
+void loop() {
+  uint32_t now = millis();
+
+  if (now > (prevTime + interval))
+  {
+    // save the last time the data has been printed
+    prevTime = now;
+
+    // toggle the LED state
+    digitalWrite(DEBUG_LED, !digitalRead(DEBUG_LED));
+
+#ifdef DEBUG_OUTPUT
+    Serial.printf("HAL_SPI_GetError: %d\n", HAL_SPI_GetError(&(_spi.handle)));
+    Serial.printf("SPI State: %d\n", _spi.handle.State);
+    Serial.printf("RX Counter: %d\n", tmpCounterRx);
+    Serial.printf("TX Counter: %d\n", tmpCounterTx);
+#endif
+
+    // print the data in the received buffer in DEC format
+    for (uint8_t i = 0; i < BUFFER_SIZE; i++)
+    {
+      Serial.printf("%d, ", RX_Buffer[i]);
+      RX_Buffer[i] = 0; // clear buffer entry
+    }
+    Serial.println();
+  }
+}
+
+void receive_data()
+{
+  // put received data from SPI into the RX_Buffer
+  // return from function if no data is received within 10 ticks (10 ms)
+  HAL_SPI_Receive(&(_spi.handle), RX_Buffer, sizeof(RX_Buffer), 10);
+  tmpCounterRx++;
+
+  // this is for demo purpose only, try to keep IRQ functions short and quick
+#ifdef DEBUG_OUTPUT
+  // print received data directly after receiving it
+  for (uint8_t i = 0; i < BUFFER_SIZE; i++)
+  {
+    Serial.printf("%d, ", RX_Buffer[i]);
+  }
+  Serial.println();
+#endif
+}
+
+void receive_and_respond_data()
+{
+  // put received data from SPI into the RX_Buffer
+  // return from function if no data is received within 10 ticks (10 ms)
+  HAL_SPI_Receive(&(_spi.handle), RX_Buffer, sizeof(RX_Buffer), 10);
+  tmpCounterRx++;
+  // e.g. [1, 2, 3, 4, 5, 6, 7, 8]
+
+  // response data shall be available as soon as possible
+  // avoid long intermediate processing or other functions
+  uint8_t TX_Buffer[BUFFER_SIZE] = {0};
+  for (uint8_t i = 0; i < BUFFER_SIZE; i++)
+  {
+    // create response message, which is the received data + 1
+    TX_Buffer[i] = RX_Buffer[i] + 1;
+  }
+  // e.g. [2, 3, 4, 5, 6, 7, 8, 9]
+
+  // send response as the data of the TX_Buffer to the SPI Master
+  // return from function within 10 ticks (10 ms)
+  HAL_SPI_Transmit(&(_spi.handle), TX_Buffer, sizeof(TX_Buffer), 10);
+  tmpCounterTx++;
+}
diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp
index 0d836a0295..0e7a47afd1 100644
--- a/libraries/SPI/src/SPI.cpp
+++ b/libraries/SPI/src/SPI.cpp
@@ -69,6 +69,7 @@ void SPIClass::begin(uint8_t _pin)
     digitalWrite(_pin, HIGH);
   }
 
+  _spi.mode = SPI_MASTER;
   _spi.handle.State = HAL_SPI_STATE_RESET;
   spi_init(&_spi, spiSettings[idx].clk,
            spiSettings[idx].dMode,
diff --git a/libraries/SPI/src/utility/spi_com.c b/libraries/SPI/src/utility/spi_com.c
index 32d46261dc..3eb371444f 100644
--- a/libraries/SPI/src/utility/spi_com.c
+++ b/libraries/SPI/src/utility/spi_com.c
@@ -256,7 +256,11 @@ 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;
+  if (obj->mode == SPI_SLAVE) {
+    handle->Init.Mode              = SPI_MODE_SLAVE;
+  } else {
+    handle->Init.Mode              = SPI_MODE_MASTER;
+  }
 
   spi_freq = spi_getClkFreqInst(obj->spi);
   if (speed >= (spi_freq / SPI_SPEED_CLOCK_DIV2_MHZ)) {
diff --git a/libraries/SPI/src/utility/spi_com.h b/libraries/SPI/src/utility/spi_com.h
index daba244b4c..788565abdf 100644
--- a/libraries/SPI/src/utility/spi_com.h
+++ b/libraries/SPI/src/utility/spi_com.h
@@ -49,6 +49,12 @@ extern "C" {
 
 /* Exported types ------------------------------------------------------------*/
 
+///@brief SPI device modes
+typedef enum {
+  SPI_SLAVE = 0,
+  SPI_MASTER = 1
+} spi_device_mode_e;
+
 struct spi_s {
   SPI_HandleTypeDef handle;
   SPI_TypeDef *spi;
@@ -56,6 +62,7 @@ struct spi_s {
   PinName pin_mosi;
   PinName pin_sclk;
   PinName pin_ssel;
+  spi_device_mode_e mode;
 #if defined(SPI_IFCR_EOTC)
   // Delay before disabling SPI.
   // See https://github.com/stm32duino/Arduino_Core_STM32/issues/1294