Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added SPI baudrate argument, high res temperature reading, and autoconvert function #28

Merged
merged 5 commits into from
Mar 11, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 60 additions & 3 deletions adafruit_max31856.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ class MAX31856:
:param ~microcontroller.Pin cs: The pin used for the CS signal.
:param ~adafruit_max31856.ThermocoupleType thermocouple_type: The type of thermocouple.\
Default is Type K.
:param ~int sampling: Number of samples to be averaged [1,2,4,8,16]
:param ~bool filter_50hz: Filter 50Hz mains frequency instead of 60Hz
:param ~int baudrate: The SPI baudrate. Default is 500000.

**Quickstart: Importing and using the MAX31856**

Expand Down Expand Up @@ -164,8 +163,9 @@ def __init__(
spi: SPI,
cs: DigitalInOut, # pylint: disable=invalid-name
thermocouple_type: int = ThermocoupleType.K,
baudrate: int = 500000,
) -> None:
self._device = SPIDevice(spi, cs, baudrate=500000, polarity=0, phase=1)
self._device = SPIDevice(spi, cs, baudrate=baudrate, polarity=0, phase=1)

# assert on any fault
self._write_u8(_MAX31856_MASK_REG, 0x0)
Expand Down Expand Up @@ -253,6 +253,35 @@ def unpack_temperature(self) -> float:

return temp_float

def read_high_res_temp(self) -> float:
"""Reads 19-bit temperature data from the sensor and returns it in degrees Celsius.

Reading must have already been initiated via:
`initiate_one_shot_measurement` or `start_autoconverting`.

Returns:
float: temperature in degrees Celsius
"""
# Per datasheet, temperature resolution in °C per LSB
resolution = 0.0078125

# Read the temperature registers
raw_bytes = self._read_sequential_registers(_MAX31856_LTCBH_REG, 3)
# Extract individual bytes from the byte array
high_byte = raw_bytes[0] # First byte
mid_byte = raw_bytes[1] # Second byte
low_byte = raw_bytes[2] # Third byte

# Combine the bytes into a single 19-bit value
combined = (high_byte << 11) | (mid_byte << 3) | (low_byte >> 5)

# Adjust for two's complement (sign extension for negative values)
if combined & 0x40000: # Check if 19th bit is set (negative temperature)
combined = combined - 0x80000

# Convert to temperature using the resolution
return combined * resolution

@property
def reference_temperature(self) -> float:
"""Wait to retrieve temperature of the cold junction in degrees Celsius. (read-only)"""
Expand Down Expand Up @@ -363,6 +392,21 @@ def initiate_one_shot_measurement(self) -> None:
# write it back with the new values, prompting the sensor to perform a measurement
self._write_u8(_MAX31856_CR0_REG, conf_reg_0)

def start_autoconverting(self) -> None: # pylint: disable=no-self-use
"""Starts autoconverting temperature measurements.
The sensor will perform a measurement every ~100ms.
"""
# read the current value of the first config register
conf_reg_0 = self._read_register(_MAX31856_CR0_REG, 1)[0]

# and the complement to guarantee the oneshot bit is unset
conf_reg_0 &= ~_MAX31856_CR0_1SHOT
# or the autoconvert bit to ensure it is set
conf_reg_0 |= _MAX31856_CR0_AUTOCONVERT

# write it back with the new values, prompting the sensor to perform a measurement
self._write_u8(_MAX31856_CR0_REG, conf_reg_0)

@property
def oneshot_pending(self) -> bool:
"""A boolean indicating the status of the one-shot flag.
Expand All @@ -386,6 +430,19 @@ def _read_register(self, address: int, length: int) -> bytearray:
device.readinto(self._BUFFER, end=length)
return self._BUFFER[:length]

def _read_sequential_registers(self, start_addr, num_registers=3) -> bytearray:
"""
Read a sequence of `num_registers` registers, starting from `start_addr`.
"""
assert num_registers >= 1, "Number of registers to read must be at least 1"
buf = bytearray(num_registers)
with self._device as device:
# Send read command and start address
device.write(bytearray([start_addr & 0x7F]))
# Read the specified number of registers into the buffer
device.readinto(buf)
return buf

def _write_u8(self, address: int, val: int) -> None:
# Write an 8-bit unsigned value to the specified 8-bit address.
with self._device as device:
Expand Down
Loading