33#ifndef MAX3185X_REFRESH_TIME
34#define MAX3185X_REFRESH_TIME 100
36#define MAX6675_REFRESH_TIME 250
40class Max3185xRead final :
public ThreadController<UTILITY_THREAD_STACK_SIZE> {
56 MAX3185X_OPEN_CIRCUIT = 1,
57 MAX3185X_SHORT_TO_GND = 2,
58 MAX3185X_SHORT_TO_VCC = 3,
59 MAX3185X_NO_REPLY = 4,
60 MAX3185X_NOT_ENABLED = 5,
69 for (
size_t i = 0; i < EGT_CHANNEL_COUNT; i++) {
70 auto&
sensor = egtSensors[i];
73 types[i] = UNKNOWN_TYPE;
92 efiPrintf(
"EGT not configured");
99 for (
size_t i = 0; i < EGT_CHANNEL_COUNT; i++) {
104 auto&
sensor = egtSensors[i];
112 while (!chThdShouldTerminateX()) {
113 sysinterval_t refreshTime = MAX3185X_REFRESH_TIME;
114 for (
int i = 0; i < EGT_CHANNEL_COUNT; i++) {
117 Max3185xState ret = getMax3185xEgtValues(i, &value, NULL);
118 if (ret == MAX3185X_OK) {
119 auto&
sensor = egtSensors[i];
124 if (types[i] == MAX6675_TYPE) {
125 refreshTime = MAX6675_REFRESH_TIME;
132 chThdSleepMilliseconds(refreshTime);
135 chThdExit((msg_t)0x0);
145 for (
int i = 0; i < EGT_CHANNEL_COUNT; i++) {
147 efiPrintf(
"EGT CS %d @%s", i + 1,
hwPortname(m_cs[i]));
154 if (driver == NULL) {
155 efiPrintf(
"No SPI selected for EGT");
159 efiPrintf(
"Reading egt(s)");
161 for (
size_t i = 0; i < EGT_CHANNEL_COUNT; i++) {
163 Max3185xState
code = getMax3185xEgtValues(i, &temp, &refTemp);
165 efiPrintf(
"egt%d: type %s, code=%d (%s)", i + 1, getMax3185xTypeName(types[i]),
code, getMax3185xErrorCodeName(
code));
167 if (
code == MAX3185X_OK) {
168 efiPrintf(
" temperature %.4f reference temperature %.2f", temp, refTemp);
175 #define MAX31855_RESERVED_BITS 0x20008
177 #define MAX6675_RESERVED_BITS 0x8002
184 SPIConfig spiConfig = {
186#ifdef _CHIBIOS_RT_CONF_VER_6_1_
199 ((5 << SPI_CR1_BR_Pos) & SPI_CR1_BR) |
204 .cr2 = SPI_CR2_8BIT_MODE
207 const char * getMax3185xErrorCodeName(Max3185xState
code) {
211 case MAX3185X_OPEN_CIRCUIT:
213 case MAX3185X_SHORT_TO_GND:
215 case MAX3185X_SHORT_TO_VCC:
217 case MAX3185X_NO_REPLY:
219 case MAX3185X_NOT_ENABLED:
220 return "not enabled";
226 const char *getMax3185xTypeName(Max3185xType type) {
239 int spi_txrx(
size_t channel, uint8_t tx[], uint8_t rx[],
size_t n)
251 spiAcquireBus(driver);
253 spiStart(driver, &spiConfig);
256 spiExchange(driver, n, tx, rx);
260 spiReleaseBus(driver);
266 int spi_rx16(
size_t channel, uint16_t *data)
273 ret = spi_txrx(
channel, tx, rx, 2);
278 *data = (rx[0] << 8) |
285 int spi_rx32(
size_t channel, uint32_t *data)
292 ret = spi_txrx(
channel, tx, rx, 4);
297 *data = (rx[0] << 24) |
306 Max3185xType detect(
size_t channel)
314 tx[0] = 0x00 | BIT(7);
318 ret = spi_txrx(
channel, tx, rx, 2);
324 tx[1] = BIT(7) | BIT(0) | (2 << 4);
326 tx[2] = (2 << 4) | (3 << 0);
327 ret = spi_txrx(
channel, tx, rx, 3);
334 ret = spi_txrx(
channel, tx, rx, 4);
335 if ((rx[1] == tx[1]) && (rx[2] == tx[2])) {
336 return MAX31856_TYPE;
340 uint32_t data = (rx[0] << 24) |
346 if ((data == 0xffffffff) || (data == 0x0)) {
351 if ((data >> 16) == (data & 0xffff)) {
355 if ((data & MAX31855_RESERVED_BITS) == 0x0) {
356 return MAX31855_TYPE;
362 Max3185xState getMax31855ErrorCode(uint32_t egtPacket) {
363 #define MAX33855_FAULT_BIT BIT(16)
364 #define MAX33855_OPEN_BIT BIT(0)
365 #define MAX33855_GND_BIT BIT(1)
366 #define MAX33855_VCC_BIT BIT(2)
368 if (((egtPacket & MAX31855_RESERVED_BITS) != 0) ||
369 (egtPacket == 0x0) ||
370 (egtPacket == 0xffffffff)) {
371 return MAX3185X_NO_REPLY;
372 }
else if ((egtPacket & MAX33855_OPEN_BIT) != 0) {
373 return MAX3185X_OPEN_CIRCUIT;
374 }
else if ((egtPacket & MAX33855_GND_BIT) != 0) {
375 return MAX3185X_SHORT_TO_GND;
376 }
else if ((egtPacket & MAX33855_VCC_BIT) != 0) {
377 return MAX3185X_SHORT_TO_VCC;
383 Max3185xState getMax31855EgtValues(
size_t channel,
float *temp,
float *coldJunctionTemp) {
385 Max3185xState
code = MAX3185X_NO_REPLY;
388 ret = spi_rx32(
channel, &packet);
390 code = getMax31855ErrorCode(packet);
393 if (
code != MAX3185X_OK) {
399 int16_t tmp = (packet >> 18) & 0x3fff;
403 *temp = (
float) tmp * 0.25;
405 if (coldJunctionTemp) {
407 int16_t tmp = (packet >> 4) & 0xfff;
411 *coldJunctionTemp = (
float)tmp * 0.0625;
417 Max3185xState getMax6675ErrorCode(uint16_t egtPacket) {
418 #define MAX6675_OPEN_BIT BIT(2)
420 if (((egtPacket & MAX6675_RESERVED_BITS) != 0) ||
421 (egtPacket == 0x0) ||
422 (egtPacket == 0xffff)) {
423 return MAX3185X_NO_REPLY;
424 }
else if ((egtPacket & MAX6675_OPEN_BIT) != 0) {
425 return MAX3185X_OPEN_CIRCUIT;
431 Max3185xState getMax31856EgtValues(
size_t channel,
float *temp,
float *coldJunctionTemp)
435 uint8_t tx[7] = {0x0a};
437 int ret = spi_txrx(
channel, tx, rx, 7);
439 return MAX3185X_NO_REPLY;
442 if (rx[6] & BIT(0)) {
443 return MAX3185X_OPEN_CIRCUIT;
444 }
else if (rx[6] & BIT(1)) {
445 return MAX3185X_SHORT_TO_VCC;
450 int32_t tmp = (rx[3] << 11) | (rx[4] << 3) | (rx[5] >> 5);
454 *temp = ((
float)tmp) / 128.0;
458 if (coldJunctionTemp) {
459 int16_t tmp = (rx[1] << 6) | (rx[2] >> 2);
463 *coldJunctionTemp = ((
float)tmp) / 64.0;
469 Max3185xState getMax6675EgtValues(
size_t channel,
float *temp,
float *coldJunctionTemp) {
471 Max3185xState
code = MAX3185X_NO_REPLY;
474 ret = spi_rx16(
channel, &packet);
476 code = getMax6675ErrorCode(packet);
479 if (
code != MAX3185X_OK) {
485 uint16_t tmp = (packet >> 3) & 0x0fff;
486 *temp = (
float) tmp * 0.25;
488 if (coldJunctionTemp) {
490 *coldJunctionTemp = -273.15;
496 Max3185xState getMax3185xEgtValues(
size_t channel,
float *temp,
float *coldJunctionTemp) {
500 return MAX3185X_NOT_ENABLED;
504 if (types[
channel] == UNKNOWN_TYPE) {
509 if (types[
channel] == UNKNOWN_TYPE) {
510 return MAX3185X_NO_REPLY;
513 if (types[
channel] == MAX31855_TYPE) {
514 ret = getMax31855EgtValues(
channel, temp, coldJunctionTemp);
515 }
else if (types[
channel] == MAX31856_TYPE) {
516 ret = getMax31856EgtValues(
channel, temp, coldJunctionTemp);
517 }
else if (types[
channel] == MAX6675_TYPE) {
518 ret = getMax6675EgtValues(
channel, temp, coldJunctionTemp);
521 if (ret == MAX3185X_NO_REPLY) {
528 Max3185xType types[EGT_CHANNEL_COUNT];
void initSpiCsNoOccupy(SPIConfig *spiConfig, brain_pin_e csPin)
void initSpiCs(SPIConfig *spiConfig, brain_pin_e csPin)
virtual bool hasSensor() const
Base class for sensors that compute a value on one thread, and want to make it available to consumers...
void setValidValue(float value, efitick_t timestamp)
A base class for a controller that requires its own thread.
virtual void ThreadTask()=0
void start()
Start the thread.
void stop()
Request thread termination and waits for termination.
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
static constexpr engine_configuration_s * engineConfiguration
SPIDriver * getSpiDevice(spi_device_e spiDevice)
static Lps25Sensor sensor(device)
static void showEgtInfo()
void initMax3185x(spi_device_e device, egt_cs_array_t max31855_cs)
void startMax3185x(spi_device_e device, egt_cs_array_t max31855_cs)
static Max3185xRead instance
const char * hwPortname(brain_pin_e brainPin)
void brain_pin_markUnused(brain_pin_e brainPin)
bool isBrainPinValid(brain_pin_e brainPin)
brain_pin_e[EGT_CHANNEL_COUNT] egt_cs_array_t
Base class for a sensor that has its value asynchronously set, then later retrieved by a consumer.
spi_device_e max31855spiDevice