From 4a75665e19e2c4a522d1055f7953b190eeb5d005 Mon Sep 17 00:00:00 2001
From: Valerio Flamminii <valerio.flamminii@skywarder.eu>
Date: Sat, 25 Nov 2023 12:54:59 +0100
Subject: [PATCH] my_LIS3DSH driver

---
 src/entrypoints/test-tempsensor.cpp           |  71 ++++
 src/shared/sensors/my_LIS3DSH/my_LIS3DSH.cpp  | 310 ++++++++++++++++++
 src/shared/sensors/my_LIS3DSH/my_LIS3DSH.h    | 211 ++++++++++++
 .../sensors/my_LIS3DSH/my_LIS3DSHData.h       |  51 +++
 src/shared/sensors/my_LIS3DSH/spi-driver.cpp  | 141 ++++++++
 src/shared/sensors/my_LIS3DSH/spi-driver.h    |  65 ++++
 6 files changed, 849 insertions(+)
 create mode 100644 src/entrypoints/test-tempsensor.cpp
 create mode 100644 src/shared/sensors/my_LIS3DSH/my_LIS3DSH.cpp
 create mode 100644 src/shared/sensors/my_LIS3DSH/my_LIS3DSH.h
 create mode 100644 src/shared/sensors/my_LIS3DSH/my_LIS3DSHData.h
 create mode 100644 src/shared/sensors/my_LIS3DSH/spi-driver.cpp
 create mode 100644 src/shared/sensors/my_LIS3DSH/spi-driver.h

diff --git a/src/entrypoints/test-tempsensor.cpp b/src/entrypoints/test-tempsensor.cpp
new file mode 100644
index 000000000..5dd788070
--- /dev/null
+++ b/src/entrypoints/test-tempsensor.cpp
@@ -0,0 +1,71 @@
+/* Copyright (c) <2023> Skyward Experimental Rocketry
+ * Author: <Valerio flamminii>
+ *
+ * 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 <miosix.h>
+#include <utils/Debug.h> 
+#include <sensors/my_LIS3DSH/my_LIS3DSH.h> 
+#include <sensors/my_LIS3DSH/my_LIS3DSHData.h>
+
+using namespace miosix;
+using namespace Boardcore;
+
+
+int main()
+{    
+
+    
+    LIS3DSH sensore(LIS3DSH::OutputDataRate::ODR_100_HZ,
+                   LIS3DSH::BlockDataUpdate::UPDATE_AFTER_READ_MODE, 
+                   LIS3DSH::FullScale::FULL_SCALE_2G); 
+
+    // test getlasterror
+    /*
+    TRACE("sensore self-test: %d\n", sensore.selfTest());
+    TRACE("lastError: %d\n\n", sensore.getLastError());
+    
+    TRACE("sensore.init(): %d\n\n", sensore.init());
+    
+    TRACE("sensore self-test: %d\n", sensore.selfTest());
+    TRACE("lastError: %d\n", sensore.getLastError());
+    */
+
+    if (sensore.init())
+    {   
+        
+        my_LIS3DSHData accel;
+        
+        while (true)
+        {
+            sensore.sample();
+            accel = sensore.getLastSample();
+            printf("timeStamp: %llu\n", accel.accelerationTimestamp);
+            TRACE("X: %f\n", accel.accelerationX);
+            TRACE("Y: %f\n", accel.accelerationY);
+            TRACE("Z: %f\n\n", accel.accelerationZ);
+            Thread::sleep(200);
+        }
+        
+    }
+    else TRACE("-----sensor initialisation failed -----\n"); 
+
+    return 0;
+}
diff --git a/src/shared/sensors/my_LIS3DSH/my_LIS3DSH.cpp b/src/shared/sensors/my_LIS3DSH/my_LIS3DSH.cpp
new file mode 100644
index 000000000..31ccf3a31
--- /dev/null
+++ b/src/shared/sensors/my_LIS3DSH/my_LIS3DSH.cpp
@@ -0,0 +1,310 @@
+/* Copyright (c) <2023> Skyward Experimental Rocketry
+ * Author: <Valerio flamminii>
+ *
+ * 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 <miosix.h>
+#include <utils/Debug.h>
+#include <drivers/timer/TimestampTimer.h> 
+#include <math.h>
+#include "my_LIS3DSH.h"
+
+namespace Boardcore { 
+
+    
+    LIS3DSH::LIS3DSH(uint8_t odr = OutputDataRate::ODR_100_HZ, 
+    uint8_t bdu = BlockDataUpdate::UPDATE_AFTER_READ_MODE, 
+    uint8_t fullScale = FullScale::FULL_SCALE_2G) 
+    : odr(odr), bdu(bdu), fullScale(fullScale) {}
+
+
+    bool LIS3DSH::init() {
+
+        // check if the sensor is already initialized
+        if (initialized)
+        {
+            lastError = SensorErrors::ALREADY_INIT;
+            return false;
+        }
+
+        // config spi-driver to initialise the communication
+        spi_driver.config();  
+
+        // check who_am_i value 
+        if(checkWhoAmI() == false) return false; 
+
+        // set the output data rate and the block-data-update in CTRL_REG4
+        // enable X,Y and Z axis setting the LSB three bits.
+        // so it's possible reading both temperature and accelaration.
+        uint8_t ctrl_reg4_value = (odr << 4) | (bdu << 3) | 7; // 7 = 111b
+
+        // set the full scale range possible values: 2g, 4g, 6g, 8g, 16g 
+        uint8_t ctrl_reg5_value = fullScale << 3; 
+
+        // write values in control registers 4 and 5
+        spi_driver.write(CTRL_REG5, ctrl_reg5_value);
+        spi_driver.write(CTRL_REG4, ctrl_reg4_value);
+
+        // select the correct sensitivity
+        // for the specified full scale range
+        sensitivity = selectSensitivity();
+
+        initialized = true; 
+
+        return true; 
+    }
+
+     
+    bool LIS3DSH::checkWhoAmI() {
+        
+        // check the WHO_AM_I_REG register
+        uint8_t whoAmIValue = spi_driver.read(WHO_AM_I_REG);
+
+        if (whoAmIValue == WHO_AM_I_DEFAULT_VALUE) return true;
+        else lastError = SensorErrors::INVALID_WHOAMI;
+
+        return false; 
+    }
+
+
+    int16_t LIS3DSH::combine(uint8_t msb, uint8_t lsb) {
+    return (msb << 8) | lsb; 
+    }
+
+    
+    float LIS3DSH::selectSensitivity() {
+
+        float s; 
+        switch(fullScale) {
+
+            case(FULL_SCALE_2G):
+                s = sensitivityValues[FullScale::FULL_SCALE_2G];
+                break;
+
+            case(FULL_SCALE_4G):
+                s = sensitivityValues[FullScale::FULL_SCALE_4G];
+                break;
+
+            case(FullScale::FULL_SCALE_6G):
+                s = sensitivityValues[FullScale::FULL_SCALE_6G];
+                break;
+
+            case(FullScale::FULL_SCALE_8G):
+                s = sensitivityValues[FullScale::FULL_SCALE_8G];
+                break;
+
+            case(FullScale::FULL_SCALE_16G):
+                s = sensitivityValues[FullScale::FULL_SCALE_16G];
+                break;
+
+            default:
+                TRACE("Invalid full scale range given, using +/-2g");
+                this->fullScale = FullScale::FULL_SCALE_2G;
+                s = sensitivityValues[FullScale::FULL_SCALE_2G];
+                break; 
+        }
+        return s; 
+    }
+
+
+    AccelerometerData LIS3DSH::readAccelData()
+    {
+       
+        AccelerometerData accelData;
+
+        // read the sensor's status register
+        uint8_t status = spi_driver.read(STATUS);
+
+        if (status & 0x08)
+        {  // bit 3 of status set to 1 (new data available)
+            if (status & 0x80)
+            {  // bit 7 of status set to 1 (some data overwritten)
+
+                // getting timestamp 
+                accelData.accelerationTimestamp = TimestampTimer::getTimestamp();
+
+                // read acceleration X axis
+                int8_t accel_L = spi_driver.read(OUT_X_L);
+                int8_t accel_H = spi_driver.read(OUT_X_H);
+                accelData.accelerationX = static_cast<float>(combine(accel_H, accel_L)) * sensitivity;
+
+                // read acceleration on Y
+                accel_L = spi_driver.read(OUT_Y_L);
+                accel_H = spi_driver.read(OUT_Y_H);
+                accelData.accelerationY = static_cast<float>(combine(accel_H, accel_L)) * sensitivity;
+
+                // read acceleration on Z
+                accel_L = spi_driver.read(OUT_Z_L);
+                accel_H = spi_driver.read(OUT_Z_H);
+                accelData.accelerationZ = static_cast<float>(combine(accel_H, accel_L)) * sensitivity;
+
+                // reset last error of the sensor 
+                lastError = SensorErrors::NO_ERRORS;
+            }
+        }
+        else lastError = SensorErrors::NO_NEW_DATA;
+
+        return accelData;
+    }
+
+
+    my_LIS3DSHData LIS3DSH::sampleImpl()
+    {
+        // check if the sensor is initialized
+        if (!initialized)
+        {
+            lastError = SensorErrors::NOT_INIT;
+            return lastSample;
+        }
+
+        AccelerometerData accelData = readAccelData();
+
+        if (lastError != SensorErrors::NO_ERRORS) return lastSample;
+        else {
+            return my_LIS3DSHData(accelData);
+        }
+    }
+
+
+    bool LIS3DSH::selfTest() 
+    {
+        // check if the sensor is initialized
+        if (!initialized)
+        {
+            lastError = SensorErrors::NOT_INIT;
+            return false;
+        }
+
+        const uint8_t numSamples = 5;  // number of samples to be used
+        // vectors for storing samples, both
+        // in self-test and no-self-test modes
+        float X_ST[numSamples]    = {0};
+        float Y_ST[numSamples]    = {0};
+        float Z_ST[numSamples]    = {0};
+        float X_NO_ST[numSamples] = {0};
+        float Y_NO_ST[numSamples] = {0};
+        float Z_NO_ST[numSamples] = {0};
+        // vectors containing avg values for each axis
+        float AVG_ST[3]    = {0};  // one element per axis
+        float AVG_NO_ST[3] = {0};  // one element per axis
+
+        // set output data rate to 50 hz
+        uint8_t ctrlReg4Value = (OutputDataRate::ODR_100_HZ << 4) |
+                                (BlockDataUpdate::UPDATE_AFTER_READ_MODE << 3) |
+                                (7 << 0);
+
+
+        spi_driver.write(CTRL_REG4, ctrlReg4Value);
+
+
+        // set full scale to default value +/-2g
+        // enable the self-test mode with positive sign
+        uint8_t ctrlReg5Value = (FullScale::FULL_SCALE_2G << 3) | (1 << 1);
+
+        spi_driver.write(CTRL_REG5, ctrlReg5Value);
+
+        // read samples in self-test positive sign mode
+        for (uint8_t i = 0; i < numSamples; i++)
+        {
+            AccelerometerData accelData = readAccelData();
+            X_ST[i]                     = accelData.accelerationX;
+            Y_ST[i]                     = accelData.accelerationY;
+            Z_ST[i]                     = accelData.accelerationZ;
+            miosix::Thread::sleep(10);
+        }
+        
+        // reset the self-test bits
+        ctrlReg5Value &= ~(3 << 1);
+        // normal mode with full scale range +/-2g
+        ctrlReg5Value |= (FULL_SCALE_2G << 3);
+
+        spi_driver.write(CTRL_REG5, ctrlReg5Value);
+
+        // read samples in normal mode
+        for (uint8_t i = 0; i < numSamples; i++)
+        {
+            AccelerometerData accelData = readAccelData();
+            X_NO_ST[i]                  = accelData.accelerationX;
+            Y_NO_ST[i]                  = accelData.accelerationY;
+            Z_NO_ST[i]                  = accelData.accelerationZ;
+            miosix::Thread::sleep(10);
+        }
+        // compute averages vectors:
+        // they contain one element for each axis
+        // (position 0 for x, 1 for y and 2 for z)
+        // AVG_ST    : for self-test samples
+        // AVG_NO_ST : for normal mode samples
+        for (uint8_t i = 0; i < numSamples; i++)
+        {
+            AVG_ST[0] += X_ST[i];
+            AVG_ST[1] += Y_ST[i];
+            AVG_ST[2] += Z_ST[i];
+            AVG_NO_ST[0] += X_NO_ST[i];
+            AVG_NO_ST[1] += Y_NO_ST[i];
+            AVG_NO_ST[2] += Z_NO_ST[i];
+        }
+        for (uint8_t i = 0; i < 3; i++)
+        {
+            AVG_ST[i] /= numSamples;
+            AVG_NO_ST[i] /= numSamples;
+        }
+
+        // Reset registers values with the ones
+        // specified in the constructor:
+        // set the output data rate value in CTRL_REG4
+        ctrlReg4Value = (odr << 4) | (bdu << 3) | (7 << 0);
+
+        spi_driver.write(CTRL_REG4, ctrlReg4Value);
+        
+        // set the full scale value in CTRL_REG5
+        ctrlReg5Value = (fullScale << 3);  // normal mode
+
+        spi_driver.write(CTRL_REG5, ctrlReg5Value);
+
+        float delta[3] = {0};
+        for (uint8_t i = 0; i < 3; i++)
+        {
+            delta[i] = fabs(AVG_NO_ST[i] - AVG_ST[i]);
+        }
+
+        /*
+        TRACE("Selftest: delta[x] = {%f}, delta[y] = {%f}, delta[z] = {%f}",
+            delta[0], delta[1], delta[2]);
+        */
+
+        // check that the averages differences
+        // do not exceed maximum tolerance
+        if ((delta[0] >
+             SELF_TEST_DIFF_X_Y + SELF_TEST_DIFF_X_Y * SELF_TEST_TOLERANCE) ||
+            (delta[1] >
+             SELF_TEST_DIFF_X_Y + SELF_TEST_DIFF_X_Y * SELF_TEST_TOLERANCE) ||
+            (delta[2] >
+             SELF_TEST_DIFF_Z + SELF_TEST_DIFF_Z * SELF_TEST_TOLERANCE))
+        {
+            lastError = SensorErrors::SELF_TEST_FAIL;
+            return false;
+        }
+
+        return true;
+    }
+
+
+
+} // namespace Bordcore
\ No newline at end of file
diff --git a/src/shared/sensors/my_LIS3DSH/my_LIS3DSH.h b/src/shared/sensors/my_LIS3DSH/my_LIS3DSH.h
new file mode 100644
index 000000000..111aac96e
--- /dev/null
+++ b/src/shared/sensors/my_LIS3DSH/my_LIS3DSH.h
@@ -0,0 +1,211 @@
+/* Copyright (c) <2023> Skyward Experimental Rocketry
+ * Author: <Valerio flamminii>
+ *
+ * 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 <sensors/Sensor.h> 
+#include "my_LIS3DSHData.h"  
+#include <drivers/timer/TimestampTimer.h> 
+#include "spi-driver.h"     
+
+namespace Boardcore { 
+
+    /**
+    *  @brief Driver class for stm32f407vg discovery on-board 3-axis
+    *  accelerometer.
+    * The sensor is connected to SPI1 using the
+    * following GPIOs: PA5 : clock
+    *                  PA6 : miso
+    *                  PA7 : mosi
+    *                  PE3 : chip select
+    */
+    class LIS3DSH : public Sensor<my_LIS3DSHData> {
+
+        public:
+        
+        /**
+        * @brief constructor
+        * @param odr output data rate, default value = 100 hz 
+        * @param bdu block data update mode. 
+        * can be continuos or not-continuos mode, default value is update after data
+        * has been read (BDU=1).
+        * @param fullScale full scale range value (from +/-2g up to +/-16g)
+        */
+        LIS3DSH(uint8_t odr, uint8_t bdu, uint8_t fullScale);
+
+        /**
+        * @brief Initialize the sensor.
+        *
+        * @return boolean value indicating whether the operation succeded or not
+        */
+        bool init() override;
+
+        /**
+        * @brief Check if the sensor is working properly.
+        *
+        * @return boolean indicating whether the sensor is correctly working or not
+        */
+        bool selfTest() override;
+
+        /**
+        * @brief Output data rate allowed values (4 bits).
+        */
+        enum OutputDataRate : uint8_t {
+
+            // to make the sensor working odr must be set (don't keep the default one)
+            ODR_POWER_DOWN = 0, // the sensor is turned off (default value)
+            ODR_3_125_HZ   = 1, 
+            ODR_6_25_HZ    = 2,  
+            ODR_12_5_HZ    = 3,
+            ODR_25_HZ      = 4,
+            ODR_50_HZ      = 5,
+            ODR_100_HZ     = 6,
+            ODR_400_HZ     = 7,
+            ODR_800_HZ     = 8,
+            ODR_1600_HZ    = 9
+
+        };
+
+        /**
+        * @brief Block data update allowed modes (1 bit).
+        */
+        enum BlockDataUpdate : uint8_t {
+
+            CONTINUOS_UPDATE_MODE = 0, // continuos sensor data updating
+            UPDATE_AFTER_READ_MODE = 1 // update data after reading process
+        };
+
+        /**
+        * @brief Full scale range allowed values (3 bits).
+        */
+        enum FullScale
+        {
+            FULL_SCALE_2G  = 0,  // 000, +/- 2g
+            FULL_SCALE_4G  = 1,  // 001, +/- 4g
+            FULL_SCALE_6G  = 2,  // 010, +/- 6g
+            FULL_SCALE_8G  = 3,  // 011, +/- 8g
+            FULL_SCALE_16G = 4   // 100  +/- 16g
+        };
+    
+        
+        private:
+
+        /**
+        * @brief Read new data from the accelerometer.
+        * Accelerations are returned in g.
+        * @return accelerations data, if there are new data available otherwise it returns the last sample.
+        */
+        my_LIS3DSHData sampleImpl() override;
+
+        /**
+        * @brief Read accelerometer data.
+        *
+        * @return the read accelerometer sample
+        */
+        AccelerometerData readAccelData();
+
+        /**
+        * @brief Check that the WHO_AM_I register
+        *        contains the correct value.
+        *
+        * @return boolean value indicating whether the value read
+        *          from the WHO_AM_I register is correct or not
+        */
+        bool checkWhoAmI();
+
+        /**
+        * @brief Given the requested full scale range, select the correct
+        * sensitivity value.
+        *
+        * @return the sensitivity value corresponding to the requested full scale
+        * range
+        */
+        float selectSensitivity();
+
+        /**
+        * @brief Combine low and high bits in a single number.
+        *
+        * @param msb   the most significatn bits
+        * @param lsb   the least significant bits
+        * @return MSB and LSB combined in one value
+        */
+        int16_t combine(uint8_t msb, uint8_t lsb);
+
+        /**
+        * @brief Registers' addresses definition.
+        */
+        enum REG : uint8_t {
+        
+            WHO_AM_I_REG = 0x0F, // contains the who_am_i number to be checked
+            
+            CTRL_REG1 = 0x21, // state Machine 1 interrupt configuration register
+            CTRL_REG2 = 0x22, // state Machine 2 interrupt configuration register
+            CTRL_REG3 = 0x23, // interrupt handling
+            CTRL_REG4 = 0x20, // control register 4, to set odr and bdu parameters
+            CTRL_REG5 = 0x24, // control register 5, to set the full scale 2,4,6,8,16g
+            CTRL_REG6 = 0x25, // fifo structure handling 
+
+            // status register
+            STATUS = 0x27,
+
+            // accelerometer output registers
+            // for x, y and z axis
+            // (low and high bits in separate registers)
+            OUT_X_L = 0x28,
+            OUT_X_H = 0x29,
+            OUT_Y_L = 0x2A,
+            OUT_Y_H = 0x2B,
+            OUT_Z_L = 0x2C,
+            OUT_Z_H = 0x2D,
+
+            // temperature output data register 
+            OUT_T = 0x0C       
+            
+        };
+
+        SpiDriver spi_driver;
+
+        bool initialized = false;  // whether the sensor has been initialized or not
+
+        uint8_t odr;       // output data rate, default = 100hz 
+        uint8_t bdu;       // block data update mode: continuous or block after update
+        uint8_t fullScale; // full scale range value default +-2g
+
+        /**
+        * @brief Sensitivity values corresponding to full scale range allowed
+        * values.
+        */
+        const float sensitivityValues[5] = {0.06, 0.12, 0.18, 0.24, 0.73};
+
+        float sensitivity = sensitivityValues[FullScale::FULL_SCALE_2G];  // default sensitivity value of +-2g scale
+
+        const uint8_t WHO_AM_I_DEFAULT_VALUE  = 63; 
+
+        // constants values needed for the self-test of the sensor
+        const float SELF_TEST_DIFF_X_Y  = 140.0f;  // 140 mg
+        const float SELF_TEST_DIFF_Z    = 590.0f;  // 590 mg
+        const float SELF_TEST_TOLERANCE = 0.3f;
+
+    };
+
+
+} // namespace boardcore
\ No newline at end of file
diff --git a/src/shared/sensors/my_LIS3DSH/my_LIS3DSHData.h b/src/shared/sensors/my_LIS3DSH/my_LIS3DSHData.h
new file mode 100644
index 000000000..c53dd56be
--- /dev/null
+++ b/src/shared/sensors/my_LIS3DSH/my_LIS3DSHData.h
@@ -0,0 +1,51 @@
+/* Copyright (c) <2023> Skyward Experimental Rocketry
+ * Author: <Valerio flamminii>
+ *
+ * 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<sensors/SensorData.h> 
+
+
+namespace Boardcore {
+
+    /**
+    * @brief  my_LIS3DSHData is a data struct same as struct Boardcore::AccelerometerData in SensorData.h
+    */
+    struct my_LIS3DSHData : public AccelerometerData {
+
+        /**
+         * @brief constructor
+        */
+        my_LIS3DSHData() : AccelerometerData {0, 0.0, 0.0, 0.0} {}
+        
+        /**
+         * @brief constructor
+         * @param acc AccelerometerData struct 
+        */
+        my_LIS3DSHData(AccelerometerData acc)
+        : AccelerometerData{acc.accelerationTimestamp, acc.accelerationX,
+                            acc.accelerationY, acc.accelerationZ} {}
+
+    };
+    
+
+} // namespace boardcore
\ No newline at end of file
diff --git a/src/shared/sensors/my_LIS3DSH/spi-driver.cpp b/src/shared/sensors/my_LIS3DSH/spi-driver.cpp
new file mode 100644
index 000000000..0690242e1
--- /dev/null
+++ b/src/shared/sensors/my_LIS3DSH/spi-driver.cpp
@@ -0,0 +1,141 @@
+/* Copyright (c) <2023> Skyward Experimental Rocketry
+ * Author: <Valerio flamminii>
+ *
+ * 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 <miosix.h>
+#include <utils/Debug.h>
+#include "spi-driver.h"
+
+
+namespace Boardcore {
+
+
+    SpiDriver::SpiDriver() {}
+
+    void SpiDriver::config(){
+        
+        // slave select pin is active low during communication
+        
+        cs::mode(miosix::Mode::OUTPUT); // set the pin with a low impedance (output)
+        
+        cs::high(); // pin state: HIGH
+
+        // sck, miso and mosi in ALTERNATE mode so they won't be affettected 
+        // by their GPIO function and will be used just for SPI. 
+        sck::mode(miosix::Mode::ALTERNATE); 
+        miso::mode(miosix::Mode::ALTERNATE); 
+        mosi::mode(miosix::Mode::ALTERNATE); 
+
+        // setting AF5 in order to use SPI1 on portA pins.
+        sck::alternateFunction(5); 
+        miso::alternateFunction(5); 
+        mosi::alternateFunction(5); 
+
+        //TRACE("[SpiDriver] GPIOs configured \n");
+
+        // now disable interrupts in order to prioritize the SPI communication.
+        // In a "local" scope so, at the end, the objects inside will be deallocated.  
+        {
+            // now disable interrupts in order to prioritize the SPI communication.
+            miosix::FastInterruptDisableLock dLock;
+            
+            // enabling SPI peripheral by setting the corresponding bit high in
+            // the "clock gating register", which is gonna start the peripheral.
+            RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
+            RCC_SYNC();
+        }
+
+        /* let's set some protocol configurations (by setting high these under-written bits):
+        - slave select pin is controlled by the firmware. (SPI_CR1_SSM)
+        - internal slave select set (SPI_CR1_SSI)
+        - myDiscovery as an SPI master device (SPI_CR1_MSTR)
+        - set clock division factor to 32 (84MHz / 32 = 2.625MHz) (SPI_CR1_BR_2)
+        - finally, enable the entire SPI peripheral (SPI_CR1_SPE)
+        */
+        SPI1->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR | SPI_CR1_BR_2 | SPI_CR1_SPE;
+        
+        
+        //TRACE("[SpiDriver] SPI1 configured \n");
+    }
+
+
+    uint8_t SpiDriver::sendRecv(uint8_t data){
+        SPI1->DR = data; // send data on the SPI bus
+        waitBusy();      // wait till the comunication has ended
+        return SPI1->DR; // return the byte received
+    }
+
+    void SpiDriver::waitBusy() {
+
+        // wait until the RX Not Empty flag in peripheral's status
+        // register (SPI1->SR) is no longer LOW. This means that the communication is over and
+        // the data received by the slave device are available in the SP1->DR (SPI data register).
+        while((SPI1->SR & SPI_SR_RXNE) == 0) {;}
+        
+    } 
+
+    uint8_t SpiDriver::read(uint8_t addr) {
+        
+        // to read a value in one of the slave's registers, we need to:
+        // 1 - pull-down the slave select pin (cs)
+        // 2 - send the register's address with the eigth bit HIGH (reading access) 
+        // 3 - send a "jummy" value over the SPI bus just in order to receive our needed data
+        // 4 - pull-up the slave select pin (cs) to end the transaction.
+
+        cs::low(); 
+        
+        sendRecv(addr | 0x80); 
+        
+        uint8_t data = sendRecv(0x00); // "jummy" value just to shift the register.
+
+        cs::high(); 
+
+        miosix::delayUs(10); // wait 10 micros
+
+        return data; 
+    }
+
+    void SpiDriver::write(uint8_t addr, uint8_t value) {
+
+        // to write a value in one of slave's register or address, we need to: 
+        // 1 - pull-down the slave select pin (cs)
+        // 2 - send the address/ or register's address that we need to write.
+        // 3 - send the data to be written.
+        // 4 - pull-up the slave select pin (cs) to end the transaction.
+
+        // active communication with the slave
+        cs::low(); 
+        
+        // send address
+        sendRecv(addr); 
+
+        // send value (data)
+        sendRecv(value); 
+
+        // cs HIGH to end the transaction over SPI bus.
+        cs::high(); 
+
+        // wait 10 microseconds
+        miosix::delayUs(10); 
+    } 
+
+
+} // namespace Boardcore
\ No newline at end of file
diff --git a/src/shared/sensors/my_LIS3DSH/spi-driver.h b/src/shared/sensors/my_LIS3DSH/spi-driver.h
new file mode 100644
index 000000000..93b881716
--- /dev/null
+++ b/src/shared/sensors/my_LIS3DSH/spi-driver.h
@@ -0,0 +1,65 @@
+/* Copyright (c) <2023> Skyward Experimental Rocketry
+ * Author: <Valerio flamminii>
+ *
+ * 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 <miosix.h>
+
+
+namespace Boardcore {
+
+    // define GPIO pins 5,6,7,3 as "sck", "miso", "mosi" and "cs"
+    typedef miosix::Gpio<GPIOA_BASE, 5> sck;  // serial clock line pin
+    typedef miosix::Gpio<GPIOA_BASE, 6> miso; // master input  slave output pin 
+    typedef miosix::Gpio<GPIOA_BASE, 7> mosi; // master output slave input pin
+    typedef miosix::Gpio<GPIOE_BASE, 3> cs;   // slave-select pin 
+
+    /*
+    @brief SPI driver for dev-board: STM32F407VG discovery
+    */
+    class SpiDriver {
+        
+        public: 
+
+        // constructor
+        SpiDriver();   
+        
+        // config spi-peripheral
+        void config(); 
+        
+        // read by SPi bus
+        uint8_t read(uint8_t addr); 
+
+        // write on SPI bus 
+        void write(uint8_t addr, uint8_t value);  
+
+    
+        private: 
+
+        // trade a byte on SPI bus
+        uint8_t sendRecv(uint8_t data); 
+        
+        // wait until SPI bus is free
+        void waitBusy();
+    }; 
+
+
+} // namespace boardcore 
\ No newline at end of file
-- 
GitLab