Skip to content
Snippets Groups Projects
Commit 50ac021e authored by Alberto Nidasio's avatar Alberto Nidasio
Browse files

[MAX31856] Improved documentation and implemented cold junction temperature sampling

parent c77a6466
Branches
No related tags found
No related merge requests found
......@@ -29,6 +29,17 @@
namespace Boardcore
{
/**
* @brief MAX31855 thermocouple sensor driver.
*
* The MAX31855 performs cold-junction compensation and digitizes the signal
* from a K, J, N, T, S, R, or E type thermocouple depending on the selected
* product variant. The data is output in a signed 14-bit, SPI-compatible,
* read-only format. This converter resolves temperatures to 0.25°C, allows
* readings as high as +1800°C and as low as -270°C, and exhibits thermocouple
* accuracy of ±2°C for temperatures ranging from -200°C to +700°C for K-type
* thermocouples.
*/
class MAX31855 : public Sensor<TemperatureData>
{
public:
......
......@@ -49,6 +49,9 @@ bool MAX31856::init()
// Set thermocouple type
setThermocoupleType(type);
// Reset the cold junction offset
setColdJunctionOffset(0);
// Enable continuous conversion mode
spi.writeRegister(CR0, CR0_CMODE);
......@@ -81,46 +84,44 @@ void MAX31856::setThermocoupleType(ThermocoupleType type)
spi.writeRegister(CR1, static_cast<uint8_t>(type));
}
TemperatureData MAX31856::sampleImpl()
void MAX31856::setColdJunctionOffset(float offset)
{
int32_t sample;
SPITransaction spi{slave};
spi.writeRegister(CJTO,
static_cast<int8_t>(offset * 1 / CJ_TEMP_LSB_VALUE));
}
MAX31856Data MAX31856::sampleImpl()
{
SPITransaction spi{slave};
sample = spi.readRegister24(LTCBH);
}
int16_t cjRaw = spi.readRegister16(CJTH);
int32_t tcRaw = spi.readRegister24(LTCBH);
TemperatureData result{};
MAX31856Data 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];
// The register has:
// - A leading sign bit (which is actually two's complement)
// - The other 18 bits
// - 5 unused trailing bits
{
SPITransaction spi{slave};
spi.read16(sample, sizeof(sample));
}
// Since the 24 bit registers value is stored into a 32 bit variable, first
// we make a left shift to move the sign bit in the 31st bit, and then a
// right shift to remove the unused bits.
// This automatically extends the sign
tcRaw = tcRaw << 8;
tcRaw = tcRaw >> (8 + 5);
TemperatureData result{};
result.temperatureTimestamp = TimestampTimer::getTimestamp();
// Here we just make a right shift as the sign bit is already in the 15th
// bit. This will also perform the sign extension like in sampleImpl()
cjRaw = cjRaw >> 4;
// Extract data bits
sample[1] = sample[1] >> 4;
// Convert the raw value into temperature
result.temperature = static_cast<float>(tcRaw) * TC_TEMP_LSB_VALUE;
// 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;
// Convert the raw value into temperature
result.coldJunctionTemperature =
static_cast<float>(cjRaw) * CJ_TEMP_LSB_VALUE;
return result;
}
......
......@@ -26,10 +26,25 @@
#include <drivers/spi/SPIDriver.h>
#include <sensors/Sensor.h>
#include "MAX31856Data.h"
namespace Boardcore
{
class MAX31856 : public Sensor<TemperatureData>
/**
* @brief MAX31855 thermocouple sensor driver.
*
* The MAX31856 performs cold-junction compensation and digitizes the signal
* from any type of thermocouple. This converter resolves temperatures to
* 0.0078125°C, allows readings as high as +1800°C and as low as -210°C
* (depending on thermocouple type), and exhibits thermocouple voltage
* measurement accuracy of ±0.15%. The thermocouple inputs are protected against
* over voltage conditions up to ±45V. A lookup table (LUT) stores linearity
* correction data for several types of thermocouples (K, J, N, R, S, T, E, and
* B). Line frequency filtering of 50Hz and 60Hz is included, as is thermocouple
* fault detection
*/
class MAX31856 : public Sensor<MAX31856Data>
{
public:
enum class ThermocoupleType : uint8_t
......@@ -63,13 +78,10 @@ public:
void setThermocoupleType(ThermocoupleType type);
/**
* @brief Read the device internal temperature (cold junction).
*/
TemperatureData readInternalTemperature();
void setColdJunctionOffset(float offset);
private:
TemperatureData sampleImpl() override;
MAX31856Data sampleImpl() override;
SPISlave slave;
ThermocoupleType type;
......@@ -99,6 +111,9 @@ private:
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;
static constexpr float TC_TEMP_LSB_VALUE = 0.007812; // [°C]
static constexpr float CJ_TEMP_LSB_VALUE = 0.0625; // [°C]
};
} // namespace Boardcore
/* 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 <utils/Debug.h>
#include <cstdio>
#include <map>
#include "sensors/SensorData.h"
namespace Boardcore
{
struct MAX31856Data : public TemperatureData
{
float coldJunctionTemperature;
MAX31856Data() : MAX31856Data{0, 0.0, 0.0} {}
MAX31856Data(uint64_t temperatureTimestamp, float temperature)
: MAX31856Data(temperatureTimestamp, temperature, 0)
{
}
MAX31856Data(uint64_t temperatureTimestamp, float temperature,
float coldJunctionTemperature)
: TemperatureData{temperatureTimestamp, temperature},
coldJunctionTemperature(coldJunctionTemperature)
{
}
static std::string header()
{
return "temperatureTimestamp,temperature,coldJunctionTemperature\n";
}
void print(std::ostream& os) const
{
os << temperatureTimestamp << "," << temperature << ","
<< coldJunctionTemperature << "\n";
}
};
} // namespace Boardcore
\ No newline at end of file
......@@ -60,13 +60,23 @@ int main()
printf("The thermocouple is connected\n");
}
// Wait for one sample to be made
Thread::sleep(100);
// Set cold junction offset
// This should set the cold junction temperature to 25°
sensor.sample();
auto sample = sensor.getLastSample();
sensor.setColdJunctionOffset(sample.coldJunctionTemperature - 25);
printf("Offset: %f\n", sample.coldJunctionTemperature - 25);
while (true)
{
sensor.sample();
TemperatureData sample = sensor.getLastSample();
sample = sensor.getLastSample();
printf("\r\e[0K[%.2f] %.2f", sample.temperatureTimestamp / 1e6,
sample.temperature);
printf("[%.2f] %f %f\n", sample.temperatureTimestamp / 1e6,
sample.temperature, sample.coldJunctionTemperature);
Thread::sleep(100);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment