diff --git a/CMakeLists.txt b/CMakeLists.txt index cd569bd1c47ea3fbc8942de427aef77eea875a6c..fed706ded258d6c0b5b70991a7271d5948ee55b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -383,6 +383,9 @@ sbs_target(test-max6675 stm32f429zi_stm32f4discovery) add_executable(test-max31855 src/tests/sensors/test-max31855.cpp) sbs_target(test-max31855 stm32f429zi_stm32f4discovery) +add_executable(test-max31856 src/tests/sensors/test-max31856.cpp) +sbs_target(test-max31856 stm32f767zi_compute_unit) + add_executable(test-mpu9250 src/tests/sensors/test-mpu9250.cpp) sbs_target(test-mpu9250 stm32f429zi_skyward_parafoil) diff --git a/cmake/boardcore.cmake b/cmake/boardcore.cmake index d600f341f11d7f0700f378598f3363f18c526e2b..1972d025dbc27ad2fcc6b21c1960876f1da6eb63 100644 --- a/cmake/boardcore.cmake +++ b/cmake/boardcore.cmake @@ -94,6 +94,7 @@ foreach(OPT_BOARD ${BOARDS}) ${SBS_BASE}/src/shared/sensors/LPS331AP/LPS331AP.cpp ${SBS_BASE}/src/shared/sensors/MAX6675/MAX6675.cpp ${SBS_BASE}/src/shared/sensors/MAX31855/MAX31855.cpp + ${SBS_BASE}/src/shared/sensors/MAX31856/MAX31856.cpp ${SBS_BASE}/src/shared/sensors/MBLoadCell/MBLoadCell.cpp ${SBS_BASE}/src/shared/sensors/MPU9250/MPU9250.cpp ${SBS_BASE}/src/shared/sensors/MS5803/MS5803.cpp diff --git a/src/shared/sensors/MAX31855/MAX31855.cpp b/src/shared/sensors/MAX31855/MAX31855.cpp index 75ab83dc487139e53601dd00a5d0fc2716d14d9d..f79eec3a4a8731a92d0a31301a4f781c74cb455e 100644 --- a/src/shared/sensors/MAX31855/MAX31855.cpp +++ b/src/shared/sensors/MAX31855/MAX31855.cpp @@ -43,9 +43,7 @@ SPIBusConfig MAX31855::getDefaultSPIConfig() bool MAX31855::init() { return true; } -bool MAX31855::selfTest() { return true; } - -bool MAX31855::checkConnection() +bool MAX31855::selfTest() { uint16_t sample[2]; diff --git a/src/shared/sensors/MAX31855/MAX31855.h b/src/shared/sensors/MAX31855/MAX31855.h index 4eb7368651024fc5490404ee61a65835559384ee..2c5fb8067b12eec4bf015539d34927ffd6fa8a45 100644 --- a/src/shared/sensors/MAX31855/MAX31855.h +++ b/src/shared/sensors/MAX31855/MAX31855.h @@ -28,43 +28,24 @@ namespace Boardcore { -/** - * @brief MAX31855 thermocouple sensor driver. - */ + class MAX31855 : public Sensor<TemperatureData> { public: - /** - * @brief Constructor. - * - * @param bus The Spi bus. - * @param cs The CS pin to lower when we need to sample. - * @param config The SPI configuration. - */ MAX31855(SPIBusInterface &bus, miosix::GpioPin cs, SPIBusConfig config = getDefaultSPIConfig()); - /** - * Constructs the default config for SPI Bus. - * - * @returns The default SPIBusConfig. - */ static SPIBusConfig getDefaultSPIConfig(); bool init(); /** - * @brief Checks whether the thermocouple is open. + * @brief Checks whether the thermocouple is connected or not. * * @return True if the thermocouple is connected. */ bool selfTest(); - /** - * @brief Checks whether the thermocouple is connected or not. - */ - bool checkConnection(); - /** * @brief Read the device internal temperature (cold junction). */ diff --git a/src/shared/sensors/MAX31856/MAX31856.cpp b/src/shared/sensors/MAX31856/MAX31856.cpp new file mode 100644 index 0000000000000000000000000000000000000000..325e1ac8aaad44ce19d95db2c63db613fc5e8d80 --- /dev/null +++ b/src/shared/sensors/MAX31856/MAX31856.cpp @@ -0,0 +1,128 @@ +/* Copyright (c) 2023 Skyward Experimental Rocketry + * Author: Alberto Nidasio + * + * 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 "MAX31856.h" + +#include <drivers/timer/TimestampTimer.h> + +namespace Boardcore +{ + +MAX31856::MAX31856(SPIBusInterface& bus, miosix::GpioPin cs, + SPIBusConfig config, ThermocoupleType type) + : slave(bus, cs, config), type(type) +{ +} + +SPIBusConfig MAX31856::getDefaultSPIConfig() +{ + SPIBusConfig spiConfig{}; + spiConfig.clockDivider = SPI::ClockDivider::DIV_32; + spiConfig.mode = SPI::Mode::MODE_1; + spiConfig.writeBit = SPI::WriteBit::INVERTED; + return spiConfig; +} + +bool MAX31856::init() +{ + SPITransaction spi{slave}; + + // Set thermocouple type + setThermocoupleType(type); + + // Enable continuous conversion mode + spi.writeRegister(CR0, CR0_CMODE); + + return true; +} + +bool MAX31856::selfTest() +{ + SPITransaction spi{slave}; + + // Enable open-circuit detection + spi.writeRegister(CR0, CR0_CMODE | CR0_OCFAULT_0); + + // Wait for detection + // Detection takes 40ms, waiting more to be extra sure + miosix::Thread::sleep(100); + + // Read fault register + auto fault = spi.readRegister(SR); + + // Disable open-circuit detection + spi.writeRegister(CR0, CR0_CMODE); + + return !(fault & SR_OPEN); +} + +void MAX31856::setThermocoupleType(ThermocoupleType type) +{ + SPITransaction spi{slave}; + spi.writeRegister(CR1, static_cast<uint8_t>(type)); +} + +TemperatureData MAX31856::sampleImpl() +{ + int32_t sample; + + { + SPITransaction spi{slave}; + sample = spi.readRegister24(LTCBH); + } + + TemperatureData result{}; + result.temperatureTimestamp = TimestampTimer::getTimestamp(); + + // Sign extension + sample = sample << 8; + sample = sample >> (8 + 5); + + // Convert the integer and decimal part separately + result.temperature = static_cast<float>(sample) * 0.007812; + + return result; +} + +TemperatureData MAX31856::readInternalTemperature() +{ + uint16_t sample[2]; + + { + SPITransaction spi{slave}; + spi.read16(sample, sizeof(sample)); + } + + TemperatureData result{}; + result.temperatureTimestamp = TimestampTimer::getTimestamp(); + + // Extract data bits + sample[1] = sample[1] >> 4; + + // Convert the integer and decimal part separately + result.temperature = static_cast<float>(sample[1] >> 4); + result.temperature += static_cast<float>(sample[1] & 0xF) * 0.0625; + + return result; +} + +} // namespace Boardcore diff --git a/src/shared/sensors/MAX31856/MAX31856.h b/src/shared/sensors/MAX31856/MAX31856.h new file mode 100644 index 0000000000000000000000000000000000000000..97fbd817e8eb3e13766eaea09c847c644a836c4a --- /dev/null +++ b/src/shared/sensors/MAX31856/MAX31856.h @@ -0,0 +1,104 @@ +/* Copyright (c) 2023 Skyward Experimental Rocketry + * Author: Alberto Nidasio + * + * 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 <diagnostic/PrintLogger.h> +#include <drivers/spi/SPIDriver.h> +#include <sensors/Sensor.h> + +namespace Boardcore +{ + +class MAX31856 : public Sensor<TemperatureData> +{ +public: + enum class ThermocoupleType : uint8_t + { + B_TYPE = 0x0, + E_TYPE = 0x1, + J_TYPE = 0x2, + K_TYPE = 0x3, + N_TYPE = 0x4, + R_TYPE = 0x5, + S_TYPE = 0x6, + T_TYPE = 0x7, + GAIN_8 = 0x8, + GAIN_32 = 0x9, + }; + + MAX31856(SPIBusInterface &bus, miosix::GpioPin cs, + SPIBusConfig config = getDefaultSPIConfig(), + ThermocoupleType type = ThermocoupleType::K_TYPE); + + static SPIBusConfig getDefaultSPIConfig(); + + bool init(); + + /** + * @brief Checks whether the thermocouple is connected or not. + * + * @return True if the thermocouple is connected. + */ + bool selfTest(); + + void setThermocoupleType(ThermocoupleType type); + + /** + * @brief Read the device internal temperature (cold junction). + */ + TemperatureData readInternalTemperature(); + +private: + TemperatureData sampleImpl() override; + + SPISlave slave; + ThermocoupleType type; + + PrintLogger logger = Logging::getLogger("max31856"); + + enum Registers : uint8_t + { + CR0 = 0x0, ///< Configuration 0 Register + CR1 = 0x1, ///< Configuration 1 Register + MASK = 0x2, ///< Fault Mask Register + CJHF = 0x3, ///< Cold-Junction High Fault Threshold + CJLF = 0x4, ///< Cold-Junction Low Fault Threshold + LTHFTH = 0x5, ///< Linearized Temperature High Fault Threshold MSB + LTHFTL = 0x6, ///< Linearized Temperature High Fault Threshold LSB + LTLFTH = 0x7, ///< Linearized Temperature Low Fault Threshold MSB + LTLFTL = 0x8, ///< Linearized Temperature Low Fault Threshold LSB + CJTO = 0x9, ///< Cold-Junction Temperature Offset Register + CJTH = 0xa, ///< Cold-Junction Temperature Register, MSB + CJTL = 0xb, ///< Cold-Junction Temperature Register, LSB + LTCBH = 0xc, ///< Linearized TC Temperature, Byte 2 + LTCBM = 0xd, ///< Linearized TC Temperature, Byte 1 + LTCBL = 0xe, ///< Linearized TC Temperature, Byte 0 + SR = 0xf, ///< Fault Status Register + }; + + static constexpr uint8_t CR0_CMODE = 0x1 << 7; + static constexpr uint8_t CR0_OCFAULT_0 = 0x1 << 4; + static constexpr uint8_t SR_OPEN = 0x1 << 0; +}; + +} // namespace Boardcore diff --git a/src/tests/sensors/test-max31856.cpp b/src/tests/sensors/test-max31856.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8cf44008d1929c29f87cdfbb14ca5f131fc5fb58 --- /dev/null +++ b/src/tests/sensors/test-max31856.cpp @@ -0,0 +1,73 @@ +/* Copyright (c) 2022 Skyward Experimental Rocketry + * Author: Alberto Nidasio + * + * 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 <drivers/timer/TimestampTimer.h> +#include <miosix.h> +#include <sensors/MAX31856/MAX31856.h> + +using namespace miosix; +using namespace Boardcore; + +GpioPin sckPin = GpioPin(GPIOB_BASE, 3); +GpioPin misoPin = GpioPin(GPIOB_BASE, 4); +GpioPin mosiPin = GpioPin(GPIOD_BASE, 6); +GpioPin csPin = GpioPin(GPIOD_BASE, 4); + +int main() +{ + // Setup gpio pins + sckPin.mode(Mode::ALTERNATE); + sckPin.alternateFunction(6); + misoPin.mode(Mode::ALTERNATE); + misoPin.alternateFunction(6); + mosiPin.mode(Mode::ALTERNATE); + mosiPin.alternateFunction(5); + csPin.mode(Mode::OUTPUT); + csPin.high(); + + SPIBus spiBus(SPI3); + MAX31856 sensor{spiBus, csPin}; + + printf("Starting process verification!\n"); + + sensor.init(); + + if (!sensor.selfTest()) + { + printf("The thermocouple is not connected\n"); + } + else + { + printf("The thermocouple is connected\n"); + } + + while (true) + { + sensor.sample(); + TemperatureData sample = sensor.getLastSample(); + + printf("\r\e[0K[%.2f] %.2f", sample.temperatureTimestamp / 1e6, + sample.temperature); + + Thread::sleep(100); + } +}