diff --git a/MAX31856/MAX31856MUD+Driver.cpp b/MAX31856/MAX31856MUD+Driver.cpp new file mode 100644 index 0000000..a03a79a --- /dev/null +++ b/MAX31856/MAX31856MUD+Driver.cpp @@ -0,0 +1,143 @@ +#include +#include + +#define SPI_DUMMY_BYTE 0x00 + +MAX31856Driver::MAX31856Driver() {} +MAX31856Driver::~MAX31856Driver() {} + +//marks driver as initialized +void MAX31856Driver::Init(SPI_HandleTypeDef* hspi_, GPIO_TypeDef* cs_gpio_, uint16_t cs_pin_) { + hspi = hspi_; + initialized = true; + + SetCSPin(cs_gpio_, cs_pin_); + CSHigh(); + + (void)GetRegister(MAX31856_REG::CR0); +} + +uint8_t MAX31856Driver::GetRegister(MAX31856_REG::REG reg) { + assert(initialized); + + uint8_t tx[2] = { + uint8_t(reg & 0x7F), + SPI_DUMMY_BYTE + }; + uint8_t rx[2] = {0,0}; + + CSLow(); + for(volatile int i = 0; i < 500; i++) { __NOP(); } + + HAL_SPI_TransmitReceive(hspi, tx, rx, 2, 1000); + + for(volatile int i = 0; i < 500; i++) { __NOP(); } + CSHigh(); + + return rx[1]; +} + +bool MAX31856Driver::SetRegister(MAX31856_REG::REG reg, uint8_t val) { + assert(initialized); + + uint8_t tx[2] = { + uint8_t(reg | 0x80), + val + }; + uint8_t dummy_rx[2] = {0, 0}; + + CSLow(); + for(volatile int i = 0; i < 500; i++) { __NOP(); } + + HAL_StatusTypeDef r = HAL_SPI_TransmitReceive(hspi, tx, dummy_rx, 2, 1000); + + for(volatile int i = 0; i < 500; i++) { __NOP(); } + CSHigh(); + + return r == HAL_OK; +} + +void MAX31856Driver::CSLow() { + assert(initialized); + HAL_GPIO_WritePin(cs_gpio, cs_pin, GPIO_PIN_RESET); +} + +void MAX31856Driver::CSHigh() { + assert(initialized); + HAL_GPIO_WritePin(cs_gpio, cs_pin, GPIO_PIN_SET); + for(volatile int i = 0; i < 500; i++) { __NOP(); } +} + +void MAX31856Driver::SetCSPin(GPIO_TypeDef* gpio, uint16_t pin) { + cs_gpio = gpio; + cs_pin = pin; +} + +bool MAX31856Driver::SetMASK(uint8_t value) { return SetRegister(MAX31856_REG::MASK, value); } +uint8_t MAX31856Driver::GetMASK() { return GetRegister(MAX31856_REG::MASK); } +bool MAX31856Driver::SetCJHF(uint8_t value) { return SetRegister(MAX31856_REG::CJHF, value); } +uint8_t MAX31856Driver::GetCJHF() { return GetRegister(MAX31856_REG::CJHF); } +bool MAX31856Driver::SetCR0(uint8_t value) { return SetRegister(MAX31856_REG::CR0, value); } +uint8_t MAX31856Driver::GetCR0() { return GetRegister(MAX31856_REG::CR0); } +bool MAX31856Driver::SetCR1(uint8_t value) { return SetRegister(MAX31856_REG::CR1, value); } +uint8_t MAX31856Driver::GetCR1() { return GetRegister(MAX31856_REG::CR1); } +bool MAX31856Driver::SetCJLF(uint8_t value) { return SetRegister(MAX31856_REG::CJLF, value); } +uint8_t MAX31856Driver::GetCJLF() { return GetRegister(MAX31856_REG::CJLF); } +bool MAX31856Driver::SetLTHFTH(uint8_t value) { return SetRegister(MAX31856_REG::LTHFTH, value); } +uint8_t MAX31856Driver::GetLTHFTH() { return GetRegister(MAX31856_REG::LTHFTH); } +bool MAX31856Driver::SetLTHFTL(uint8_t value) { return SetRegister(MAX31856_REG::LTHFTL, value); } +uint8_t MAX31856Driver::GetLTHFTL() { return GetRegister(MAX31856_REG::LTHFTL); } +bool MAX31856Driver::SetLTLFTH(uint8_t value) { return SetRegister(MAX31856_REG::LTLFTH, value); } +uint8_t MAX31856Driver::GetLTLFTH() { return GetRegister(MAX31856_REG::LTLFTH); } +bool MAX31856Driver::SetCJTO(uint8_t value) { return SetRegister(MAX31856_REG::CJTO, value); } +uint8_t MAX31856Driver::GetCJTO() { return GetRegister(MAX31856_REG::CJTO); } +bool MAX31856Driver::SetCJTH(uint8_t value) { return SetRegister(MAX31856_REG::CJTH, value); } +uint8_t MAX31856Driver::GetCJTH() { return GetRegister(MAX31856_REG::CJTH); } +bool MAX31856Driver::SetCJTL(uint8_t value) { return SetRegister(MAX31856_REG::CJTL, value); } +uint8_t MAX31856Driver::GetCJTL() { return GetRegister(MAX31856_REG::CJTL); } +bool MAX31856Driver::SetLTLFTL(uint8_t value) { return SetRegister(MAX31856_REG::LTLFTL, value); } +uint8_t MAX31856Driver::GetLTLFTL() { return GetRegister(MAX31856_REG::LTLFTL); } + +void MAX31856Driver::GetMultipleRegisters(MAX31856_REG::REG startreg, int numBytes, uint8_t* out) { + assert(initialized); + + if (numBytes > 7) numBytes = 7; + uint8_t tx[8] = {0}; + uint8_t rx[8] = {0}; + + tx[0] = startreg & 0x7F; + for(int i = 1; i <= numBytes; i++) tx[i] = SPI_DUMMY_BYTE; + + CSLow(); + for(volatile int i = 0; i < 500; i++) { __NOP(); } + + HAL_SPI_TransmitReceive(hspi, tx, rx, numBytes + 1, 1000); + + for(volatile int i = 0; i < 500; i++) { __NOP(); } + CSHigh(); + + for(int i = 0; i < numBytes; i++) + out[i] = rx[i+1]; +} + + +float MAX31856Driver::ReadThermocoupleTempC() { + uint8_t buf[3]; + + + + GetMultipleRegisters(MAX31856_REG::LTCBH, 3, buf); + + // Convert 24-bit + int32_t raw = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | buf[2]; + + // Sign extend + if(raw & 0x800000) + raw |= 0xFF000000; + + return raw / 4096.0f; +} + +uint8_t MAX31856Driver::GetFaultStatus() { + return GetRegister(MAX31856_REG::SR); +} diff --git a/MAX31856/MAX31856MUD+Driver.hpp b/MAX31856/MAX31856MUD+Driver.hpp new file mode 100644 index 0000000..251ad90 --- /dev/null +++ b/MAX31856/MAX31856MUD+Driver.hpp @@ -0,0 +1,58 @@ +#ifndef MAX31856_DRIVER_HPP_ +#define MAX31856_DRIVER_HPP_ + +#include "stm32h7xx_hal.h" +#include "MAX31856_regs.hpp" +#include + +class MAX31856Driver { +public: + MAX31856Driver(); + ~MAX31856Driver(); + + void Init(SPI_HandleTypeDef *hspi, GPIO_TypeDef *gpio, uint16_t pin); + + bool SetRegister(MAX31856_REG::REG reg, uint8_t val); + uint8_t GetRegister(MAX31856_REG::REG reg); + void GetMultipleRegisters(MAX31856_REG::REG startreg, int numBytes, uint8_t *out); + + float ReadThermocoupleTempC(); + uint8_t GetFaultStatus(); + + bool SetMASK(uint8_t value); + uint8_t GetMASK(); + bool SetCJHF(uint8_t value); + uint8_t GetCJHF(); + bool SetCR0(uint8_t value); + uint8_t GetCR0(); + bool SetCR1(uint8_t value); + uint8_t GetCR1(); + bool SetCJLF(uint8_t value); + uint8_t GetCJLF(); + bool SetLTHFTH(uint8_t value); + uint8_t GetLTHFTH(); + bool SetLTHFTL(uint8_t value); + uint8_t GetLTHFTL(); + bool SetLTLFTH(uint8_t value); + uint8_t GetLTLFTH(); + bool SetCJTO(uint8_t value); + uint8_t GetCJTO(); + bool SetCJTH(uint8_t value); + uint8_t GetCJTH(); + bool SetCJTL(uint8_t value); + uint8_t GetCJTL(); + bool SetLTLFTL(uint8_t value); + uint8_t GetLTLFTL(); + +private: + SPI_HandleTypeDef *hspi = nullptr; + GPIO_TypeDef *cs_gpio = nullptr; + uint16_t cs_pin = 0; + bool initialized = false; + + void CSLow(); + void CSHigh(); + void SetCSPin(GPIO_TypeDef *gpio, uint16_t pin); +}; + +#endif diff --git a/MAX31856/MAX31856_regs.hpp b/MAX31856/MAX31856_regs.hpp new file mode 100644 index 0000000..306f26d --- /dev/null +++ b/MAX31856/MAX31856_regs.hpp @@ -0,0 +1,83 @@ +/** + ****************************************************************************** + * @file MAX31856_regs.hpp + * @brief Register map and bit definitions for MAX31856. + ****************************************************************************** + */ + +#ifndef MAX31856_REGS_HPP_ +#define MAX31856_REGS_HPP_ + +#include + +namespace MAX31856_REG { + +// Register addresses. +enum REG : uint8_t { + CR0 = 0x00, + CR1 = 0x01, + MASK = 0x02, + CJHF = 0x03, + CJLF = 0x04, + LTHFTH = 0x05, + LTHFTL = 0x06, + LTLFTH = 0x07, + LTLFTL = 0x08, + CJTO = 0x09, + CJTH = 0x0A, + CJTL = 0x0B, + LTCBH = 0x0C, + LTCBM = 0x0D, + LTCBL = 0x0E, + SR = 0x0F +}; + +// CR0 bit masks. +constexpr uint8_t CR0_CONV_MODE = 0x80; // 1 = automatic, 0 = normally off +constexpr uint8_t CR0_1SHOT = 0x40; // 1 = trigger one-shot conversion +constexpr uint8_t CR0_OCFAULT = 0x30; // Fault mode bits [5:4] +constexpr uint8_t CR0_CJ = 0x08; // 1 = enable cold-junction sensor +constexpr uint8_t CR0_FAULT = 0x04; // 1 = fault detection enable +constexpr uint8_t CR0_FAULTCLR = 0x02; // 1 = clear fault status +constexpr uint8_t CR0_50HZ = 0x01; // 1 = 50Hz, 0 = 60Hz + +// CR1 bit masks and field values. +constexpr uint8_t CR1_AVG_MASK = 0x70; // Averaging [6:4] +constexpr uint8_t CR1_TYPE_MASK = 0x0F; // Thermocouple type [3:0] + +constexpr uint8_t CR1_AVG_1 = 0x00; +constexpr uint8_t CR1_AVG_2 = 0x10; +constexpr uint8_t CR1_AVG_4 = 0x20; +constexpr uint8_t CR1_AVG_8 = 0x30; +constexpr uint8_t CR1_AVG_16 = 0x40; + +constexpr uint8_t CR1_TYPE_B = 0x00; +constexpr uint8_t CR1_TYPE_E = 0x01; +constexpr uint8_t CR1_TYPE_J = 0x02; +constexpr uint8_t CR1_TYPE_K = 0x03; +constexpr uint8_t CR1_TYPE_N = 0x04; +constexpr uint8_t CR1_TYPE_R = 0x05; +constexpr uint8_t CR1_TYPE_S = 0x06; +constexpr uint8_t CR1_TYPE_T = 0x07; + +// MASK register bits (1 = mask fault). +constexpr uint8_t MASK_CJHF = 0x01; // Cold-junction high +constexpr uint8_t MASK_CJLF = 0x02; // Cold-junction low +constexpr uint8_t MASK_TCHF = 0x04; // Thermocouple high +constexpr uint8_t MASK_TCLF = 0x08; // Thermocouple low +constexpr uint8_t MASK_OVUV = 0x10; // Over/under voltage +constexpr uint8_t MASK_OPEN = 0x20; // Open-circuit + +// SR (fault status) bits. +constexpr uint8_t SR_CJHF = 0x01; +constexpr uint8_t SR_CJLF = 0x02; +constexpr uint8_t SR_TCHF = 0x04; +constexpr uint8_t SR_TCLF = 0x08; +constexpr uint8_t SR_OVUV = 0x10; +constexpr uint8_t SR_OPEN = 0x20; +constexpr uint8_t SR_RANGE = 0x40; // Linearized temperature out of range +constexpr uint8_t SR_CJ_RANGE = 0x80; // Cold-junction temperature out of range + +} // namespace MAX31856_REG + +#endif // MAX31856_REGS_HPP_