linuxcnc-hal-sys 0.1.5

Generated, unsafe Rust bindings to the LinuxCNC HAL submodule
Documentation
component max31855 "Support for the MAX31855 Thermocouple-to-Digital converter using bitbanged spi";

description """The component requires at least 3 pins to bitbang spi protocol, for example:

\\fB loadrt max31855 personality=1\\fR

\\fB setp hm2_6i25.0.gpio.023.is_output true\\fR
\\fB setp hm2_6i25.0.gpio.024.is_output true\\fR

\\fB net spi.clk.in    hm2_6i25.0.gpio.023.out     max31855.0.clk.out\\fR
\\fB net spi.cs.in     hm2_6i25.0.gpio.024.out     max31855.0.cs.out\\fR
\\fB net spi.data0.in  hm2_6i25.0.gpio.033.in_not  max31855.0.data.0.in\\fR

\\fB addf max31855.0.bitbang-spi servo-thread \\fR


The MAX31855 supports a range of -270C to 1800C, however linearization data 
is only available for the -200C to 1350C range, beyond which raw temperature is returned.

Temperature pins are provided for readings in Celsius, Fahrenheit and Kelvin,
temperature values are not updated while a fault condition is present.

The personality parameter is used to indicate the number of sensors.
Multiple sensors share the clk and cs pins, but connect to discrete data input pins.
A maximum of 15 sensors are supported.

""";

pin in  bit data.#.in [15 : (personality & 0xf)]  "Pin(s) connected to data out.";
pin out bit cs.out         "Pin connected to cs, pulled low to shift data, pulled high for data refresh.";
pin out bit clk.out        "Pin connected to clk.";

pin out float temp_celsius.# [15 : (personality & 0xf)] """Temperature output values in Celsius.""";
pin out float temp_fahrenheit.# [15 : (personality & 0xf)] """Temperature in Fahrenheit.""";
pin out float temp_kelvin.# [15 : (personality & 0xf)] """Temperature in Kelvin.""";

pin out bit fault.# [15 : (personality & 0xf)]  "Fault condition detected.";
pin out unsigned fault_flags.# [15 : (personality & 0xf)]  "Fault flags: 0x1  = open sensor, 0x2 short to gnd, 0x3 short to vcc.";

variable unsigned data_frame [15];
variable unsigned state = 1;

function bitbang_spi fp;
license "GPL";
author "Joseph Calderon";

;;

#include "rtapi_math.h"

static float accpoly(float *v, size_t n, float p) {
  int i;
  float ret = 0;
  for (i = 0; i < n; i++) {
    ret += v[i] * pow(p, i);
  }
  return ret;
}

static float to_kelvin(float celsius) {
  return celsius + 273.15;
}

static float to_fahrenheit(float celsius) {
  return celsius * 1.80 + 32.0;
}

static float read_celsius(int32_t v) {
  if (v & 0x7) {
    return nan(""); /* fault bit(s) set */
  }

  /* thermocouple temperature is in bits 31:18 */
  if (v & 0x80000000) {
    v = 0xffffc000 | ((v >> 18) & 0x0003ffff); /* extend sign bit */
  } else {
    v >>= 18;
  }
  return v / 4.0; /* 0.25 degree resolution */
}

static float read_internal(int32_t v) {
  if (v & 0x7) {
    return nan(""); /* fault bit(s) set */
  }

  /* internal temperature is in bits 15:4 */
  v = 0x0000ffff & v;
  if (v & 0x8000) {
    v = 0xfffff000 | ((v >> 4) & 0x00000fff); /* extend sign bit */
  } else {
    v >>= 4;
  }
  return v / 16.0; /* 0.0625 degree resolution */
}

static float read_celsius_adjusted(int32_t sensor_data) {
  float temp_raw = read_celsius(sensor_data);
  float temp_internal = read_internal(sensor_data);
  float voltage_internal = 0, voltage_thermocouple = 0, temp_corrected = 0;

  if (isnan(temp_raw) || isnan(temp_internal))
    return nan("");

  /* NIST K-Type table (http://srdata.nist.gov/its90/download/type_k.tab) */
  float coeff[][11] = {
      {-0.0176004134, 0.0389212035, 1.85587705e-05, -9.94575942e-08,
       3.18409465e-10, -5.60728439e-13, 5.60750581e-16, -3.20207199e-19,
       9.71511487e-23, -1.21047216e-26, 0},
      {0, 0.0394501276, 2.36223732e-05, -3.28589067e-07, -4.99048269e-09,
       -6.75090608e-11, -5.74103265e-13, -3.10888726e-15, -1.0451609e-17,
       -1.9889267e-20, -1.63226981e-23},
      {0, 25.1734619, -1.16628778, -1.08336377, -0.897735417, -0.373423755,
       -0.0866326466, -0.0104505979, -0.000519205758, 0, 0},
      {0, 25.0835495, 0.0786010623, -0.250313103, 0.0831526965, -0.0122803403,
       0.000980403624, -4.41302982e-05, 1.05773404e-06, -1.05275504e-08, 0},
      {-131.805801, 48.3022194, -1.64603102, 0.0546473116, -0.000965071493,
       8.80219341e-06, -3.1108101e-08, 0, 0, 0, 0}};
  int coeff_cols = sizeof(coeff[0]) / sizeof(float);

  /* determine thermocouple voltage by substracting internal temp and adjusting
   * for K-type thermocouple */
  voltage_thermocouple = (temp_raw - temp_internal) * 0.041276;

  if (temp_internal >= 0) {
    float a[] = {0.118597597, -0.000118343203, 126.968597};
    /* for positive temps additional exponential coefficients are needed */
    voltage_internal += accpoly(coeff[0], coeff_cols, temp_internal);
    voltage_internal += a[0] * exp(a[1] * pow((temp_internal - a[2]), 2));
  } else if (temp_internal < 0) {
    voltage_internal += accpoly(coeff[1], coeff_cols, temp_internal);
  }

  float voltage_total = voltage_thermocouple + voltage_internal;

  /* linearize temperature depending on voltage range */
  if (voltage_total < 0) {
    /* Temperature is between -200 and 0C. */
    temp_corrected += accpoly(coeff[2], coeff_cols, voltage_total);
  } else if (voltage_total < 20.644) {
    /* Temperature is between 0C and 500C. */
    temp_corrected += accpoly(coeff[3], coeff_cols, voltage_total);
  } else if (voltage_total < 54.886) {
    /* Temperature is between 500C and 1372C. */
    temp_corrected += accpoly(coeff[4], coeff_cols, voltage_total);
  } else {
    /* NIST only has data for K-type thermocouples from -200C to +1372C. */
    temp_corrected = temp_raw;
  }

  return temp_corrected;
}

FUNCTION(bitbang_spi) {
  int nbit = (state >> 1) & 0x3f;
  int delay = (state >> 7) & 0x3ff;
  int cs = state & 0x1;

  clk_out ^= 0x1;
  if (cs) {
    /* data refreshes when cs is pulled high */
    delay--;
    if (delay <= 0) {
      nbit = 32;
      cs = 0;
    }
  } else {
    int i, n = (personality > 15) ? 15 : personality;
    /* with cs low pull data bits when clock is high */
    if (clk_out) {
      for (i = 0; i < n; i++) {
        data_frame[i] |= (data_in(i) << nbit);
      }
      nbit--;
    }
    if (nbit < 0) {
      for (i = 0; i < n; i++) {
        float f = read_celsius_adjusted((int32_t)data_frame[i]);
        fault(i) = (data_frame[i] & 0x7) ? TRUE : FALSE;
        fault_flags(i) = data_frame[i] & 0x7;
        if (isnan(f)) {
          rtapi_print("max31855: sensor %d detected fault %x\n", i, data_frame[i] & 0x7);
        } else {
          temp_celsius(i) = f;
          temp_fahrenheit(i) = to_fahrenheit(f);
          temp_kelvin(i) = to_kelvin(f);
        }
        data_frame[i] = 0;
      }
      nbit = 0;
      cs = 1;
    }
    delay++;
  }
  state = (delay << 7) | (nbit << 1) | cs;
  cs_out = cs;
}