kopia lustrzana https://github.com/SP8EBC/ParaTNC
505 wiersze
10 KiB
C
505 wiersze
10 KiB
C
/*
|
|
* max31865.c
|
|
*
|
|
* Created on: Sep 25, 2022
|
|
* Author: mateusz
|
|
*/
|
|
|
|
#include "rte_wx.h"
|
|
#include "int_average.h"
|
|
#include "drivers/max31865.h"
|
|
#include <math.h>
|
|
|
|
#define DATA_RACE_WORKAROUND
|
|
|
|
#define REFERENCE_RESISTOR 4300.0f
|
|
|
|
#define RTD_A 3.9083e-3
|
|
#define RTD_B -5.775e-7
|
|
|
|
#define MAX31865_INTERVAL 9 //!< Interval between measurements. To convert to second add one and multiply times two
|
|
|
|
int32_t test;
|
|
|
|
//tary specific
|
|
#include "io.h"
|
|
|
|
typedef enum max31865_pool_state_t {
|
|
MAX_UNINITIALIZED,
|
|
MAX_IDLE,
|
|
MAX_INITIALIZED,
|
|
MAX_ERROR,
|
|
MAX_MEASUREMENT_STARTED,
|
|
MAX_REGISTER_REQUESTED,
|
|
MAX_SHUTDOWN,
|
|
MAX_POWER_OFF
|
|
}max31865_pool_state_t;
|
|
|
|
static const float max31865_rref_lookup_table[32] =
|
|
{
|
|
430.0f,
|
|
432.0f,
|
|
442.0f,
|
|
470.0f,
|
|
499.0f,
|
|
510.0f,
|
|
560.0f,
|
|
620.0f,
|
|
680.0f,
|
|
768.0f, // index 9
|
|
1000.0f,
|
|
1100.0f,
|
|
1200.0f,
|
|
1300.0f,
|
|
1400.0f,
|
|
1500.0f,
|
|
1600.0f,
|
|
1740.0f,
|
|
1800.0f,
|
|
1910.0f, // index 19
|
|
2000.0f, // index 20
|
|
2100.0f,
|
|
2400.0f,
|
|
2700.0f,
|
|
3000.0f,
|
|
3090.0f,
|
|
3400.0f,
|
|
3900.0f,
|
|
4300.0f, // index 28
|
|
4700.0f, // index 29
|
|
4990.0f, // index 30
|
|
5600.0f // index 31
|
|
|
|
};
|
|
|
|
max31865_pool_state_t max31865_current_state = MAX_UNINITIALIZED;
|
|
|
|
/**
|
|
* reference resistor value
|
|
*/
|
|
float max31865_rref = 0;
|
|
|
|
/**
|
|
* And it's index from the table
|
|
*/
|
|
uint8_t max31865_rref_index = 0;
|
|
|
|
/**
|
|
* This variable is incremented from 0 up to 9 to pause measurement
|
|
* state machine into MAX_SHUTDOWN state. When it reach 9 measurement
|
|
* is triggered
|
|
*/
|
|
uint8_t max31865_shutdown_ticks = 0;
|
|
|
|
/**
|
|
* 1 - bias on
|
|
* 0 - bias on
|
|
*/
|
|
uint8_t max31865_vbias = 0;
|
|
|
|
/**
|
|
* 1 - Auto (continous)
|
|
* 0 - Off (single - shot)
|
|
*/
|
|
uint8_t max31865_conversion_mode = 0;
|
|
|
|
/**
|
|
* Set to one and send config register to trigger single measurement
|
|
*/
|
|
uint8_t max31865_start_singleshot = 0;
|
|
|
|
/**
|
|
* 1 - 3wire
|
|
* 0 - 2 wire or 4 wire
|
|
*/
|
|
uint8_t max31865_rdt_sensor_type = 0;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
uint8_t max31865_fault_detection_config = 0;
|
|
|
|
/**
|
|
* Set to one to clear
|
|
*/
|
|
uint8_t max31865_fault_clear = 0;
|
|
|
|
/**
|
|
* 1 - 50Hz
|
|
* 0 - 60Hz
|
|
*/
|
|
uint8_t max31865_filter_select = 0;
|
|
|
|
uint8_t max31865_buffer[3] = {0u};
|
|
|
|
/**
|
|
* Set to one if MAX has been initialized correctly
|
|
*/
|
|
uint8_t max31865_ok = 0;
|
|
|
|
/**
|
|
* Last raw result read from MAX
|
|
*/
|
|
uint16_t max31865_raw_result = 0;
|
|
|
|
uint16_t max31865_physical_result = 0;
|
|
|
|
/**
|
|
* Value of configuration register which should be currently stored in
|
|
* amplifier
|
|
*/
|
|
uint8_t max31865_current_config_register = 0;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
max31865_qf_t max31865_quality_factor = MAX_QF_UNKNOWN;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
uint8_t max31865_measurements_counter = 0;
|
|
uint8_t max31865_merasurements_error_counter = 0;
|
|
|
|
int_average_t max31865_average;
|
|
|
|
uint8_t max31865_current_fault_status = 0;
|
|
|
|
/**
|
|
* Function generates a content of configuration register basing on
|
|
*/
|
|
static uint8_t max31865_get_config_register(void) {
|
|
|
|
uint8_t out = 0;
|
|
|
|
out |= (max31865_filter_select & 0x01);
|
|
out |= ((max31865_fault_clear & 0x01) << 1);
|
|
out |= ((max31865_fault_detection_config & 0x03) << 2);
|
|
out |= ((max31865_rdt_sensor_type & 0x01) << 4);
|
|
out |= ((max31865_start_singleshot & 0x01) << 5);
|
|
out |= ((max31865_conversion_mode & 0x01) << 6);
|
|
out |= ((max31865_vbias & 0x01) << 7);
|
|
|
|
return out;
|
|
}
|
|
|
|
static void max31865_request_registers(void) {
|
|
|
|
uint8_t result = 0;
|
|
|
|
// check if SPI is busy now
|
|
if (spi_get_current_slave() == 0) {
|
|
// read adres of configuation register
|
|
max31865_buffer[0] = 0x00;
|
|
max31865_buffer[1] = 0x00;
|
|
|
|
// read data for verifiaction
|
|
result = spi_rx_tx_data(1, SPI_TX_FROM_EXTERNAL, SPI_USE_INTERNAL_RX_BUF, max31865_buffer, 10, 1);
|
|
}
|
|
else {
|
|
max31865_current_state = MAX_ERROR;
|
|
}
|
|
|
|
if (result != SPI_OK) {
|
|
max31865_current_state = MAX_ERROR;
|
|
}
|
|
}
|
|
|
|
static void max31865_send_config_register(void) {
|
|
uint8_t result = 0;
|
|
|
|
// check if SPI is busy now
|
|
if (spi_get_current_slave() == 0) {
|
|
max31865_current_config_register = max31865_get_config_register();
|
|
|
|
// read adres of configuation register
|
|
max31865_buffer[0] = 0x80;
|
|
max31865_buffer[1] = max31865_current_config_register;
|
|
|
|
spi_tx_data(1, SPI_TX_FROM_EXTERNAL, max31865_buffer, 2);
|
|
|
|
}
|
|
else {
|
|
max31865_current_state = MAX_ERROR;
|
|
}
|
|
|
|
if (result != SPI_OK) {
|
|
max31865_current_state = MAX_ERROR;
|
|
}
|
|
}
|
|
|
|
void max31865_init(uint8_t rdt_type, uint8_t reference_resistor_index) {
|
|
|
|
uint8_t * rx_data;
|
|
|
|
if (rdt_type == MAX_3WIRE) {
|
|
max31865_rdt_sensor_type = 1;
|
|
}
|
|
else if (rdt_type == MAX_4WIRE) {
|
|
max31865_rdt_sensor_type = 0;
|
|
}
|
|
else {
|
|
max31865_current_state = MAX_UNINITIALIZED;
|
|
|
|
return;
|
|
}
|
|
|
|
if (reference_resistor_index > 31) {
|
|
max31865_current_state = MAX_UNINITIALIZED;
|
|
|
|
return;
|
|
}
|
|
else {
|
|
max31865_rref = max31865_rref_lookup_table[reference_resistor_index];
|
|
}
|
|
|
|
max31865_rref_index = reference_resistor_index;
|
|
|
|
// set filter to 50Hz
|
|
max31865_filter_select = 1;
|
|
|
|
max31865_vbias = 0;
|
|
|
|
max31865_conversion_mode = 0;
|
|
|
|
max31865_send_config_register();
|
|
|
|
spi_wait_for_comms_done();
|
|
|
|
max31865_request_registers();
|
|
|
|
spi_wait_for_comms_done();
|
|
|
|
rx_data = spi_get_rx_data();
|
|
|
|
if (rx_data[0] == max31865_get_config_register()) {
|
|
max31865_ok = 1;
|
|
|
|
max31865_current_state = MAX_INITIALIZED;
|
|
}
|
|
else {
|
|
max31865_ok = 0;
|
|
}
|
|
|
|
}
|
|
|
|
void max31865_init_average(void) {
|
|
int_average_init(&max31865_average);
|
|
}
|
|
|
|
/**
|
|
* This pooler shall be called in two seconds interval
|
|
*/
|
|
void max31865_pool(void) {
|
|
|
|
uint8_t * result_ptr;
|
|
|
|
switch (max31865_current_state) {
|
|
case MAX_IDLE:
|
|
// MAX31865 is powered up but not initialized
|
|
if (max31865_rdt_sensor_type == 1) {
|
|
max31865_init(MAX_3WIRE, max31865_rref_index);
|
|
}
|
|
else {
|
|
max31865_init(MAX_4WIRE, max31865_rref_index);
|
|
}
|
|
|
|
if (max31865_ok == 1) {
|
|
max31865_current_state = MAX_INITIALIZED;
|
|
}
|
|
|
|
break;
|
|
case MAX_INITIALIZED:
|
|
// initialized and ready to start measurement
|
|
max31865_current_state = MAX_MEASUREMENT_STARTED;
|
|
|
|
max31865_start_singleshot = 1;
|
|
|
|
max31865_vbias = 1;
|
|
|
|
// this function may change 'max31865_current_state' internally due to errors
|
|
max31865_send_config_register();
|
|
|
|
// disable VBIAS to reduce power consumption
|
|
max31865_vbias = 0;
|
|
|
|
max31865_start_singleshot = 0;
|
|
|
|
break;
|
|
case MAX_ERROR:
|
|
// go back to idle in case of any error
|
|
max31865_current_state = MAX_IDLE;
|
|
|
|
io___cntrl_vbat_s_enable();
|
|
|
|
max31865_quality_factor = MAX_QF_NOT_AVALIABLE;
|
|
|
|
break;
|
|
case MAX_MEASUREMENT_STARTED:
|
|
// measurement has been started before, so now it's time to request for results
|
|
max31865_request_registers();
|
|
|
|
max31865_current_state = MAX_REGISTER_REQUESTED;
|
|
|
|
break;
|
|
case MAX_REGISTER_REQUESTED:
|
|
// results shall be available
|
|
max31865_current_state = MAX_SHUTDOWN;
|
|
|
|
// check a SPI status
|
|
if (spi_get_rx_state() != SPI_RX_DONE) {
|
|
// if SPI is not done
|
|
max31865_current_state = MAX_ERROR;
|
|
}
|
|
else {
|
|
// get a pointer to results
|
|
result_ptr = spi_get_rx_data();
|
|
|
|
#ifdef DATA_RACE_WORKAROUND
|
|
if ((max31865_current_config_register & 0xDF) == *(result_ptr + 1)) {
|
|
result_ptr++;
|
|
}
|
|
#endif
|
|
|
|
// check communication results by comparing a value of config register
|
|
if ((max31865_current_config_register & 0xDF) == *result_ptr) { // fifth bit read always zero
|
|
// save raw results
|
|
max31865_raw_result = *(result_ptr + 2) | (*(result_ptr + 1) << 8);
|
|
|
|
max31865_raw_result = max31865_raw_result >> 1;
|
|
|
|
// rte_wx_temperature_average_pt = max31865_get_pt100_result(0);
|
|
if (max31865_rdt_sensor_type == 0) {
|
|
max31865_physical_result = max31865_get_result(1000);
|
|
}
|
|
else {
|
|
max31865_physical_result = max31865_get_result(100);
|
|
}
|
|
|
|
int_average(max31865_physical_result, &max31865_average);
|
|
|
|
rte_wx_temperature_average_pt = (int16_t)int_get_min(&max31865_average);
|
|
|
|
max31865_current_fault_status = *(result_ptr + 7);
|
|
|
|
max31865_measurements_counter++;
|
|
|
|
max31865_quality_factor = MAX_QF_FULL;
|
|
}
|
|
else {
|
|
max31865_merasurements_error_counter++;
|
|
|
|
max31865_current_state = MAX_ERROR;
|
|
|
|
max31865_quality_factor = MAX_QF_NOT_AVALIABLE;
|
|
}
|
|
|
|
// disable VBIAS to reduce power consumption
|
|
max31865_vbias = 0;
|
|
|
|
// this function may change 'max31865_current_state' internally due to errors
|
|
//max31865_send_config_register();
|
|
|
|
max31865_shutdown_ticks = 0;
|
|
}
|
|
|
|
// tatry specific
|
|
io___cntrl_vbat_s_disable();
|
|
|
|
break;
|
|
case MAX_SHUTDOWN:
|
|
// MAX31865 is powered up and initialized but PT bias is disabled
|
|
// and no measurement is ongoing
|
|
if (max31865_shutdown_ticks++ > MAX31865_INTERVAL) {
|
|
|
|
max31865_current_state = MAX_IDLE; //
|
|
|
|
io___cntrl_vbat_s_enable();
|
|
|
|
max31865_shutdown_ticks = 0;
|
|
}
|
|
|
|
break;
|
|
case MAX_UNINITIALIZED:
|
|
case MAX_POWER_OFF:
|
|
// supply voltage for MAX31865 is powered off and no communication
|
|
// is currently possible
|
|
break;
|
|
}
|
|
}
|
|
|
|
int32_t max31865_get_pt100_result(void) {
|
|
|
|
int32_t temperature_scaled = 0;
|
|
|
|
float R_ohms = (max31865_raw_result * max31865_rref) / 32768.0f;
|
|
|
|
float num, denom, T ;
|
|
|
|
float c0= -245.19 ;
|
|
float c1 = 2.5293 ;
|
|
float c2 = -0.066046 ;
|
|
float c3 = 4.0422E-3 ;
|
|
float c4 = -2.0697E-6 ;
|
|
float c5 = -0.025422 ;
|
|
float c6 = 1.6883E-3 ;
|
|
float c7 = -1.3601E-6 ;
|
|
|
|
num = R_ohms * (c1 + R_ohms * (c2 + R_ohms * (c3 + R_ohms * c4))) ;
|
|
denom = 1.0 + R_ohms * (c5 + R_ohms * (c6 + R_ohms * c7)) ;
|
|
T = c0 + (num / denom) ;
|
|
|
|
temperature_scaled = (int32_t) (T * 10.0f);
|
|
|
|
return temperature_scaled;
|
|
}
|
|
|
|
int32_t max31865_get_result(uint32_t RTDnominal) {
|
|
|
|
float Z1, Z2, Z3, Z4, Rt, temp;
|
|
|
|
//float R_ohms = (max31865_raw_result * REFERENCE_RESISTOR) / 32768.0f;
|
|
|
|
Rt = max31865_raw_result;
|
|
Rt /= 32768.0f;
|
|
Rt *= max31865_rref;
|
|
|
|
// Serial.print("\nResistance: "); Serial.println(Rt, 8);
|
|
|
|
Z1 = -RTD_A;
|
|
Z2 = RTD_A * RTD_A - (4 * RTD_B);
|
|
Z3 = (4 * RTD_B) / RTDnominal;
|
|
Z4 = 2 * RTD_B;
|
|
|
|
temp = Z2 + (Z3 * Rt);
|
|
temp = (sqrt(temp) + Z1) / Z4;
|
|
|
|
if (temp >= 0)
|
|
return (int32_t) (temp * 10.0f);
|
|
|
|
// ugh.
|
|
Rt /= RTDnominal;
|
|
Rt *= 100; // normalize to 100 ohm
|
|
|
|
float rpoly = Rt;
|
|
|
|
temp = -242.02;
|
|
temp += 2.2228 * rpoly;
|
|
rpoly *= Rt; // square
|
|
temp += 2.5859e-3 * rpoly;
|
|
rpoly *= Rt; // ^3
|
|
temp -= 4.8260e-6 * rpoly;
|
|
rpoly *= Rt; // ^4
|
|
temp -= 2.8183e-8 * rpoly;
|
|
rpoly *= Rt; // ^5
|
|
temp += 1.5243e-10 * rpoly;
|
|
|
|
return (int32_t) (temp * 10.0f);
|
|
|
|
//return 0;
|
|
}
|
|
|
|
max31865_qf_t max31865_get_qf(void) {
|
|
return max31865_quality_factor;
|
|
}
|