diff --git a/cmake/boardcore.cmake b/cmake/boardcore.cmake
index 2d773978aa5dbfcdb7770a23a6ab0360cc89e521..67d81def893634f62166f1eba206c1ce2006c448 100644
--- a/cmake/boardcore.cmake
+++ b/cmake/boardcore.cmake
@@ -60,6 +60,7 @@ set(BOARDCORE_SRC
     ${BOARDCORE_PATH}/src/shared/drivers/timer/PWM.cpp
     ${BOARDCORE_PATH}/src/shared/drivers/timer/CountedPWM.cpp
     ${BOARDCORE_PATH}/src/shared/drivers/runcam/Runcam.cpp
+    ${BOARDCORE_PATH}/src/shared/drivers/spi/SPISlave.cpp
     ${BOARDCORE_PATH}/src/shared/drivers/spi/SPITransaction.cpp
     ${BOARDCORE_PATH}/src/shared/drivers/usart/USART.cpp
     ${BOARDCORE_PATH}/src/shared/drivers/i2c/I2CDriver-f4.cpp
diff --git a/src/shared/drivers/WIZ5500/WIZ5500.cpp b/src/shared/drivers/WIZ5500/WIZ5500.cpp
index 89577709c24e8bfdda532bf808b08bb9a85eba0c..073b8235d052e26096448711145dba83dba8d32e 100644
--- a/src/shared/drivers/WIZ5500/WIZ5500.cpp
+++ b/src/shared/drivers/WIZ5500/WIZ5500.cpp
@@ -632,11 +632,11 @@ void Wiz5500::spiRead(uint8_t block, uint16_t address, uint8_t *data,
     // Do a manual SPI transaction
     slave.bus.configure(slave.config);
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write16(address);
     slave.bus.write(Wiz::buildControlWord(block, false));
     slave.bus.read(data, len);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void Wiz5500::spiWrite(uint8_t block, uint16_t address, const uint8_t *data,
@@ -645,11 +645,11 @@ void Wiz5500::spiWrite(uint8_t block, uint16_t address, const uint8_t *data,
     // Do a manual SPI transaction
     slave.bus.configure(slave.config);
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write16(address);
     slave.bus.write(Wiz::buildControlWord(block, true));
     slave.bus.write(data, len);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 uint8_t Wiz5500::spiRead8(uint8_t block, uint16_t address)
diff --git a/src/shared/drivers/spi/SPIBus.h b/src/shared/drivers/spi/SPIBus.h
index ef71a7d4c52e00ca0eda587308651b7ee2f6c676..2d6d05e39474a7c19b7425e680cf7988002df0d6 100644
--- a/src/shared/drivers/spi/SPIBus.h
+++ b/src/shared/drivers/spi/SPIBus.h
@@ -144,16 +144,6 @@ public:
      */
     void configure(SPIBusConfig newConfig) override;
 
-    /**
-     * @brief See SPIBusInterface::select().
-     */
-    void select(GpioType cs) override;
-
-    /**
-     * @brief See SPIBusInterface::deselect().
-     */
-    void deselect(GpioType cs) override;
-
     // Read, write and transfer operations
 
     /**
@@ -446,26 +436,6 @@ inline void SPIBus::configure(SPIBusConfig newConfig)
     }
 }
 
-inline void SPIBus::select(GpioType cs)
-{
-    cs.low();
-
-    if (config.csSetupTimeUs > 0)
-    {
-        miosix::delayUs(config.csSetupTimeUs);
-    }
-}
-
-inline void SPIBus::deselect(GpioType cs)
-{
-    if (config.csHoldTimeUs > 0)
-    {
-        miosix::delayUs(config.csHoldTimeUs);
-    }
-
-    cs.high();
-}
-
 inline uint8_t SPIBus::read() { return transfer(0); }
 
 inline uint16_t SPIBus::read16() { return transfer16(0); }
diff --git a/src/shared/drivers/spi/SPIBusInterface.h b/src/shared/drivers/spi/SPIBusInterface.h
index ff501c21903e5f27f5e54598c6f10366c667f608..8a69d04e95cdf1def25ab784f3627f23fff99ad6 100644
--- a/src/shared/drivers/spi/SPIBusInterface.h
+++ b/src/shared/drivers/spi/SPIBusInterface.h
@@ -134,20 +134,6 @@ public:
      */
     virtual void configure(SPIBusConfig config) = 0;
 
-    /**
-     * @brief Selects the slave.
-     *
-     * @param cs Chip select pin for the slave.
-     */
-    virtual void select(GpioType cs) = 0;
-
-    /**
-     * @brief Deselects the slave.
-     *
-     * @param cs Chip select pin for the slave.
-     */
-    virtual void deselect(GpioType cs) = 0;
-
     // Read, write and transfer operations
 
     /**
@@ -287,63 +273,4 @@ public:
     virtual void transfer16(uint16_t* data, size_t size) = 0;
 };
 
-/**
- * @brief Contains information about a single SPI slave device.
- */
-struct SPISlave
-{
-    SPIBusInterface& bus;  ///< Bus on which the slave is connected.
-    SPIBusConfig config;   ///< How the bus should be configured to communicate
-                           ///< with the slave.
-    GpioType cs;           ///< Chip select pin
-
-    SPISlave(SPIBusInterface& bus, GpioType cs, SPIBusConfig config = {})
-        : bus(bus), config(config), cs(cs)
-    {
-    }
-};
-
-/**
- * @brief RAII Interface for SPI bus acquisition
- *
- */
-class SPIAcquireLock
-{
-public:
-    explicit SPIAcquireLock(SPISlave slave)
-        : SPIAcquireLock(slave.bus, slave.config)
-    {
-    }
-
-    SPIAcquireLock(SPIBusInterface& bus, SPIBusConfig cfg) : bus(bus)
-    {
-        bus.configure(cfg);
-    }
-
-private:
-    SPIBusInterface& bus;
-};
-
-/**
- * @brief RAII Interface for SPI chip selection.
- */
-class SPISelectLock
-{
-public:
-    explicit SPISelectLock(SPISlave slave) : SPISelectLock(slave.bus, slave.cs)
-    {
-    }
-
-    SPISelectLock(SPIBusInterface& bus, GpioType cs) : bus(bus), cs(cs)
-    {
-        bus.select(cs);
-    }
-
-    ~SPISelectLock() { bus.deselect(cs); }
-
-private:
-    SPIBusInterface& bus;
-    GpioType& cs;
-};
-
 }  // namespace Boardcore
diff --git a/src/shared/drivers/spi/SPISlave.cpp b/src/shared/drivers/spi/SPISlave.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..122e31dfe038ddda2f61580199e20a3631d7d638
--- /dev/null
+++ b/src/shared/drivers/spi/SPISlave.cpp
@@ -0,0 +1,124 @@
+/* Copyright (c) 2024 Skyward Experimental Rocketry
+ * Author: Niccolò Betto
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "SPISlave.h"
+
+#include <miosix.h>
+
+namespace Boardcore
+{
+
+SPISlave::SlaveSelect SPISlave::SlaveSelect::MuxSelect(GpioType s0, GpioType s1,
+                                                       GpioType s2,
+                                                       uint8_t value)
+{
+    return SlaveSelect{
+        .type = Type::MUX,
+        .data =
+            {
+                .mux =
+                    {
+                        .s0    = s0,
+                        .s1    = s1,
+                        .s2    = s2,
+                        .value = value,
+                    },
+            },
+    };
+}
+
+SPISlave::SlaveSelect SPISlave::SlaveSelect::PinSelect(GpioType cs)
+{
+    return SlaveSelect{
+        .type = Type::CS,
+        .data =
+            {
+                .cs = cs,
+            },
+    };
+}
+
+void SPISlave::SlaveSelect::select()
+{
+    switch (type)
+    {
+        case Type::CS:
+            data.cs.low();
+            break;
+
+        case Type::MUX:
+            if (data.mux.value & 0b001)
+                data.mux.s0.high();
+            else
+                data.mux.s0.low();
+
+            if (data.mux.value & 0b010)
+                data.mux.s1.high();
+            else
+                data.mux.s1.low();
+
+            if (data.mux.value & 0b100)
+                data.mux.s2.high();
+            else
+                data.mux.s2.low();
+
+            break;
+    }
+}
+
+void SPISlave::SlaveSelect::deselect()
+{
+    switch (type)
+    {
+        case Type::CS:
+            data.cs.high();
+            break;
+
+        case Type::MUX:
+            data.mux.s0.low();
+            data.mux.s1.low();
+            data.mux.s2.low();
+
+            break;
+    }
+}
+
+void SPISlave::select()
+{
+    cs.select();
+
+    if (config.csSetupTimeUs > 0)
+    {
+        miosix::delayUs(config.csSetupTimeUs);
+    }
+}
+
+void SPISlave::deselect()
+{
+    if (config.csHoldTimeUs > 0)
+    {
+        miosix::delayUs(config.csHoldTimeUs);
+    }
+
+    cs.deselect();
+}
+}  // namespace Boardcore
\ No newline at end of file
diff --git a/src/shared/drivers/spi/SPISlave.h b/src/shared/drivers/spi/SPISlave.h
new file mode 100644
index 0000000000000000000000000000000000000000..7cd49fd1b81003a47b994f143a5f86c2d42162be
--- /dev/null
+++ b/src/shared/drivers/spi/SPISlave.h
@@ -0,0 +1,133 @@
+/* Copyright (c) 2024 Skyward Experimental Rocketry
+ * Author: Niccolò Betto
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "SPIBusInterface.h"
+
+namespace Boardcore
+{
+
+/**
+ * @brief Contains information about a single SPI slave device.
+ */
+struct SPISlave
+{
+private:
+    struct SlaveSelect
+    {
+        enum class Type
+        {
+            CS,
+            MUX
+        } type;
+
+        union
+        {
+            // Type::CS
+            GpioType cs;
+
+            // Type::MUX
+            struct
+            {
+                GpioType s0;
+                GpioType s1;
+                GpioType s2;
+                uint8_t value;
+            } mux;
+        } data;
+
+        /**
+         * @brief Creates a multiplexer slave select object.
+         */
+        static SlaveSelect MuxSelect(GpioType s0, GpioType s1, GpioType s2,
+                                     uint8_t value);
+
+        /**
+         * @brief Creates a single pin slave select object.
+         */
+        static SlaveSelect PinSelect(GpioType cs);
+
+        void select();
+
+        void deselect();
+    };
+
+public:
+    SPIBusInterface& bus;  ///< Bus on which the slave is connected.
+    SPIBusConfig config;   ///< How the bus should be configured to
+                           ///< communicate with the slave.
+    SlaveSelect cs;        ///< Chip select of the slave.
+
+    SPISlave(SPIBusInterface& bus, GpioType cs, SPIBusConfig config = {})
+        : bus(bus), config(config), cs(SlaveSelect::PinSelect(cs))
+    {
+    }
+
+    SPISlave(SPIBusInterface& bus, GpioType s0, GpioType s1, GpioType s2,
+             uint8_t value, SPIBusConfig config = {})
+        : bus(bus), config(config),
+          cs(SlaveSelect::MuxSelect(s0, s1, s2, value))
+    {
+    }
+
+    void configureBus() { bus.configure(config); }
+
+    void select();
+
+    void deselect();
+};
+
+/**
+ * @brief RAII Interface for SPI chip selection.
+ */
+class SPISelectLock
+{
+public:
+    explicit SPISelectLock(SPISlave& slave) : slave(slave) { slave.select(); }
+
+    ~SPISelectLock() { slave.deselect(); }
+
+private:
+    SPISlave& slave;
+};
+
+/**
+ * @brief RAII Interface for SPI bus configuration and slave selection.
+ *
+ * Bus configuration must happen before selection to ensure that the bus is
+ * ready for communication. Here, configuration is performed in the
+ * initializer list by taking advantage of the comma operator.
+ */
+class SPIAcquireLock
+{
+public:
+    explicit SPIAcquireLock(SPISlave& slave)
+        : sel((slave.configureBus(), slave))
+    {
+    }
+
+private:
+    SPISelectLock sel;
+};
+
+}  // namespace Boardcore
diff --git a/src/shared/drivers/spi/SPITransaction.cpp b/src/shared/drivers/spi/SPITransaction.cpp
index d330ff14a49cbf181fdaa2dcddc05284890bc33f..b1ff7d783f21b2695c7c69a564147837ec89a7a6 100644
--- a/src/shared/drivers/spi/SPITransaction.cpp
+++ b/src/shared/drivers/spi/SPITransaction.cpp
@@ -27,7 +27,7 @@
 namespace Boardcore
 {
 
-SPITransaction::SPITransaction(const SPISlave& slave) : slave(slave)
+SPITransaction::SPITransaction(SPISlave& slave) : slave(slave)
 {
     slave.bus.configure(slave.config);
 }
@@ -38,142 +38,142 @@ SPIBusInterface& SPITransaction::getBus() { return slave.bus; }
 
 uint8_t SPITransaction::read()
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     uint8_t data = slave.bus.read();
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     return data;
 }
 
 uint16_t SPITransaction::read16()
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     uint16_t data = slave.bus.read16();
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     return data;
 }
 
 uint32_t SPITransaction::read24()
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     uint32_t data = slave.bus.read24();
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
     return data;
 }
 
 uint32_t SPITransaction::read32()
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     uint32_t data = slave.bus.read32();
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
     return data;
 }
 
 void SPITransaction::read(uint8_t* data, size_t size)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.read(data, size);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::read16(uint16_t* data, size_t size)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.read16(data, size);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::write(uint8_t data)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::write16(uint16_t data)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write16(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::write24(uint32_t data)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write24(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::write32(uint32_t data)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write32(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::write(uint8_t* data, size_t size)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(data, size);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::write16(uint16_t* data, size_t size)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write16(data, size);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 uint8_t SPITransaction::transfer(uint8_t data)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     data = slave.bus.transfer(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     return data;
 }
 
 uint16_t SPITransaction::transfer16(uint16_t data)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     data = slave.bus.transfer16(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     return data;
 }
 
 uint32_t SPITransaction::transfer24(uint32_t data)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     data = slave.bus.transfer24(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     return data;
 }
 
 uint32_t SPITransaction::transfer32(uint32_t data)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     data = slave.bus.transfer32(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     return data;
 }
 
 void SPITransaction::transfer(uint8_t* data, size_t size)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.transfer(data, size);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::transfer16(uint16_t* data, size_t size)
 {
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.transfer16(data, size);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 // Read, write and transfer operations with registers
@@ -183,10 +183,10 @@ uint8_t SPITransaction::readRegister(uint8_t reg)
     if (slave.config.writeBit == SPI::WriteBit::NORMAL)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     uint8_t data = slave.bus.read();
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     return data;
 }
@@ -196,10 +196,10 @@ uint16_t SPITransaction::readRegister16(uint8_t reg)
     if (slave.config.writeBit == SPI::WriteBit::NORMAL)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     uint16_t data = slave.bus.read16();
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     if (slave.config.byteOrder == SPI::Order::LSB_FIRST)
         data = swapBytes16(data);
@@ -212,10 +212,10 @@ uint32_t SPITransaction::readRegister24(uint8_t reg)
     if (slave.config.writeBit == SPI::WriteBit::NORMAL)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     uint32_t data = slave.bus.read24();
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     if (slave.config.byteOrder == SPI::Order::LSB_FIRST)
         data = swapBytes32(data) >> 8;
@@ -228,10 +228,10 @@ uint32_t SPITransaction::readRegister32(uint8_t reg)
     if (slave.config.writeBit == SPI::WriteBit::NORMAL)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     uint32_t data = slave.bus.read32();
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 
     if (slave.config.byteOrder == SPI::Order::LSB_FIRST)
         data = swapBytes32(data) >> 8;
@@ -244,10 +244,10 @@ void SPITransaction::readRegisters(uint8_t reg, uint8_t* data, size_t size)
     if (slave.config.writeBit == SPI::WriteBit::NORMAL)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     slave.bus.read(data, size);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::writeRegister(uint8_t reg, uint8_t data)
@@ -255,10 +255,10 @@ void SPITransaction::writeRegister(uint8_t reg, uint8_t data)
     if (slave.config.writeBit == SPI::WriteBit::INVERTED)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     slave.bus.write(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::writeRegister16(uint8_t reg, uint16_t data)
@@ -266,10 +266,10 @@ void SPITransaction::writeRegister16(uint8_t reg, uint16_t data)
     if (slave.config.writeBit == SPI::WriteBit::INVERTED)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     slave.bus.write16(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::writeRegister24(uint8_t reg, uint32_t data)
@@ -277,10 +277,10 @@ void SPITransaction::writeRegister24(uint8_t reg, uint32_t data)
     if (slave.config.writeBit == SPI::WriteBit::INVERTED)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     slave.bus.write24(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::writeRegister32(uint8_t reg, uint32_t data)
@@ -288,10 +288,10 @@ void SPITransaction::writeRegister32(uint8_t reg, uint32_t data)
     if (slave.config.writeBit == SPI::WriteBit::INVERTED)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     slave.bus.write32(data);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 void SPITransaction::writeRegisters(uint8_t reg, uint8_t* data, size_t size)
@@ -299,10 +299,10 @@ void SPITransaction::writeRegisters(uint8_t reg, uint8_t* data, size_t size)
     if (slave.config.writeBit == SPI::WriteBit::INVERTED)
         reg |= 0x80;
 
-    slave.bus.select(slave.cs);
+    slave.select();
     slave.bus.write(reg);
     slave.bus.write(data, size);
-    slave.bus.deselect(slave.cs);
+    slave.deselect();
 }
 
 }  // namespace Boardcore
diff --git a/src/shared/drivers/spi/SPITransaction.h b/src/shared/drivers/spi/SPITransaction.h
index 10606d8403c648c45ef9487db7a5adf10de6ad59..96c2c0729ca4038bfc69f46a9e6ee42e78f87a2f 100644
--- a/src/shared/drivers/spi/SPITransaction.h
+++ b/src/shared/drivers/spi/SPITransaction.h
@@ -23,6 +23,7 @@
 #pragma once
 
 #include "SPIBusInterface.h"
+#include "SPISlave.h"
 
 namespace Boardcore
 {
@@ -62,7 +63,7 @@ public:
      *
      * @param slave Slave to communicate with.
      */
-    explicit SPITransaction(const SPISlave &slave);
+    explicit SPITransaction(SPISlave &slave);
 
     // /**
     //  * @brief Instantiates a new SPITransaction, configuring the bus with the
@@ -305,7 +306,7 @@ public:
     void writeRegisters(uint8_t reg, uint8_t *data, size_t size);
 
 private:
-    const SPISlave &slave;
+    SPISlave &slave;
 };
 
 }  // namespace Boardcore
diff --git a/src/shared/radio/Xbee/Xbee.cpp b/src/shared/radio/Xbee/Xbee.cpp
index 1f698c1ee15f8d2880532da8bc80638871de4665..0e4d2ae832c704b78d432f263b1d6a57288503ec 100644
--- a/src/shared/radio/Xbee/Xbee.cpp
+++ b/src/shared/radio/Xbee/Xbee.cpp
@@ -184,10 +184,8 @@ void Xbee::reset()
         // Assert SSEL on every iteration as we don't exactly know when the
         // xbee will be ready.
         {
-            SPIAcquireLock acq(spiXbee);
-            spiXbee.cs.low();
+            SPIAcquireLock sel(spiXbee);
             miosix::delayUs(10);
-            spiXbee.cs.high();
         }
 
         miosix::delayUs(50);
diff --git a/src/shared/sensors/ADS1118/ADS1118.h b/src/shared/sensors/ADS1118/ADS1118.h
index 828cdc9bb08024c3a933e0714ac6f2e505afa24c..9dd598da46ba2aa6461b6e214399c6649ef64625 100644
--- a/src/shared/sensors/ADS1118/ADS1118.h
+++ b/src/shared/sensors/ADS1118/ADS1118.h
@@ -309,7 +309,7 @@ private:
 
     int8_t findNextEnabledChannel(int8_t startChannel);
 
-    const SPISlave spiSlave;
+    SPISlave spiSlave;
     ADS1118Config baseConfig;
 
     ///< Read the written configuration on each transaction and checks it
diff --git a/src/shared/sensors/BME280/BME280.h b/src/shared/sensors/BME280/BME280.h
index 99cdb4017719ec3396a10de5c35addc3c01218c2..e62308b088c7ec55f9c3f19bac9fc95f00afde8e 100644
--- a/src/shared/sensors/BME280/BME280.h
+++ b/src/shared/sensors/BME280/BME280.h
@@ -295,7 +295,7 @@ private:
         REG_HUM_LSB    = 0x7E,
     };
 
-    const SPISlave spiSlave;
+    SPISlave spiSlave;
     BME280Config config;
     BME280Comp compParams;
     int32_t fineTemperature;  // Used in compensation algorithm
diff --git a/src/shared/sensors/BMP280/BMP280.h b/src/shared/sensors/BMP280/BMP280.h
index 3b7abf775d1d0cd9aa930891d61729cf15f8f2cd..aa93f66247677d9a7457004bc08acb81ad78fbd7 100644
--- a/src/shared/sensors/BMP280/BMP280.h
+++ b/src/shared/sensors/BMP280/BMP280.h
@@ -264,7 +264,7 @@ private:
         REG_TEMP_XLSB  = 0x7C
     };
 
-    const SPISlave spiSlave;
+    SPISlave spiSlave;
     BMP280Config config;
     BMP280Comp compParams;
     int32_t fineTemperature;  // Used in compensation algorithm
diff --git a/src/shared/sensors/MAX6675/MAX6675.h b/src/shared/sensors/MAX6675/MAX6675.h
index 743a46fc8b33a53ca760cb10641462d9eef6e887..0c0df7e6c72719ac065488b62a91581a5a6abc0e 100644
--- a/src/shared/sensors/MAX6675/MAX6675.h
+++ b/src/shared/sensors/MAX6675/MAX6675.h
@@ -59,7 +59,7 @@ protected:
     TemperatureData sampleImpl() override;
 
 private:
-    const SPISlave slave;
+    SPISlave slave;
 
     PrintLogger logger = Logging::getLogger("max6675");
 };
diff --git a/src/shared/sensors/UBXGPS/UBXGPSSpi.cpp b/src/shared/sensors/UBXGPS/UBXGPSSpi.cpp
index 1137164b89aaef27cce88a3cd821c51c48e0fa0a..c0384778147d02d8c9eadfeaa4aa23fd14960e78 100644
--- a/src/shared/sensors/UBXGPS/UBXGPSSpi.cpp
+++ b/src/shared/sensors/UBXGPS/UBXGPSSpi.cpp
@@ -245,7 +245,7 @@ bool UBXGPSSpi::readUBXFrame(UBXFrame& frame)
 
     {
         spiSlave.bus.configure(spiSlave.config);
-        spiSlave.bus.select(spiSlave.cs);
+        spiSlave.select();
 
         // Search UBX frame preamble byte by byte
         size_t i     = 0;
@@ -255,7 +255,7 @@ bool UBXGPSSpi::readUBXFrame(UBXFrame& frame)
             if (Kernel::getOldTick() >= end)
             {
                 // LOG_ERR(logger, "Timeout for read expired");
-                spiSlave.bus.deselect(spiSlave.cs);
+                spiSlave.deselect();
                 Thread::sleep(1);  // GPS minimum time after deselect
                 return false;
             }
@@ -296,7 +296,7 @@ bool UBXGPSSpi::readUBXFrame(UBXFrame& frame)
         spiSlave.bus.read(frame.payload, frame.getRealPayloadLength());
         spiSlave.bus.read(frame.checksum, 2);
 
-        spiSlave.bus.deselect(spiSlave.cs);
+        spiSlave.deselect();
         Thread::sleep(1);  // GPS minimum time after deselect
     }
 
diff --git a/src/shared/sensors/Vectornav/VN100/VN100Spi.cpp b/src/shared/sensors/Vectornav/VN100/VN100Spi.cpp
index 7caea2a86bb2313020811e6a6c3a10973ff9bed3..7904975e31243d02806ce3d74bb8e62a06ce659e 100644
--- a/src/shared/sensors/Vectornav/VN100/VN100Spi.cpp
+++ b/src/shared/sensors/Vectornav/VN100/VN100Spi.cpp
@@ -299,15 +299,15 @@ VN100SpiDefs::VNErrors VN100Spi::readRegister(const uint8_t regId,
         (regId << 16);                    // Id of the register
 
     // Send request packet
-    spiSlave.bus.select(spiSlave.cs);
+    spiSlave.select();
     spiSlave.bus.write32(requestPacket);
-    spiSlave.bus.deselect(spiSlave.cs);
+    spiSlave.deselect();
 
     // Wait at least 100us
     miosix::delayUs(100);
 
     // Read response
-    spiSlave.bus.select(spiSlave.cs);
+    spiSlave.select();
 
     // Discard the first 3 bytes of the response
     VN100SpiDefs::VNErrors err =
@@ -316,13 +316,13 @@ VN100SpiDefs::VNErrors VN100Spi::readRegister(const uint8_t regId,
     if (err != VN100SpiDefs::VNErrors::NO_ERROR)
     {
         // An error occurred while attempting to service the request
-        spiSlave.bus.deselect(spiSlave.cs);
+        spiSlave.deselect();
         return err;
     }
 
     spiSlave.bus.read(payloadBuf, payloadSize);
 
-    spiSlave.bus.deselect(spiSlave.cs);
+    spiSlave.deselect();
 
     return VN100SpiDefs::VNErrors::NO_ERROR;
 }
@@ -353,21 +353,21 @@ VN100SpiDefs::VNErrors VN100Spi::writeRegister(const uint8_t regId,
         (regId << 16);                     // Id of the register
 
     // Send request packet
-    spiSlave.bus.select(spiSlave.cs);
+    spiSlave.select();
     spiSlave.bus.write32(requestPacket);
     spiSlave.bus.write(payloadBuf, payloadSize);
-    spiSlave.bus.deselect(spiSlave.cs);
+    spiSlave.deselect();
 
     // Wait at least 100us
     miosix::delayUs(100);
 
     // Read response
-    spiSlave.bus.select(spiSlave.cs);
+    spiSlave.select();
 
     // Discard the first 3 bytes of the response
     uint8_t err = spiSlave.bus.read32() & 255;
 
-    spiSlave.bus.deselect(spiSlave.cs);
+    spiSlave.deselect();
 
     return (VN100SpiDefs::VNErrors)err;
 }
diff --git a/src/shared/utils/TestUtils/MockSPIBus.h b/src/shared/utils/TestUtils/MockSPIBus.h
index 2fdf6a948ac106fb0fd09338f850c8ef186d2ca4..491a90167acdc6d84e5be654c1f5d1e8709b71ea 100644
--- a/src/shared/utils/TestUtils/MockSPIBus.h
+++ b/src/shared/utils/TestUtils/MockSPIBus.h
@@ -139,13 +139,13 @@ public:
      * @brief See SPIBusInterface::select()
      *
      */
-    virtual void select(GpioType& cs) override;
+    void select(GpioType& cs);
 
     /**
      * @brief See SPIBusInterface::deselect()
      *
      */
-    virtual void deselect(GpioType& cs) override;
+    void deselect(GpioType& cs);
 
     /**
      * @brief See SPIBusInterface::acquire()