Compare commits

...

2 commits

Author SHA1 Message Date
Rahix 25ce0ebdff temp: Proper readout script 2025-08-24 01:18:51 +02:00
Rahix df8ae2263d temp: First version of adc readout 2025-08-24 00:11:16 +02:00
2 changed files with 274 additions and 0 deletions

254
Misc/Temp-Monitor/cs1237.py Normal file
View file

@ -0,0 +1,254 @@
# From: https://github.com/robert-hh/CS1237/blob/f442365eab14fb0b8e2df3858ee46e70bfb56536/cs1237.py
# MIT License
# Copyright (c) 2024 Robert Hammelrath
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from machine import Pin
import time
import micropython
_CMD_READ = const(0x56)
_CMD_WRITE = const(0x65)
class CS1237:
_gain = {1: 0, 2: 1, 64: 2, 128: 3}
_rate = {10: 0, 40: 1, 640: 2, 1280: 3}
def __init__(self, clock, data, gain=64, rate=10, channel=0):
self.clock = clock
self.data = data
self.data.init(mode=Pin.IN)
self.clock.init(mode=Pin.OUT)
self.clock(0)
# determine the number of attempts to find the trigger pulse
start = time.ticks_us()
for _ in range(10):
temp = data()
spent = time.ticks_diff(time.ticks_us(), start)
self.__wait_loop = 4_000_000 // spent
self.config(gain, rate, channel)
# pre-set some values for temperature calibration.
self.ref_value = 769000
self.ref_temp = 20
self.init = self.config
self.buffer_full = False
def __repr__(self):
return "{}(gain={}, rate={}, channel={})".format(self.__qualname__, *self.get_config())
def __call__(self):
return self.read()
def __write_bits(self, value, mask):
clock = self.clock
data = self.data
while mask != 0:
clock(1)
data(1 if (value & mask) != 0 else 0)
clock(0)
mask >>= 1
def __read_bits(self, bits=1):
# duplicate the clock high call to extend the positive pulse
clock = self.clock
data = self.data
value = 0
for _ in range(bits):
clock(1)
clock(1)
clock(0)
value = (value << 1) | data()
return value
def __write_status(self):
# get the config write status bits
return self.__read_bits(3) >> 1
def __write_cmd(self, cmd):
# clock bits 25 and 29, telling that a command follows
clock = self.clock
for _ in range(5):
clock(1)
clock(1)
clock(0)
# write the command word + 1 extra clock cycle
self.data.init(mode=Pin.OUT)
self.__write_bits(cmd << 1, 0x80)
def __write_config(self, config):
value = self.read() # get the ADC value
self.__write_cmd(_CMD_WRITE)
# write the configuration byte + the 46th clock cycle
self.__write_bits(config << 1, 0x100)
self.data.init(mode=Pin.IN)
return value
def __read_config(self):
value = self.read() # get the ADC value
self.__write_cmd(_CMD_READ)
self.data.init(mode=Pin.IN)
# read the configuration byte + 1 extra clock cycle
# And return both config and value
return self.__read_bits(9) >> 1, value
def __drdy_cb(self, data):
self.data.irq(handler=None)
self.__drdy = True
def read(self):
# Set up the trigger for conversion enable.
self.__drdy = False
self.data.irq(trigger=Pin.IRQ_FALLING, handler=self.__drdy_cb)
# Wait for the DRDY event
for _ in range(20000):
if self.__drdy is True:
break
time.sleep_us(50)
else:
self.__drdy = False
self.data.irq(handler=None)
raise OSError("Sensor does not respond")
# Get the data.
result = self.__read_bits(24)
# Check the sign.
if result > 0x7FFFFF:
result -= 0x1000000
return result
def align_buffer(self, buffer):
for i in range(len(buffer)):
if buffer[i] > 0x7FFFFF:
buffer[i] -= 0x1000000
self.data_acquired = True
def __buffer_cb(self, data):
self.data.irq(handler=None)
# Check the sign later when it's time to do so
if self.buffer_index < self.buffer_size:
self.buffer[self.buffer_index] = self.__read_bits(24)
self.buffer_index += 1
self.data.irq(trigger=Pin.IRQ_FALLING, handler=self.__buffer_cb)
else:
micropython.schedule(self.align_buffer, self.buffer)
def read_buffered(self, buffer):
self.data_acquired = False
self.buffer = buffer
self.buffer_size = len(buffer)
self.buffer_index = 0
self.data.irq(trigger=Pin.IRQ_FALLING, handler=self.__buffer_cb)
def get_config(self):
config, _ = self.__read_config()
return (
{value: key for key, value in self._gain.items()}[config >> 2 & 0x03],
{value: key for key, value in self._rate.items()}[config >> 4 & 0x03],
config & 0x03,
)
def config_status(self):
self.read() ## dummy read value
return self.__write_status() >> 1
def config(self, gain=None, rate=None, channel=None):
if gain is not None:
if gain not in self._gain.keys():
raise ValueError("Invalid Gain")
self.gain = self._gain[gain]
if rate is not None:
if rate not in self._rate.keys():
raise ValueError("Invalid rate")
self.rate = self._rate[rate]
if channel is not None:
if not 0 <= channel <= 3:
raise ValueError("Invalid channel")
self.channel = channel
config = self.rate << 4 | self.gain << 2 | self.channel
self.__write_config(config)
def calibrate_temperature(self, temp, ref_value=None):
self.ref_temp = temp
if ref_value is None:
config, self.ref_value = self.__read_config()
if config != 0x02:
# Set gain=1, rate=10, channel=2 (temperature)
self.__write_config(0x02)
# Read the value and restore the previous configuration
self.ref_value = self.__write_config(config)
else:
self.ref_value = ref_value
def temperature(self):
config, value = self.__read_config()
if config != 0x02:
# set gain=1, rate=10, channel=2 (temperature)
self.__write_config(0x02)
# Read the value and restore the previous configuration
value = self.__write_config(config)
return value / self.ref_value * (273.15 + self.ref_temp) - 273.15
def power_down(self):
self.clock(0)
self.clock(1)
def power_up(self):
self.clock(0)
class CS1238(CS1237):
pass
class CS1237P(CS1237):
def read(self):
data = self.data
# wait for the trigger pulse
start = time.ticks_ms()
for _ in range(self.__wait_loop):
if data():
break
else:
raise OSError("No trigger pulse found")
for _ in range(5000):
if not data():
break
time.sleep_us(50)
else:
raise OSError("Sensor does not respond")
result = self.__read_bits(24)
# check the sign.
if result > 0x7FFFFF:
result -= 0x1000000
return result
def read_buffered(self, buffer):
self.data_acquired = False
self.buffer = buffer
self.buffer_size = len(buffer)
for i in range(self.buffer_size):
self.buffer[i] = self.read()
self.data_acquired = True
class CS1238P(CS1237P):
pass

View file

@ -0,0 +1,20 @@
import time
from cs1237 import CS1237
from machine import Pin
clock = Pin(2)
data = Pin(4)
cs1237 = CS1237(clock, data)
cs1237.config(gain=1)
while True:
raw_value = cs1237.read()
value = float(raw_value) / (2**23 - 1)
if value > 0.9999:
value = 0
else:
value = 1 / (1 / value - 1)
temperature = 25 - value
if abs(temperature) < 50:
print(temperature)