diff --git a/src/entrypoints/bmx160-calibration-entry.cpp b/src/entrypoints/bmx160-calibration-entry.cpp
index 2d36db1e9760a947bfff29dbd324c7a0647c8bcb..05f100a16d3796c4ce18e4ac8fee1aec2cad51b6 100644
--- a/src/entrypoints/bmx160-calibration-entry.cpp
+++ b/src/entrypoints/bmx160-calibration-entry.cpp
@@ -238,8 +238,8 @@ void calibrateAccelerometer()
             {
                 bmx160->sample();
 
-                uint8_t fifoSize = bmx160->getLastFifoSize();
-                auto& fifo       = bmx160->getLastFifo();
+                uint16_t fifoSize;
+                const auto fifo = bmx160->getLastFifo(fifoSize);
 
                 for (uint8_t ii = 0; ii < fifoSize; ii++)
                 {
@@ -333,9 +333,8 @@ void calibrateMagnetometer()
         [&]()
         {
             bmx160->sample();
-
-            uint8_t fifoSize = bmx160->getLastFifoSize();
-            auto& fifo       = bmx160->getLastFifo();
+            uint16_t fifoSize;
+            const auto fifo = bmx160->getLastFifo(fifoSize);
 
             for (uint8_t i = 0; i < fifoSize; i++)
             {
@@ -409,8 +408,8 @@ void calibrateGyroscope()
         {
             bmx160->sample();
 
-            uint8_t fifoSize = bmx160->getLastFifoSize();
-            auto& fifo       = bmx160->getLastFifo();
+            uint16_t fifoSize;
+            const auto fifo = bmx160->getLastFifo(fifoSize);
 
             for (uint8_t i = 0; i < fifoSize; i++)
             {
diff --git a/src/shared/sensors/BMX160/BMX160.cpp b/src/shared/sensors/BMX160/BMX160.cpp
index ccf1e0fef7650d5b95ab8b6be540411b98daaf13..f175ad87342fb1dbbd7309c69b9a6ab683e20ad4 100644
--- a/src/shared/sensors/BMX160/BMX160.cpp
+++ b/src/shared/sensors/BMX160/BMX160.cpp
@@ -750,8 +750,9 @@ void BMX160::readFifo(bool headerless)
     spi.readRegisters(BMX160Defs::REG_FIFO_DATA, buf, len);
     uint64_t timestamp          = 0;
     uint64_t watermarkTimestamp = 0;
+    int idx                     = 0;
+    miosix::Lock<miosix::FastMutex> l(fifoMutex);
 
-    int idx = 0;
     while (idx < len && buf[idx] != BMX160Defs::FIFO_STOP_BYTE)
     {
         if (headerless)
diff --git a/src/shared/sensors/BMX160/BMX160.h b/src/shared/sensors/BMX160/BMX160.h
index b4a3864ab7ccdf1a2f6c9bddb90dbe7663d382aa..17a84f360df643d3b31c0a9817afc809146ba170 100644
--- a/src/shared/sensors/BMX160/BMX160.h
+++ b/src/shared/sensors/BMX160/BMX160.h
@@ -41,7 +41,7 @@ namespace Boardcore
 /**
  * @brief BMX160 Driver.
  */
-class BMX160 : public SensorFIFO<BMX160Data, 200>
+class BMX160 : public SensorFIFO<BMX160Data, BMX160Defs::FIFO_SIZE>
 {
 public:
     /**
@@ -117,6 +117,8 @@ private:
     /**
      * @brief Push a sample into the FIFO.
      *
+     * @note The fifo mutex must be locked prior to calling this function
+     *
      * @param sample Sample to be pushed.
      */
     void pushSample(BMX160Data sample);
diff --git a/src/shared/sensors/BMX160/BMX160Defs.h b/src/shared/sensors/BMX160/BMX160Defs.h
index 0d14e7fb696c615853dea67c944203f9bb6fb405..907b0ef82b1a3f29233e56fb1505d1e1629fa348 100644
--- a/src/shared/sensors/BMX160/BMX160Defs.h
+++ b/src/shared/sensors/BMX160/BMX160Defs.h
@@ -33,6 +33,11 @@ namespace Boardcore
 namespace BMX160Defs
 {
 
+/**
+ * @brief Driver's fifo size expressed as number of samples.
+ */
+const uint16_t FIFO_SIZE = 200;
+
 /**
  * @brief Temperature sensor sensibility.
  */
diff --git a/src/shared/sensors/BMX160/BMX160WithCorrection.cpp b/src/shared/sensors/BMX160/BMX160WithCorrection.cpp
index ba68500bb4214faab3e5f48e8323bc92310a629b..1d2500f7fda10b32766b8c054bef2e537024185a 100644
--- a/src/shared/sensors/BMX160/BMX160WithCorrection.cpp
+++ b/src/shared/sensors/BMX160/BMX160WithCorrection.cpp
@@ -71,16 +71,16 @@ BMX160WithCorrectionData BMX160WithCorrection::sampleImpl()
     }
 
     Eigen::Vector3f avgAccel{0, 0, 0}, avgMag{0, 0, 0}, avgGyro{0, 0, 0}, vec;
-    BMX160Data fifoElement;
     BMX160WithCorrectionData result;
-
-    uint8_t fifoSize = bmx160->getLastFifoSize();
+    BMX160Data fifoElement;
+    uint16_t lastFifoSize;
+    const auto lastFifo = bmx160->getLastFifo(
+        lastFifoSize);  // get last fifo and save last fifo size in fifoSize
 
     // Read all data in the fifo
-    for (int i = 0; i < fifoSize; i++)
+    for (int i = 0; i < lastFifoSize; i++)
     {
-        fifoElement = bmx160->getFifoElement(i);
-
+        fifoElement = lastFifo[i];
         // Read acceleration data
         static_cast<AccelerometerData>(fifoElement) >> vec;
         avgAccel += vec;
@@ -95,7 +95,7 @@ BMX160WithCorrectionData BMX160WithCorrection::sampleImpl()
     }
 
     // Average the samples
-    if (fifoSize == 0)
+    if (lastFifoSize == 0)
     {
         static_cast<AccelerometerData>(bmx160->getLastSample()) >> avgAccel;
         static_cast<MagnetometerData>(bmx160->getLastSample()) >> avgMag;
@@ -104,9 +104,9 @@ BMX160WithCorrectionData BMX160WithCorrection::sampleImpl()
     }
     else
     {
-        avgAccel /= fifoSize;
-        avgMag /= fifoSize;
-        avgGyro /= fifoSize;
+        avgAccel /= lastFifoSize;
+        avgMag /= lastFifoSize;
+        avgGyro /= lastFifoSize;
     }
 
     // Correct the measurements
diff --git a/src/shared/sensors/L3GD20/L3GD20.h b/src/shared/sensors/L3GD20/L3GD20.h
index 802b0ed2fefad0331afcd5da5598178984e4eadc..5d50608e82ef884ae3ab6352f6580393339b2b5c 100644
--- a/src/shared/sensors/L3GD20/L3GD20.h
+++ b/src/shared/sensors/L3GD20/L3GD20.h
@@ -221,11 +221,13 @@ public:
             int16_t z = buf[4] | buf[5] << 8;
 
             Eigen::Vector3f rads = toRadiansPerSecond(x, y, z);
-            lastFifo[0] = {lastSampleTimestamp, rads(0), rads(1), rads(2)};
+            return {lastSampleTimestamp, rads(0), rads(1), rads(2)};
         }
-
         else  // FIFO is enabled
         {
+            // Lock mutex for thread safe Fifo reading
+            miosix::Lock<miosix::FastMutex> l(fifoMutex);
+
             SPITransaction spi(spislave);
             // Read last fifo level
             uint8_t fifoSrc   = spi.readRegister(REG_FIFO_SRC);
@@ -287,9 +289,8 @@ public:
             }
 
             lastFifoLevel = fifoLevel - duplicates;
+            return lastFifo[lastFifoLevel - 1];
         }
-
-        return lastFifo[lastFifoLevel - 1];
     }
 
 private:
diff --git a/src/shared/sensors/LSM6DSRX/LSM6DSRX.cpp b/src/shared/sensors/LSM6DSRX/LSM6DSRX.cpp
index 9508ad8969c422598b3489f355db80acc69e17b5..aa7d51c9b6763b28696728c23019a22dd5fd56eb 100644
--- a/src/shared/sensors/LSM6DSRX/LSM6DSRX.cpp
+++ b/src/shared/sensors/LSM6DSRX/LSM6DSRX.cpp
@@ -765,6 +765,9 @@ float LSM6DSRX::getSensorTimestampResolution()
 
 void LSM6DSRX::readFromFifo()
 {
+    // Lock mutex for thread safe Fifo reading
+    miosix::Lock<miosix::FastMutex> l(fifoMutex);
+
     SPITransaction spi{spiSlave};
 
     // get number of sample to read
@@ -794,17 +797,17 @@ void LSM6DSRX::readFromFifo()
     // --> `i` keeps count of the number of elements in `rawFifo`
     //     `idxFifo` keeps track of the samples saved inside `lastFifo`
     uint16_t idxFifo = 0;
+
     for (uint16_t i = 0; i < numSamples; ++i)
     {
         const uint8_t sensorTag   = (rawFifo[i].sampleTag >> 3) & 31;
         const uint8_t timeslotTag = (rawFifo[i].sampleTag & 6) >> 1;
-
-        const uint8_t xl = rawFifo[i].xl;
-        const uint8_t xh = rawFifo[i].xh;
-        const uint8_t yl = rawFifo[i].yl;
-        const uint8_t yh = rawFifo[i].yh;
-        const uint8_t zl = rawFifo[i].zl;
-        const uint8_t zh = rawFifo[i].zh;
+        const uint8_t xl          = rawFifo[i].xl;
+        const uint8_t xh          = rawFifo[i].xh;
+        const uint8_t yl          = rawFifo[i].yl;
+        const uint8_t yh          = rawFifo[i].yh;
+        const uint8_t zl          = rawFifo[i].zl;
+        const uint8_t zh          = rawFifo[i].zh;
 
         switch (sensorTag)
         {
diff --git a/src/shared/sensors/LSM6DSRX/LSM6DSRX.h b/src/shared/sensors/LSM6DSRX/LSM6DSRX.h
index a13b6802c92dcf8bc838dcbf84cebe8dc4121ce3..45d99ddf6fbb235012ffa71662f6fb2205924743 100644
--- a/src/shared/sensors/LSM6DSRX/LSM6DSRX.h
+++ b/src/shared/sensors/LSM6DSRX/LSM6DSRX.h
@@ -127,6 +127,8 @@ private:
      * timestamp is 0: in this case nothing happens to the fifo, data inside
      * `timeslot` is discarded.
      *
+     * @note The fifo mutex must be locked prior to calling this function
+     *
      * @param timeslot The timeslot containing data to be pushed inside the
      * fifo.
      * @param fifoIdx The current index of the fifo, pointing to the current
diff --git a/src/shared/sensors/Sensor.h b/src/shared/sensors/Sensor.h
index bfbae274092d983a504ddc459b9f49b8a78fc5c9..11cbf3709151a2509c243c5e2d34d86154381978 100644
--- a/src/shared/sensors/Sensor.h
+++ b/src/shared/sensors/Sensor.h
@@ -137,36 +137,47 @@ public:
 
 /**
  * @brief Interface for sensor that implement a FIFO.
+ *
+ * @note This class is move constructible, but the move operation is not thread
+ * safe. The moved-to object's mutex is initialized to the unlocked state, no
+ * matter the moved-from object's mutex state. The move constructor is only
+ * needed for HIL.
+ *
  */
 template <typename Data, uint32_t FifoSize>
 class SensorFIFO : public Sensor<Data>
 {
 protected:
     std::array<Data, FifoSize> lastFifo;
-    uint16_t lastFifoLevel = 1;  ///< number of samples in lastFifo
-
+    uint16_t lastFifoLevel          = 1;  //< number of samples in lastFifo
     uint64_t lastInterruptTimestamp = 0;
     uint64_t interruptTimestampDelta =
-        0;  ///< delta between previous interrupt timestamp and the last
-            ///< received one
+        0;                        //< delta between previous interrupt
+                                  // timestamp and the last received one
+    miosix::FastMutex fifoMutex;  // thread safe mutex to read FIFO
 
 public:
-    /**
-     * @return last FIFO sampled from the sensor
-     */
-    const std::array<Data, FifoSize>& getLastFifo() { return lastFifo; }
-
-    /**
-     * @param i index of the requested item inside the FIFO
-     *
-     * @return the i-th element of the FIFO
-     */
-    const Data& getFifoElement(uint32_t i) const { return lastFifo[i]; }
+    SensorFIFO() {}
+
+    SensorFIFO(SensorFIFO&& other)
+        : lastFifo{std::move(other.lastFifo)},
+          lastFifoLevel{std::move(other.lastFifoLevel)},
+          lastInterruptTimestamp{std::move(other.lastInterruptTimestamp)},
+          interruptTimestampDelta{std::move(other.interruptTimestampDelta)},
+          fifoMutex{}
+    {
+    }
 
     /**
-     * @return number of elements in the last FIFO sampled from the sensor
+     * @param lastFifoSize output parameter for last FIFO size
+     * @return last FIFO sampled from the sensor
      */
-    uint16_t getLastFifoSize() const { return lastFifoLevel; }
+    const std::array<Data, FifoSize> getLastFifo(uint16_t& lastFifoSize)
+    {
+        miosix::Lock<miosix::FastMutex> l(fifoMutex);
+        lastFifoSize = lastFifoLevel;
+        return lastFifo;
+    }
 
     /**
      * @brief Called by the interrupt handling routine: provides the timestamp
diff --git a/src/tests/hil/Sensors/Sensors.cpp b/src/tests/hil/Sensors/Sensors.cpp
index bc1edb3d9f9aaab9ecdf0d0da2095538ba12d4a3..888c07aacf77d0dea7ce83a68c70d6428938758d 100644
--- a/src/tests/hil/Sensors/Sensors.cpp
+++ b/src/tests/hil/Sensors/Sensors.cpp
@@ -675,8 +675,8 @@ void Sensors::ubxgpsCallback()
 }
 void Sensors::lsm6dsrxCallback()
 {
-    auto& fifo        = lsm6dsrx->getLastFifo();
-    uint16_t fifoSize = lsm6dsrx->getLastFifoSize();
+    uint16_t fifoSize;
+    const auto fifo = lsm6dsrx->getLastFifo(fifoSize);
 
     // For every instance inside the fifo log the sample
     for (uint16_t i = 0; i < fifoSize; i++)
diff --git a/src/tests/sensors/test-bmx160-with-correction.cpp b/src/tests/sensors/test-bmx160-with-correction.cpp
index db14f2c9679bb72a0dad6953101cfc8d2b80984f..b39cff4a9274e467372ac5c75313b6841cf4cadc 100644
--- a/src/tests/sensors/test-bmx160-with-correction.cpp
+++ b/src/tests/sensors/test-bmx160-with-correction.cpp
@@ -209,8 +209,8 @@ SixParametersCorrector calibrateMagnetometer(SixParametersCorrector oldCorr)
         {
             bmx160->sample();
 
-            uint8_t fifoSize = bmx160->getLastFifoSize();
-            auto& fifo       = bmx160->getLastFifo();
+            uint16_t fifoSize;
+            const auto fifo = bmx160->getLastFifo(fifoSize);
 
             for (uint8_t i = 0; i < fifoSize; i++)
             {
@@ -294,8 +294,8 @@ SixParametersCorrector calibrateGyroscope(SixParametersCorrector corr)
         {
             bmx160->sample();
 
-            uint8_t fifoSize = bmx160->getLastFifoSize();
-            auto& fifo       = bmx160->getLastFifo();
+            uint16_t fifoSize;
+            const auto fifo = bmx160->getLastFifo(fifoSize);
 
             for (uint8_t i = 0; i < fifoSize; i++)
             {
@@ -436,7 +436,7 @@ SixParametersCorrector calibrateGyroscope(SixParametersCorrector corr)
 //             bmx160->sample();
 //             avgAccel = {0, 0, 0};
 
-//             // Read all the data contained in the fifo
+//             // Read all the data contaigetLastFifoned in the fifo
 //             uint8_t size       = bmx160->getLastFifoSize();
 //             fifoAccSampleCount = 0;
 //             for (int ii = 0; ii < size; ii++)
diff --git a/src/tests/sensors/test-bmx160.cpp b/src/tests/sensors/test-bmx160.cpp
index 6557645cd6c98f9c40d26bae285fd82bbd488292..8be612fd4d69282806e653bd0d70295465f2529e 100644
--- a/src/tests/sensors/test-bmx160.cpp
+++ b/src/tests/sensors/test-bmx160.cpp
@@ -94,18 +94,19 @@ int main()
         }
 
         uint64_t now = TimestampTimer::getTimestamp();
+        uint16_t fifoSize;
+        const auto lastFifo = sensor->getLastFifo(fifoSize);
+        uint16_t len        = std::min(fifoSize, (uint16_t)5);
 
         printf("Tick: %.4f s, Now: %.4f s\n", tick / 1000000.0f,
                now / 1000000.0f);
         printf("Temp: %.2f deg\n", sensor->getTemperature().temperature);
-        printf("Fill: %d\n", sensor->getLastFifoSize());
-
+        printf("Fill: %d\n", fifoSize);
         printf("----------------------------\n");
-        uint16_t len = std::min(sensor->getLastFifoSize(), (uint16_t)5);
 
         for (uint16_t i = 0; i < len; i++)
         {
-            BMX160Data data = sensor->getFifoElement(i);
+            BMX160Data data = lastFifo[i];
             printf("Mag [%.4f s]:\t%.2f\t%.2f\t%.2f\n",
                    data.magneticFieldTimestamp / 1000000.0f,
                    data.magneticFieldX, data.magneticFieldY,
diff --git a/src/tests/sensors/test-l3gd20-fifo.cpp b/src/tests/sensors/test-l3gd20-fifo.cpp
index 76e9186c0d8068f57181890359a866c4f1c7436c..aad44c5c40dfae6705afe9418869f6a80504e548 100644
--- a/src/tests/sensors/test-l3gd20-fifo.cpp
+++ b/src/tests/sensors/test-l3gd20-fifo.cpp
@@ -174,11 +174,9 @@ int main()
         // Measure how long we take to read the fifo
         update = TimestampTimer::getTimestamp() - update;
 
-        uint8_t level =
-            gyro->getLastFifoSize();  // Current number of samples in the FIFO
-
-        // Obtain the FIFO
-        const array<L3GD20Data, L3GD20_FIFO_SIZE>& fifo = gyro->getLastFifo();
+        uint16_t level;
+        // Obtain the FIFO and save the last fifo size
+        const auto fifo = gyro->getLastFifo(level);
 
         // Store everything in the data buffer
         for (int i = 0; i < level; i++)
diff --git a/src/tests/sensors/test-lsm6dsrx.cpp b/src/tests/sensors/test-lsm6dsrx.cpp
index a979fe0f49b67a0a4cfd2bcc423cb85ecf73d1e7..3b3c037bfadf0771195ab864298be9c93350cce5 100644
--- a/src/tests/sensors/test-lsm6dsrx.cpp
+++ b/src/tests/sensors/test-lsm6dsrx.cpp
@@ -264,17 +264,15 @@ void testFifoRead(SPIBus& bus, miosix::GpioPin csPin,
         }
 
         sens->sample();
-
-        const std::array<LSM6DSRXData, LSM6DSRXDefs::FIFO_SIZE>& buf =
-            sens->getLastFifo();
-
+        uint16_t fifoSize;
+        const auto buf = sens->getLastFifo(fifoSize);
         // Print fifo
         std::cout << "last fifo element:\n";
-        buf[sens->getLastFifoSize() - 1].print(std::cout);
-        std::cout << "last fifo size: " << sens->getLastFifoSize() << "\n";
+        buf[fifoSize - 1].print(std::cout);
+        std::cout << "last fifo size: " << fifoSize << "\n";
 
         // Check fifo data
-        for (uint16_t i = 1; i < sens->getLastFifoSize(); ++i)
+        for (uint16_t i = 1; i < fifoSize; ++i)
         {
             // Check for accelerometer timestamps
             if (buf[i].accelerationTimestamp <=
diff --git a/src/tests/test-sensormanager.cpp b/src/tests/test-sensormanager.cpp
index b67326b5b3a2875a20457f95c1bf458b43a3a3d6..8fcbec7df56fd1d8dcd6b7a626075825c6aacb8b 100644
--- a/src/tests/test-sensormanager.cpp
+++ b/src/tests/test-sensormanager.cpp
@@ -158,7 +158,8 @@ public:
     FIFOData sampleImpl()
     {
         index = 0;
-        return sensor->getFifoElement(index);
+        uint16_t actualFifoSize;
+        return sensor->getLastFifo(actualFifoSize)[index];
     }
 
     FIFOData getLastSample() override
@@ -167,8 +168,8 @@ public:
             index++;
 
         TRACE("Index : %d \n", index);
-
-        return sensor->getFifoElement(index);
+        uint16_t actualFifoSize;
+        return sensor->getLastFifo(actualFifoSize)[index];
     }
 
 private: