8
8
Brushless fan controller: extended functionality
9
9
10
10
11
- * Author(s): Bryan Siepert
11
+ * Author(s): Bryan Siepert, Ryan Pavlik
12
12
13
13
Implementation Notes
14
14
--------------------
22
22
* Adafruit CircuitPython firmware for the supported boards:
23
23
https://github.com/adafruit/circuitpython/releases
24
24
25
- # * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
26
- # * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
25
+ * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
26
+ * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
27
27
28
- The class defined here may be used instead of adafruit_emc2101.EMC2101,
28
+ The class defined here may be used instead of :class:` adafruit_emc2101.EMC2101` ,
29
29
if your device has enough RAM to support it. This class adds LUT control
30
30
and PWM frequency control to the base feature set.
31
31
"""
32
32
33
33
from micropython import const
34
+ from adafruit_register .i2c_struct_array import StructArray
34
35
from adafruit_register .i2c_struct import UnaryStruct
35
36
from adafruit_register .i2c_bit import RWBit
36
37
from adafruit_register .i2c_bits import RWBits
43
44
_PWM_FREQ = const (0x4D )
44
45
_PWM_DIV = const (0x4E )
45
46
_LUT_HYSTERESIS = const (0x4F )
47
+ _LUT_BASE = const (0x50 )
46
48
47
49
MAX_LUT_SPEED = 0x3F # 6-bit value
48
50
MAX_LUT_TEMP = 0x7F # 7-bit
@@ -56,30 +58,8 @@ class FanSpeedLUT:
56
58
"""A class used to provide a dict-like interface to the EMC2101's Temperature to Fan speed
57
59
Look Up Table"""
58
60
59
- # seems like a pain but ¯\_(ツ)_/¯
60
- _fan_lut_t1 = UnaryStruct (0x50 , "<B" )
61
- _fan_lut_s1 = UnaryStruct (0x51 , "<B" )
62
-
63
- _fan_lut_t2 = UnaryStruct (0x52 , "<B" )
64
- _fan_lut_s2 = UnaryStruct (0x53 , "<B" )
65
-
66
- _fan_lut_t3 = UnaryStruct (0x54 , "<B" )
67
- _fan_lut_s3 = UnaryStruct (0x55 , "<B" )
68
-
69
- _fan_lut_t4 = UnaryStruct (0x56 , "<B" )
70
- _fan_lut_s4 = UnaryStruct (0x57 , "<B" )
71
-
72
- _fan_lut_t5 = UnaryStruct (0x58 , "<B" )
73
- _fan_lut_s5 = UnaryStruct (0x59 , "<B" )
74
-
75
- _fan_lut_t6 = UnaryStruct (0x5A , "<B" )
76
- _fan_lut_s6 = UnaryStruct (0x5B , "<B" )
77
-
78
- _fan_lut_t7 = UnaryStruct (0x5C , "<B" )
79
- _fan_lut_s7 = UnaryStruct (0x5D , "<B" )
80
-
81
- _fan_lut_t8 = UnaryStruct (0x5E , "<B" )
82
- _fan_lut_s8 = UnaryStruct (0x5F , "<B" )
61
+ # 8 (Temperature, Speed) pairs in increasing order
62
+ _fan_lut = StructArray (_LUT_BASE , "<B" , 16 )
83
63
84
64
def __init__ (self , fan_obj ):
85
65
self .emc_fan = fan_obj
@@ -96,10 +76,15 @@ def __getitem__(self, index):
96
76
def __setitem__ (self , index , value ):
97
77
if not isinstance (index , int ):
98
78
raise IndexError
99
- if value > 100.0 or value < 0 :
79
+ if value is None :
80
+ # Assign None to remove this entry
81
+ del self .lut_values [index ]
82
+ elif value > 100.0 or value < 0 :
83
+ # Range check
100
84
raise AttributeError ("LUT values must be a fan speed from 0-100%" )
101
- self .lut_values [index ] = value
102
- self ._set_lut ()
85
+ else :
86
+ self .lut_values [index ] = value
87
+ self ._update_lut ()
103
88
104
89
def __repr__ (self ):
105
90
"""return the official string representation of the LUT"""
@@ -122,16 +107,11 @@ def __len__(self):
122
107
# their correct spot within the lut table as pairs of set registers, sorted with the lowest
123
108
# temperature first
124
109
125
- def _set_lut (self ):
110
+ def _update_lut (self ):
126
111
# Make sure we're not going to try to set more entries than we have slots
127
112
if len (self .lut_values ) > 8 :
128
113
raise AttributeError ("LUT can only contain a maximum of 8 items" )
129
114
130
- # Verify that the value is a correct amount
131
- for speed in self .lut_values .values ():
132
- if speed > 100.0 or speed < 0 :
133
- raise AttributeError ("LUT values must be a fan speed from 0-100%" )
134
-
135
115
# Backup state
136
116
current_mode = self .emc_fan .lut_enabled
137
117
@@ -142,18 +122,20 @@ def _set_lut(self):
142
122
# get and sort the new lut keys so that we can assign them in order
143
123
for idx , current_temp in enumerate (sorted (self .lut_values .keys ())):
144
124
current_speed = _speed_to_lsb (self .lut_values [current_temp ])
145
- setattr (self , "_fan_lut_t%d" % (idx + 1 ), current_temp )
146
- setattr (self , "_fan_lut_s%d" % (idx + 1 ), current_speed )
125
+ self ._set_lut_entry (idx , current_temp , current_speed )
147
126
148
127
# Set the remaining LUT entries to the default (Temp/Speed = max value)
149
- for idx in range (8 )[len (self .lut_values ):]:
150
- setattr (self , "_fan_lut_t%d" % (idx + 1 ), MAX_LUT_TEMP )
151
- setattr (self , "_fan_lut_s%d" % (idx + 1 ), MAX_LUT_SPEED )
128
+ for idx in range (len (self .lut_values ), 8 ):
129
+ self ._set_lut_entry (idx , MAX_LUT_TEMP , MAX_LUT_SPEED )
152
130
self .emc_fan .lut_enabled = current_mode
153
131
132
+ def _set_lut_entry (self , idx , temp , speed ):
133
+ self ._fan_lut [idx * 2 ] = bytearray ((temp ,))
134
+ self ._fan_lut [idx * 2 + 1 ] = bytearray ((speed ,))
135
+
154
136
155
137
class EMC2101_LUT (EMC2101 ): # pylint: disable=too-many-instance-attributes
156
- """Driver for the EMC2101 Fan Controller.
138
+ """Driver for the EMC2101 Fan Controller, with PWM frequency and LUT control .
157
139
:param ~busio.I2C i2c_bus: The I2C bus the EMC is connected to.
158
140
"""
159
141
@@ -239,5 +221,5 @@ def lut_enabled(self, enable_lut):
239
221
240
222
@property
241
223
def lut (self ):
242
- """The dict-like representation of the LUT"""
224
+ """The dict-like representation of the LUT, actually of type :class:`FanSpeedLUT` """
243
225
return self ._lut
0 commit comments