-
Notifications
You must be signed in to change notification settings - Fork 0
/
mlx90615.py
358 lines (323 loc) · 15.9 KB
/
mlx90615.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
"""
MicroPython driver for MLX90615 IR temperature I2C sensor :
https://github.com/rcolistete/MicroPython_MLX90615_driver
Version : 0.2.1 @ 2020/04/27
Author: Roberto Colistete Jr. (roberto.colistete at gmail.com)
License: MIT License (https://opensource.org/licenses/MIT)
"""
__version__ = '0.2.1'
import time
import machine
MLX90615_I2C_DEFAULT_ADDR = const(0x5B)
EEPROM_DEFAULT_TIME_MS = const(50) # erase/write EEPROM time in ms
_REG_SLAVE_I2C_ADDRESS = const(0x10) # EEPROM register - slave I2C address
_REG_PWM_TMIN = const(0x10) # EEPROM register - PWM temperature minimum
_REG_PWM_TRANGE = const(0x11) # EEPROM register - PWM temperature range
_REG_CONFIG = const(0x12) # EEPROM register - Config
_REG_EMISSIVITY = const(0x13) # EEPROM register - Emissivity
_REG_ID_LOW = const(0x1E) # EEPROM register - ID number low
_REG_ID_HIGH = const(0x1F) # EEPROM register - ID number high
_REG_RAW_IR_DATA = const(0x25) # RAM register - raw IR data register
_REG_AMBIENT_TEMP = const(0x26) # RAM register - ambient temperature register
_REG_OBJECT_TEMP = const(0x27) # RAM register - object temperature register
_REG_SLEEP = const(0xC6) # Sleep command
class MLX90615:
def __init__(self, i2c, address=MLX90615_I2C_DEFAULT_ADDR):
self.i2c = i2c
self.address = address
self.buf = bytearray(3)
def _crc8(self, icrc, data):
crc = icrc ^ data
for _ in range(8):
crc <<= 1
if crc & 0x0100:
crc ^= 0x07
crc &= 0xFF
return crc
def read16(self, register, crc_check=True):
self.i2c.readfrom_mem_into(self.address, register, self.buf)
lsb = self.buf[0]
msb = self.buf[1]
pec = self.buf[2]
crc = 0
if crc_check:
crc = self._crc8(crc, self.address << 1)
crc = self._crc8(crc, register)
crc = self._crc8(crc, (self.address << 1) + 1)
crc = self._crc8(crc, lsb)
crc = self._crc8(crc, msb)
if (not crc_check) or (pec == crc):
return lsb | (msb << 8)
else:
raise Exception("PEC != CRC8 error in reading register {:02x}.".format(register))
def write16(self, register, data, read_check=True, eeprom_time=EEPROM_DEFAULT_TIME_MS):
lsb = data & 0x00FF
msb = data >> 8
crc = self._crc8(0, self.address << 1)
crc = self._crc8(crc, register)
crc = self._crc8(crc, lsb)
crc = self._crc8(crc, msb)
self.buf[0] = lsb; self.buf[1] = msb; self.buf[2] = crc
self.i2c.writeto_mem(self.address, register, self.buf)
time.sleep_ms(eeprom_time)
if read_check:
try:
data_read = self.read16(register)
except Exception as err:
raise Exception("Error reading after writing to EEPROM register {:02x}.\n{}".format(register, err))
else:
if data != data_read:
raise Exception("Error reading after writing to EEPROM register {:02x}.\n{}".format(register, err))
def read_ambient_temp(self, pec_check=True):
try:
t = self.read16(_REG_AMBIENT_TEMP, crc_check=pec_check)
except Exception as err:
raise Exception("Error reading ambient temperature.\n{}".format(err))
else:
if (t > 0x7FFF):
raise Exception("Invalid ambient temperature error.")
else:
return t*2 - 27315
def read_object_temp(self, pec_check=True):
try:
t = self.read16(_REG_OBJECT_TEMP, crc_check=pec_check)
except Exception as err:
raise Exception("Error reading object temperature.\n{}".format(err))
else:
if (t > 0x7FFF):
raise Exception("Invalid object temperature error.")
else:
return t*2 - 27315
def read_raw_ir_data(self, pec_check=True):
try:
d = self.read16(_REG_RAW_IR_DATA, crc_check=pec_check)
except Exception as err:
raise Exception("Error reading raw IR data.\n{}".format(err))
else:
return d
def read_id(self, pec_check=True):
try:
return self.read16(_REG_ID_LOW, crc_check=pec_check) | (self.read16(_REG_ID_HIGH, crc_check=pec_check) << 16)
except Exception as err:
raise Exception("Error reading sensor ID.\n{}".format(err))
def read_eeprom(self, pec_check=True):
eeprom_data = [0]*0x10
for register in range(0x10, 0x20):
try:
eeprom_data[register - 0x10] = self.read16(register, crc_check=pec_check)
except Exception as err:
raise Exception("Error reading EEPROM.\n{}".format(err))
return eeprom_data
def read_emissivity(self, pec_check=True):
try:
d = self.read16(_REG_EMISSIVITY, crc_check=pec_check)
except Exception as err:
raise Exception("Error reading emissivity from EEPROM. {}".format(err))
if (d >= 32768):
d = 32768 - d
return round(100*d/0x4000)
def set_emissivity(self, value=100, eeprom_read_check=True, eeprom_write_time=EEPROM_DEFAULT_TIME_MS):
if (value >= 5) and (value <= 100):
e = round((value*0x4000)/100)
try:
time.sleep_ms(eeprom_write_time)
self.write16(_REG_EMISSIVITY, 0x0000, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error erasing EEPROM emissivity.\n{}".format(err))
else:
try:
self.write16(_REG_EMISSIVITY, e, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error writing EEPROM emissivity.\n{}".format(err))
else:
raise Exception("Error : emissivity value {} out of range (5 <= e <= 100).".format(value))
def read_i2c_address(self, pec_check=True):
try:
return self.read16(_REG_SLAVE_I2C_ADDRESS, crc_check=pec_check) & 0x007F
except Exception as err:
raise Exception("Error reading EEPROM I2C address.\n{}".format(err))
def set_i2c_address(self, addr=0x5B, eeprom_read_check=False, eeprom_write_time=EEPROM_DEFAULT_TIME_MS):
if self.address == 0:
if (addr >= 0x08) and (addr <= 0x77):
d = 0x3500 | addr
try:
time.sleep_ms(eeprom_write_time)
self.write16(_REG_SLAVE_I2C_ADDRESS, 0x0000, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error erasing EEPROM I2C address.\n{}".format(err))
else:
try:
self.write16(_REG_SLAVE_I2C_ADDRESS, d, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error writing EEPROM I2C address.\n{}".format(err))
else:
raise Exception("Error : new I2C address {:02x} out of range (0x01 <= address <= 0x7F).".format(addr))
else:
raise Exception("Current I2C address of MLX90615 should be 0x00 to avoid errors while setting the new EEPROM I2C address.")
def sleep(self):
crc = self._crc8(0, self.address << 1)
crc = self._crc8(crc, _REG_SLEEP)
self.buf[0] = crc
self.i2c.writeto_mem(self.address, _REG_SLEEP, self.buf)
self.i2c.stop()
def wake(self, scl_pin):
p = machine.Pin(scl_pin, machine.Pin.OUT)
p.value(0)
time.sleep_ms(50)
self.i2c.start()
time.sleep_ms(500)
if ((self.address >= 0x08) and (self.address <= 0x77)) and (not (self.address in self.i2c.scan())):
raise Exception("I2C has not restarted with MLX90615 I2C address {:02x}.".format(self.address))
def pwm_to_i2c(self, scl_pin):
p = machine.Pin(scl_pin, machine.Pin.OUT)
p.value(0)
time.sleep_ms(100)
self.i2c.start()
if ((self.address >= 0x08) and (self.address <= 0x77)) and (not (self.address in self.i2c.scan())):
raise Exception("I2C has not restarted with MLX90615 I2C address {:02x}.".format(self.address))
def read_pwm_tmin(self, pec_check=True):
try:
return self.read16(_REG_PWM_TMIN, crc_check=pec_check)
except Exception as err:
raise Exception("Error reading EEPROM PWM TMIN.\n{}".format(err))
def set_pwm_tmin(self, tmin=0x355B, eeprom_read_check=False, eeprom_write_time=EEPROM_DEFAULT_TIME_MS):
if self.address == 0:
try:
time.sleep_ms(eeprom_write_time)
self.write16(_REG_PWM_TMIN, 0x0000, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error erasing EEPROM PWM TMIN.\n{}".format(err))
else:
try:
self.write16(_REG_PWM_TMIN, tmin, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error writing EEPROM PWM TMIN.\n{}".format(err))
else:
raise Exception("Current I2C address of MLX90615 should be 0x00 to avoid errors while setting the new EEPROM PWM TMIN.")
def read_pwm_trange(self, pec_check=True):
try:
return self.read16(_REG_PWM_TRANGE, crc_check=pec_check)
except Exception as err:
raise Exception("Error reading EEPROM PWM TRANGE.\n{}".format(err))
def set_pwm_trange(self, trange=0x09C3, eeprom_read_check=False, eeprom_write_time=EEPROM_DEFAULT_TIME_MS):
try:
time.sleep_ms(eeprom_write_time)
self.write16(_REG_PWM_TRANGE, 0x0000, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error erasing EEPROM PWM TRANGE.\n{}".format(err))
else:
try:
self.write16(_REG_PWM_TRANGE, trange, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error writing EEPROM PWM TRANGE.\n{}".format(err))
def read_pwm_mode(self, pec_check=True):
try:
return ((self.read16(_REG_CONFIG, crc_check=pec_check) & 0x0001) == 0)
except Exception as err:
raise Exception("Error reading config register from EEPROM.\n{}".format(err))
def set_pwm_mode(self, pwm=False, eeprom_read_check=True, eeprom_write_time=EEPROM_DEFAULT_TIME_MS):
try:
d = self.read16(_REG_CONFIG)
except Exception as err:
raise Exception("Error reading config register from EEPROM. {}".format(err))
else:
d &= 0xFFFE
if not pwm:
d |= 0x0001
try:
time.sleep_ms(eeprom_write_time)
self.write16(_REG_CONFIG, 0x0000, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error erasing EEPROM config register.\n{}".format(err))
else:
try:
self.write16(_REG_CONFIG, d, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error writing EEPROM config register.\n{}".format(err))
def read_pwm_fast(self, pec_check=True):
try:
return ((self.read16(_REG_CONFIG, crc_check=pec_check) & 0x0002) != 0)
except Exception as err:
raise Exception("Error reading config register from EEPROM.\n{}".format(err))
def set_pwm_fast(self, pwm_fast=False, eeprom_read_check=True, eeprom_write_time=EEPROM_DEFAULT_TIME_MS):
try:
d = self.read16(_REG_CONFIG)
except Exception as err:
raise Exception("Error reading config register from EEPROM. {}".format(err))
else:
d &= 0xFFFD
if pwm_fast:
d |= 0x0002
try:
time.sleep_ms(eeprom_write_time)
self.write16(_REG_CONFIG, 0x0000, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error erasing EEPROM config register.\n{}".format(err))
else:
try:
self.write16(_REG_CONFIG, d, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error writing EEPROM config register.\n{}".format(err))
def read_pwm_object_temp(self, pec_check=True):
try:
return ((self.read16(_REG_CONFIG, crc_check=pec_check) & 0x0004) == 0)
except Exception as err:
raise Exception("Error reading config register from EEPROM.\n{}".format(err))
def set_pwm_object_temp(self, object_temp=True, eeprom_read_check=True, eeprom_write_time=EEPROM_DEFAULT_TIME_MS):
try:
d = self.read16(_REG_CONFIG)
except Exception as err:
raise Exception("Error reading config register from EEPROM. {}".format(err))
else:
d &= 0xFFFB
if not object_temp:
d |= 0x0004
try:
time.sleep_ms(eeprom_write_time)
self.write16(_REG_CONFIG, 0x0000, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error erasing EEPROM config register.\n{}".format(err))
else:
try:
self.write16(_REG_CONFIG, d, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error writing EEPROM config register.\n{}".format(err))
def read_iir_filter(self, pec_check=True):
try:
return ((self.read16(_REG_CONFIG, crc_check=pec_check) & 0x7000) >> 12)
except Exception as err:
raise Exception("Error reading config register from EEPROM.\n{}".format(err))
def set_iir_filter(self, iir=1, eeprom_read_check=True, eeprom_write_time=EEPROM_DEFAULT_TIME_MS):
try:
d = self.read16(_REG_CONFIG)
except Exception as err:
raise Exception("Error reading config register from EEPROM. {}".format(err))
else:
d &= 0x8FFF
d |= (iir & 0x0007) << 12
try:
time.sleep_ms(eeprom_write_time)
self.write16(_REG_CONFIG, 0x0000, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error erasing EEPROM config register.\n{}".format(err))
else:
try:
self.write16(_REG_CONFIG, d, read_check=eeprom_read_check, eeprom_time=eeprom_write_time)
time.sleep_ms(eeprom_write_time)
except Exception as err:
raise Exception("Error writing EEPROM config register.\n{}".format(err))