Skip to content

Commit

Permalink
[driver] Add MAX31865 driver with STM32F469 Discovery example
Browse files Browse the repository at this point in the history
  • Loading branch information
hshose committed Apr 7, 2023
1 parent d1938eb commit b1105be
Show file tree
Hide file tree
Showing 6 changed files with 481 additions and 6 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -738,47 +738,48 @@ you specific needs.
<td align="center"><a href="https://modm.io/reference/module/modm-driver-ltc2984">LTC2984</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-max31855">MAX31855</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-max31855">MAX31865</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-max6966">MAX6966</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-max7219">MAX7219</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-mcp23x17">MCP23x17</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-mcp2515">MCP2515</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-mcp7941x">MCP7941x</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-mcp7941x">MCP7941x</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-mcp990x">MCP990X</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-mmc5603">MMC5603</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-ms5611">MS5611</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-ms5837">MS5837</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-nokia5110">NOKIA5110</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-nrf24">NRF24</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-nrf24">NRF24</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-parallel_tft_display">TFT-DISPLAY</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-pat9125el">PAT9125EL</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-pca8574">PCA8574</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-pca9535">PCA9535</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-pca9548a">PCA9548A</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-pca9685">PCA9685</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-pca9685">PCA9685</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-sh1106">SH1106</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-siemens_s65">SIEMENS-S65</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-siemens_s75">SIEMENS-S75</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-sk6812">SK6812</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-sk9822">SK9822</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-ssd1306">SSD1306</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-ssd1306">SSD1306</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-st7586s">ST7586S</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-st7789">ST7789</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-stts22h">STTS22H</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-stusb4500">STUSB4500</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-sx1276">SX1276</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-tcs3414">TCS3414</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-tcs3414">TCS3414</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-tcs3472">TCS3472</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-tlc594x">TLC594x</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-tmp102">TMP102</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-tmp12x">TMP12x</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-tmp175">TMP175</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-touch2046">TOUCH2046</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-touch2046">TOUCH2046</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-vl53l0">VL53L0</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-vl6180">VL6180</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-driver-ws2812">WS2812</a></td>
Expand Down
87 changes: 87 additions & 0 deletions examples/stm32f469_discovery/max31865/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// coding: utf-8
/*
* Copyright (c) 2023, Henrik Hose
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <modm/board.hpp>
#include <modm/driver/temperature/max31865.hpp>
#include <modm/processing.hpp>

using namespace Board;

using SpiMaster = modm::platform::SpiMaster2;

using Cs = D9;
using Mosi = D11;
using Miso = D12;
using Sck = D13;

class ThermocoupleThread : public modm::pt::Protothread
{
public:
ThermocoupleThread() : data{}, pt100(data) {}

bool
run()
{
PT_BEGIN();
pt100.initialize();

while (true)
{
MODM_LOG_INFO << "\nNew readout:" << modm::endl;
RF_CALL_BLOCKING(pt100.readout());

MODM_LOG_INFO << " resistance : " << data.getResistance() << " Ohm"
<< modm::endl;
MODM_LOG_INFO << " temperature fast: " << data.getTemperatureFast() << " degrees"
<< modm::endl;
MODM_LOG_INFO << " temperature precise: " << data.getTemperaturePrecise() << " degrees"
<< modm::endl;

timeout.restart(std::chrono::milliseconds(1000));
PT_WAIT_UNTIL(timeout.isExpired());
}

PT_END();
}

private:
modm::max31865pt100::Data data;
modm::Max31865<SpiMaster, Cs> pt100;

modm::ShortTimeout timeout;
};

ThermocoupleThread pt100Thread{};

int
main()
{
Board::initialize();
Cs::setOutput(modm::Gpio::High);

SpiMaster::connect<Miso::Miso, Mosi::Mosi, Sck::Sck>();
SpiMaster::initialize<Board::SystemClock, 351_kHz>();

MODM_LOG_INFO << "==========MAX 31865 Test==========" << modm::endl;
MODM_LOG_DEBUG << "Debug logging here" << modm::endl;
MODM_LOG_INFO << "Info logging here" << modm::endl;
MODM_LOG_WARNING << "Warning logging here" << modm::endl;
MODM_LOG_ERROR << "Error logging here" << modm::endl;
MODM_LOG_INFO << "===============================" << modm::endl;

while (true)
{
pt100Thread.run();
Board::LedOrange::toggle();
}

return 0;
}
14 changes: 14 additions & 0 deletions examples/stm32f469_discovery/max31865/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<library>
<extends>modm:disco-f469ni</extends>
<options>
<option name="modm:build:build.path">../../../build/stm32f469_discovery/max31865</option>
</options>
<modules>
<module>modm:driver:max31865</module>
<module>modm:platform:gpio</module>
<module>modm:platform:spi:2</module>
<module>modm:processing:protothread</module>
<module>modm:processing:timer</module>
<module>modm:build:scons</module>
</modules>
</library>
217 changes: 217 additions & 0 deletions src/modm/driver/temperature/max31865.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// coding: utf-8
// ----------------------------------------------------------------------------
/*
* Copyright (c) 2023, Henrik Hose
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#ifndef MODM_MAX31865_HPP
#define MODM_MAX31865_HPP

#include <array>
#include <modm/architecture/interface/register.hpp>
#include <modm/architecture/interface/spi_device.hpp>
#include <modm/processing/resumable.hpp>

namespace modm
{

/// @ingroup modm_driver_max31865
// Standard values for IEC 751 (PT100) with 400 Ohm reference
template<float R0 = 100.f, float Rref = 430.f, float alpha = 3.85055e-3f,
double a = double{3.90830e-3}, double b = double{-5.77500e-7},
double c = double{-4.18301e-12}>
struct max31865
{

enum class Fault : uint8_t
{
RtdHighThreshold = Bit7,
RtdLowThreshold = Bit6,
RefinMGreater85Percentbias = Bit5,
RefinMLess85PercentVbias = Bit4,
RtdinMLess85PercentVbias = Bit3,
OverUnderVoltage = Bit2
};
MODM_FLAGS8(Fault)

enum class Config : uint8_t
{
VBias = Bit7,
ConversionModeAuto = Bit6,
OneShot = Bit5,
ThreeWire = Bit4,
FaultDetectionCycle1 = Bit3,
FaultDetectionCycle0 = Bit2,
FaultStatusClear = Bit1,
Rejection = Bit0
};
MODM_FLAGS8(Config)

enum class FaultDetectionWrite : uint8_t
{
NoAction = 0b00,
FaultDetectionAutomaticDelay = 0b01,
RunFaultDetectionWithManualDelayCycle1 = 0b10,
FinishFaultDetectionWithManualDelayCycle2 = 0b11,
};
typedef Configuration<Config_t, FaultDetectionWrite, 0b11, 2>
FaultDetectionWrite_t; // Bit 8..10

enum class FaultDetectionRead : uint8_t
{
FaultDetectionFinished = 0b00,
AutomaticDetectionStillRunning = 0b01,
ManualCycle1Running =
0b10, // waiting for user to write FinishFaultDetectionWithManualDelayCycle2
ManualCycle2StillRunning = 0b11,
};
typedef Configuration<Config_t, FaultDetectionRead, 0b11, 2> FaultDetectionRead_t; // Bit 8..10

enum class Rejection : uint8_t
{
Rejection60Hz = 0b0,
Rejection50Hz = 0b1,
};
typedef Configuration<Config_t, Rejection, 0b1> Rejection_t; // Bit 8..10

struct FaultThreshold
{
typedef uint16_t RtdResistance_t;
};

static constexpr uint16_t
rtdfaultthresh(const max31865::FaultThreshold::RtdResistance_t res)
{
return static_cast<uint16_t>(res << 1);
};

enum class Register : uint8_t
{
ReadConfiguration = 0x00,
ReadRtdMsb = 0x01,
ReadRtdLsb = 0x02,
ReadHighFaultThresholdMsb = 0x03,
ReadHighFaultThresholdLsb = 0x04,
ReadLowFaultThresholdMsb = 0x05,
ReadLowFaultThresholdLsb = 0x06,
ReadFaultStatus = 0x07,

WriteConfiguration = 0x80,
WriteHighFaultThresholdMsb = 0x83,
WriteHighFaultThresholdLsb = 0x84,
WriteLowFaultThresholdMsb = 0x85,
WriteLowFaultThresholdLsb = 0x86,
};

struct modm_packed Data
{
/// @return measure resistance in ohm
constexpr float
getResistance() const
{
const uint16_t adccode = data >> 1;
return adccode / 32768.f * Rref;
}

/// @return fast temperature in degrees celsius, about 0.3 degrees error between 0 and 100
/// degrees celsius
constexpr float
getTemperatureFast() const
{
return (getResistance() - R0) / alpha / 100.f;
}

/// @return slow but accurate temperature in degrees celsius
constexpr double
getTemperaturePrecise() const
{
const double res = getResistance();
double T = getTemperatureFast();
const double c0 = T <= 0 ? c : 0;

// Do some fixed number of newton steps for root finding
// on Callendar Van Dusen equation:
// R = R0*(1+a*T+b*T*T+c*(T-100)*T*T*T)
// Newton seems to need double precision to achieve 1.e-10 residual?!
for (int i = 0; i < 10; i++)
{
const double R =
double{R0} * (1 + (a * T) + (b * T * T) + (c0 * (T - 100) * T * T * T)) - res;
const double Rdash =
double{R0} * (a + (2 * b * T) + c0 * (((4 * T) - 300) * T * T));
T -= R / Rdash;
if (std::abs(R) <= 1.e-10) { break; }
}

return T;
}

uint16_t data;
};
}; // struct max31865

using max31865pt100 = max31865<>;

/**
* @tparam SpiMaster
* @tparam Cs
*
* @author Henrik Hose
* @ingroup modm_driver_max31865
*/
template<typename SpiMaster, typename Cs>
class Max31865 : public max31865pt100,
public modm::SpiDevice<SpiMaster>,
protected modm::NestedResumable<3>
{
public:
/**
* @param data pointer to buffer of the internal data of type Data
*/
Max31865(Data &data);

/// Call this function once before using the device
void
initialize();

/// Read the raw data from the sensor
modm::ResumableResult<void>
readout();

public:
/// Get the data object for this sensor
inline Data &
getData()
{
return data;
}

private:
Data &data;
std::array<uint8_t, 2> buffer;
Config_t config;

modm::ShortTimeout timeout;

modm::ResumableResult<void>
writeSingleRegister(Register address, uint8_t data);

modm::ResumableResult<uint8_t>
readSingleRegister(Register address);

modm::ResumableResult<uint16_t>
readTwoRegisters(Register address);
};

} // namespace modm

#include "max31865_impl.hpp"

#endif // MODM_MAX31865_HPP
Loading

0 comments on commit b1105be

Please sign in to comment.