39
39
_EXTERNAL_TEMP_MSB = const (0x01 )
40
40
_EXTERNAL_TEMP_LSB = const (0x10 )
41
41
42
- _STATUS = const (0x02 )
43
42
_REG_CONFIG = const (0x03 )
44
43
_TEMP_FORCE = const (0x0C )
45
44
_TACH_LSB = const (0x46 )
49
48
_FAN_CONFIG = const (0x4A )
50
49
_FAN_SPINUP = const (0x4B )
51
50
_REG_FAN_SETTING = const (0x4C )
52
- _PWM_FREQ = const (0x4D )
53
- _PWM_DIV = const (0x4E )
54
- _LUT_HYSTERESIS = const (0x4F )
55
51
56
- _TEMP_FILTER = const (0xBF )
57
52
_REG_PARTID = const (0xFD ) # 0x16
58
53
_REG_MFGID = const (0xFE ) # 0xFF16
59
54
62
57
63
58
_I2C_ADDR = const (0x4C )
64
59
_FAN_RPM_DIVISOR = const (5400000 )
65
- _TEMP_LSB = 0.125
66
-
67
-
68
- def _speed_to_lsb (percentage ):
69
- return round ((percentage / 100.0 ) * MAX_LUT_SPEED )
70
-
71
-
72
- def _lsb_to_speed (lsb_speed ):
73
- return round ((lsb_speed / MAX_LUT_SPEED ) * 100.0 )
74
-
75
-
76
- class FanSpeedLUT :
77
- """A class used to provide a dict-like interface to the EMC2101's Temperature to Fan speed
78
- Look Up Table"""
79
-
80
- # seems like a pain but ¯\_(ツ)_/¯
81
- _fan_lut_t1 = UnaryStruct (0x50 , "<B" )
82
- _fan_lut_s1 = UnaryStruct (0x51 , "<B" )
83
-
84
- _fan_lut_t2 = UnaryStruct (0x52 , "<B" )
85
- _fan_lut_s2 = UnaryStruct (0x53 , "<B" )
86
-
87
- _fan_lut_t3 = UnaryStruct (0x54 , "<B" )
88
- _fan_lut_s3 = UnaryStruct (0x55 , "<B" )
89
-
90
- _fan_lut_t4 = UnaryStruct (0x56 , "<B" )
91
- _fan_lut_s4 = UnaryStruct (0x57 , "<B" )
92
-
93
- _fan_lut_t5 = UnaryStruct (0x58 , "<B" )
94
- _fan_lut_s5 = UnaryStruct (0x59 , "<B" )
95
-
96
- _fan_lut_t6 = UnaryStruct (0x5A , "<B" )
97
- _fan_lut_s6 = UnaryStruct (0x5B , "<B" )
98
-
99
- _fan_lut_t7 = UnaryStruct (0x5C , "<B" )
100
- _fan_lut_s7 = UnaryStruct (0x5D , "<B" )
101
-
102
- _fan_lut_t8 = UnaryStruct (0x5E , "<B" )
103
- _fan_lut_s8 = UnaryStruct (0x5F , "<B" )
104
-
105
- def __init__ (self , fan_obj ):
106
- self .emc_fan = fan_obj
107
- self .lut_values = {}
108
- self .i2c_device = fan_obj .i2c_device
109
-
110
- def __getitem__ (self , index ):
111
- if not isinstance (index , int ):
112
- raise IndexError
113
- if not index in self .lut_values :
114
- raise IndexError
115
- return self .lut_values [index ]
116
-
117
- def __setitem__ (self , index , value ):
118
- if not isinstance (index , int ):
119
- raise IndexError
120
- self .lut_values [index ] = value
121
- self ._set_lut (self .lut_values )
122
-
123
- def __repr__ (self ):
124
- """return the official string representation of the LUT"""
125
- return "FanSpeedLUT <%x>" % id (self )
126
-
127
- def __str__ (self ):
128
- """return the official string representation of the LUT"""
129
- value_strs = []
130
- lut_keys = list (self .lut_values .keys ())
131
- lut_keys .sort ()
132
- for temp in lut_keys :
133
- fan_drive = self .lut_values [temp ]
134
- value_strs .append ("%d deg C => %.1f%% duty cycle" % (temp , fan_drive ))
135
-
136
- return "\n " .join (value_strs )
137
-
138
- def __len__ (self ):
139
- return len (self .lut_values )
140
-
141
- # this function does a whole lot of work to organized the user-supplied lut dict into
142
- # their correct spot within the lut table as pairs of set registers, sorted with the lowest
143
- # temperature first
144
-
145
- def _set_lut (self , lut_dict ):
146
- lut_keys = list (lut_dict .keys ())
147
- lut_size = len (lut_dict )
148
- # Make sure we're not going to try to set more entries than we have slots
149
- if lut_size > 8 :
150
- raise AttributeError ("LUT can only contain a maximum of 8 items" )
151
-
152
- # we want to assign the lowest temperature to the lowest LUT slot, so we sort the keys/temps
153
- for k in lut_keys :
154
- # Verify that the value is a correct amount
155
- lut_value = lut_dict [k ]
156
- if lut_value > 100.0 or lut_value < 0 :
157
- raise AttributeError ("LUT values must be a fan speed from 0-100%" )
158
-
159
- # add the current temp/speed to our internal representation
160
- self .lut_values [k ] = lut_value
161
- current_mode = self .emc_fan .lut_enabled
162
-
163
- # Disable the lut to allow it to be updated
164
- self .emc_fan .lut_enabled = False
165
-
166
- # get and sort the new lut keys so that we can assign them in order
167
- lut_keys = list (self .lut_values .keys ())
168
- lut_keys .sort ()
169
- for idx , current_temp in enumerate (sorted (self .lut_values .keys ())):
170
- current_speed = _speed_to_lsb (self .lut_values [current_temp ])
171
- setattr (self , "_fan_lut_t%d" % (idx + 1 ), current_temp )
172
- setattr (self , "_fan_lut_s%d" % (idx + 1 ), current_speed )
173
-
174
- # Set the remaining LUT entries to the default (Temp/Speed = max value)
175
- for idx in range (8 )[len (self .lut_values ) :]:
176
- setattr (self , "_fan_lut_t%d" % (idx + 1 ), MAX_LUT_TEMP )
177
- setattr (self , "_fan_lut_s%d" % (idx + 1 ), MAX_LUT_SPEED )
178
- self .emc_fan .lut_enabled = current_mode
179
60
180
61
181
62
class CV :
@@ -285,11 +166,6 @@ class EMC2101: # pylint: disable=too-many-instance-attributes
285
166
"""When set to True, the magnitude of the fan output signal is inverted, making 0 the maximum
286
167
value and 100 the minimum value"""
287
168
288
- _fan_pwm_clock_select = RWBit (_FAN_CONFIG , 3 )
289
- _fan_pwm_clock_override = RWBit (_FAN_CONFIG , 2 )
290
- _pwm_freq = RWBits (5 , _PWM_FREQ , 0 )
291
- _pwm_freq_div = UnaryStruct (_PWM_DIV , "<B" )
292
-
293
169
dac_output_enabled = RWBit (_REG_CONFIG , 4 )
294
170
"""When set, the fan control signal is output as a DC voltage instead of a PWM signal"""
295
171
@@ -299,27 +175,18 @@ class EMC2101: # pylint: disable=too-many-instance-attributes
299
175
_spin_time = RWBits (3 , _FAN_SPINUP , 0 )
300
176
_spin_tach_limit = RWBit (_FAN_SPINUP , 5 )
301
177
302
- lut_temperature_hysteresis = UnaryStruct (_LUT_HYSTERESIS , "<B" )
303
- """The amount of hysteresis in Degrees celcius of hysteresis applied to temperature readings
304
- used for the LUT. As the temperature drops, the controller will switch to a lower LUT entry when
305
- the measured value is belowthe lower entry's threshold, minus the hysteresis value"""
306
-
307
178
def __init__ (self , i2c_bus ):
308
179
self .i2c_device = i2cdevice .I2CDevice (i2c_bus , _I2C_ADDR )
309
180
310
181
if not self ._part_id in [0x16 , 0x28 ] or self ._mfg_id != 0x5D :
311
182
raise AttributeError ("Cannot find a EMC2101" )
312
- # self._lut = {}
313
183
314
184
self .initialize ()
315
- self ._lut = FanSpeedLUT (self )
316
185
317
186
def initialize (self ):
318
187
"""Reset the controller to an initial default configuration"""
319
188
self ._tach_mode_enable = True
320
- self .lut_enabled = False
321
189
self ._enabled_forced_temp = False
322
- self ._fan_pwm_clock_override = True
323
190
self ._spin_tach_limit = False
324
191
325
192
@property
@@ -339,54 +206,6 @@ def external_temperature(self):
339
206
340
207
return full_tmp
341
208
342
- def set_pwm_clock (self , use_preset = False , use_slow = False ):
343
- """
344
- Select the PWM clock source, chosing between two preset clocks or by configuring the
345
- clock using `pwm_frequency` and `pwm_frequency_divisor`.
346
-
347
- :param bool use_preset:
348
- True: Select between two preset clock sources
349
- False: The PWM clock is set by `pwm_frequency` and `pwm_frequency_divisor`
350
- :param bool use_slow:
351
- True: Use the 1.4kHz clock
352
- False: Use the 360kHz clock.
353
- :type priority: integer or None
354
- :return: None
355
- :raises AttributeError: if use_preset is not a `bool`
356
- :raises AttributeError: if use_slow is not a `bool`
357
-
358
- """
359
-
360
- if not isinstance (use_preset , bool ):
361
- raise AttributeError ("use_preset must be given a bool" )
362
- if not isinstance (use_slow , bool ):
363
- raise AttributeError ("use_slow_pwm must be given a bool" )
364
-
365
- self ._fan_pwm_clock_override = not use_preset
366
- self ._fan_pwm_clock_select = use_slow
367
-
368
- @property
369
- def pwm_frequency (self ):
370
- """Selects the base clock frequency used for the fan PWM output"""
371
- return self ._pwm_freq
372
-
373
- @pwm_frequency .setter
374
- def pwm_frequency (self , value ):
375
- if value < 0 or value > 0x1F :
376
- raise AttributeError ("pwm_frequency must be from 0-31" )
377
- self ._pwm_freq = value
378
-
379
- @property
380
- def pwm_frequency_divisor (self ):
381
- """The Divisor applied to the PWM frequency to set the final frequency"""
382
- return self ._pwm_freq_div
383
-
384
- @pwm_frequency_divisor .setter
385
- def pwm_frequency_divisor (self , divisor ):
386
- if divisor < 0 or divisor > 255 :
387
- raise AttributeError ("pwm_frequency_divisor must be from 0-255" )
388
- self ._pwm_freq_div = divisor
389
-
390
209
@property
391
210
def fan_speed (self ):
392
211
"""The current speed in Revolutions per Minute (RPM)"""
@@ -422,15 +241,6 @@ def lut_enabled(self):
422
241
to a fan speed. When the LUT is disabled fan speed can be changed with `manual_fan_speed`"""
423
242
return not self ._fan_lut_prog
424
243
425
- @lut_enabled .setter
426
- def lut_enabled (self , enable_lut ):
427
- self ._fan_lut_prog = not enable_lut
428
-
429
- @property
430
- def lut (self ):
431
- """The dict-like representation of the LUT"""
432
- return self ._lut
433
-
434
244
@property
435
245
def tach_limit (self ):
436
246
"""The maximum /minimum speed expected for the fan"""
0 commit comments