Skip to content

Commit

Permalink
updated demo
Browse files Browse the repository at this point in the history
  • Loading branch information
siddacious committed Oct 13, 2020
1 parent dd8fcf8 commit 6c1ff14
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 88 deletions.
237 changes: 152 additions & 85 deletions adafruit_emc2101.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,110 +36,133 @@

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EMC2101.git"
_INTERNAL_TEMP = const(0x00)
_EXTERNAL_TEMP_MSB = const(0x01)
_EXTERNAL_TEMP_LSB = const(0x10)
_TACH_LSB = const(0x46)
_TACH_MSB = const(0x47)
_REG_FAN_SETTING =const(0x4C)
foo = """
# 00h R Internal Temperature "Stores the Internal Temperature" 00h Page 33
# 02h R Status "Reports internal, external, and TCRIT alarms" 00h Page 33
# 00h R Internal Temperature "Stores the Internal Temperature" 00h Page 33
# 02h R Status "Reports internal, external, and TCRIT alarms" 00h Page 33
# 03h and 09h R/W Configuration "Alert Mask, STANDBY, TCRIT override, Alert Fault
# Queue" 00h Page 34
# 04h and 0Ah R/W Conversion Rate Sets conversion rate "08h (16 / sec)" Page 35
# Queue" 00h Page 34
# 04h and 0Ah R/W Conversion Rate Sets conversion rate "08h (16 / sec)" Page 35
# 4Ah R/W FAN Configuration "defines polarity of PWM or DAC" 20h Page 41
# 46h R TACH Reading Low Byte "Stores the lower 6 bits of the TACH count. and theTACH configuration bits" FFh Page 40
# 4Ah R/W FAN Configuration "defines polarity of PWM or DAC" 20h Page 41
# 46h R TACH Reading Low Byte "Stores the lower 6 bits of the TACH count. and theTACH configuration bits" FFh Page 40
# 47h R TACH Reading High Byte "Stores the upper 8 bits of
# the TACH count." FFh Page 40
# 48h R/W TACH Limit Low Byte "Stores the lower 6 bits ofthe TACH Limit" FFh Page 40
# 49h R/W TACH Limit High Byte "Stores the upper 8 bits ofthe TACH Limit" FFh Page 40
# the TACH count." FFh Page 40
# 48h R/W TACH Limit Low Byte "Stores the lower 6 bits ofthe TACH Limit" FFh Page 40
# 49h R/W TACH Limit High Byte "Stores the upper 8 bits ofthe TACH Limit" FFh Page 40
# 19h R/W TCRIT Temp Limit "Fan will be set to full speedif external temp above this
# value" "55h
# (85°C)" Page 36
# (85°C)" Page 36
# 21h R/W TCRIT Hysteresis "Amount of hysteresisapplied to TCRIT Temp
# (1LSB = 1°C)" "0Ah
# (10°C)" Page 36
# (10°C)" Page 36
# 4Ah R/W FAN Configuration "defines polarity of PWM or
# DAC" 20h Page 41
# 4Bh R/W Fan Spin-up Sets Spin Up options 3Fh Page 42
# 4Ch R/W Fan Setting Sets PWM or DAC value 00h Page 43
# DAC" 20h Page 41
# 4Bh R/W Fan Spin-up Sets Spin Up options 3Fh Page 42
# 4Ch R/W Fan Setting Sets PWM or DAC value 00h Page 43
# 4Dh R/W PWM Frequency "Sets the final PWM
# Frequency" 17h Page 44
# Frequency" 17h Page 44
# 4Eh R/W PWM Frequency Divide "Sets the base PWM
# frequency" 01h Page 44
# frequency" 01h Page 44
# ##### LUT
# 50h "R/W (See
# Note 6.1)" Lookup Table Temp Setting 1 "Look Up Table
# Temperature Setting 1" 7Fh Page 46
# Temperature Setting 1" 7Fh Page 46
# 51h "R/W (See
# Note 6.1)" Lookup Table Fan Setting 1 "Associated Fan Setting for
# Temp Setting 1" 3Fh Page 46
# Temp Setting 1" 3Fh Page 46
# 52h "R/W (See
# Note 6.1)" Lookup Table Temp Setting 2 "Look Up Table
# Temperature Setting 2" 7Fh Page 46
# Temperature Setting 2" 7Fh Page 46
# 53h "R/W (See
# Note 6.1)" Lookup Table Fan Setting 2 "Associated Fan Setting for
# Temp Setting 2" 3Fh Page 46
# Temp Setting 2" 3Fh Page 46
# 54h "R/W (See
# Note 6.1)" Lookup Table Temp Setting 3 "Look Up Table
# Temperature Setting 3" 7Fh Page 46
# Temperature Setting 3" 7Fh Page 46
# 55h "R/W (See
# Note 6.1)" Lookup Table Fan Setting 3 "Associated Fan Setting for
# Temp Setting 3" 3Fh Page 46
# Temp Setting 3" 3Fh Page 46
# 56h "R/W (See
# Note 6.1)" Lookup Table Temp Setting 4 "Look Up Table
# Temperature Setting 4" 7Fh Page 46
# Temperature Setting 4" 7Fh Page 46
# 57h "R/W (See
# Note 6.1)" Lookup Table Fan Setting 4 "Associated Fan Setting for
# Temp Setting 4" 3Fh Page 46
# Temp Setting 4" 3Fh Page 46
# 58h "R/W (See
# Note 6.1)" Lookup Table Temp Setting 5 "Look Up Table
# Temperature Setting 5" 7Fh Page 46
# Temperature Setting 5" 7Fh Page 46
# 59h "R/W (See
# Note 6.1)" Lookup Table Fan Setting 5 "Associated Fan Setting for
# Temp Setting 5" 3Fh Page 46
# Temp Setting 5" 3Fh Page 46
# 5Ah "R/W (See
# Note 6.1)" Lookup Table Temp Setting 6 "Look Up Table
# Temperature Setting 6" 7Fh Page 46
# Temperature Setting 6" 7Fh Page 46
# 5Bh "R/W (See
# Note 6.1)" Lookup Table Fan Setting 6 "Associated Fan Setting for
# Temp Setting 6" 3Fh Page 46
# Temp Setting 6" 3Fh Page 46
# 5Ch "R/W (See
# Note 6.1)" Lookup Table Temp Setting 7 "Look Up Table
# Temperature Setting 7" 7Fh Page 46
# Temperature Setting 7" 7Fh Page 46
# 5Dh "R/W (See
# Note 6.1)" Lookup Table Fan Setting 7 "Associated Fan Setting for
# Temp Setting 7" 3Fh Page 46
# Temp Setting 7" 3Fh Page 46
# 5Eh "R/W (See
# Note 6.1)" Lookup Table Temp Setting 8 "Look Up Table
# Temperature Setting 8" 7Fh Page 46
# Temperature Setting 8" 7Fh Page 46
# 5Fh "R/W (See
# Note 6.1)" Lookup Table Fan Setting 8 "Associated Fan Setting for
# Temp Setting 8" 3Fh Page 46
# Temp Setting 8" 3Fh Page 46
"""
_REG_PARTID = const(0xFD) # 0x16
_REG_MFGID = const(0xFE) # 0xFF16

# _REG_CONFIG = const(0x09)
_REG_CONFIG = const(0x03)
# FDh R Product ID ID 16h or 28h Page 48
# FEh R Manufacturer ID SMSC 5Dh Page 48


_INTERNAL_TEMP = const(0x00)
_EXTERNAL_TEMP_MSB = const(0x01)
_EXTERNAL_TEMP_LSB = const(0x10)
_TACH_LSB = const(0x46)
_TACH_MSB = const(0x47)
_REG_FAN_SETTING = const(0x4C)
_REG_PARTID = const(0xFD) # 0x16
_REG_MFGID = const(0xFE) # 0xFF16
_REG_CONFIG = const(0x03)
_I2C_ADDR = const(0x4C)
_TEMP_LSB = 0.125
_FAN_RPM_DIVISOR = const(5400000)
_REG_FAN_CONFIG=const(0x4A)
_FAN_CONFIG = const(0x4A)
_TEMP_FORCE = const(0x0C)
_LUT_HYSTERESIS = const(0x4F)

FAN_MAX_SPEED = 0x3F # 6-bit value


def _h(val):
return "0x{:02X}".format(val)


def _b(val):
return "{:#010b}".format(val)


# class FanSpeedLUT:
# def __init__(self, emc_fan):
# self.emc_fan = emc_fan

# def __get__(self, obj, objtype=None):
# if not isinstance(obj, int):
# raise IndexError
# def __len__(self):
# return len(self.lut_values)
# def __set__(self, obj, value):
# if not isinstance(obj, int):
# raise IndexError
class EMC2101: # pylint: disable=too-many-instance-attributes
"""Driver for the EMC2101 Fan Controller.
:param ~busio.I2C i2c_bus: The I2C bus the EMC is connected to.
Expand All @@ -150,56 +173,49 @@ class EMC2101: # pylint: disable=too-many-instance-attributes
_int_temp = ROUnaryStruct(_INTERNAL_TEMP, "<b")
_ext_temp_msb = ROUnaryStruct(_INTERNAL_TEMP, "<b")
_ext_temp_lsb = ROUnaryStruct(_INTERNAL_TEMP, "<b")
#_tach_read = ROUnaryStruct(_TACH_LSB, "<H")
# _tach_read = ROUnaryStruct(_TACH_LSB, "<H")
_tach_read_lsb = ROUnaryStruct(_TACH_LSB, "<B")
_tach_read_msb = ROUnaryStruct(_TACH_MSB, "<B")
_tach_mode_enable = RWBit(_REG_CONFIG, 2)

# temp used to override current external temp measurement
_ext_tmp_force = UnaryStruct(_TEMP_FORCE, "<b")
_fan_ext_force_lut_en = RWBit(_REG_FAN_CONFIG, 6)
_fan_ext_force_lut_en = RWBit(_FAN_CONFIG, 6)

# speed to use when LUT is disabled in programming mode, default speed
# uses 6 lsbits
_fan_setting = UnaryStruct(_REG_FAN_SETTING, "<B")
_fan_lut_prog = RWBit(_REG_FAN_CONFIG, 5)
_fan_polarity = RWBit(_REG_FAN_CONFIG, 4)
_fan_pwm_clock_slow = RWBit(_REG_FAN_CONFIG, 3)
_fan_pwm_clock_override = RWBit(_REG_FAN_CONFIG, 2)
_fan_tach_mode = RWBits(2, _REG_FAN_CONFIG, 0)
_fan_lut_prog = RWBit(_FAN_CONFIG, 5)
_fan_polarity = RWBit(_FAN_CONFIG, 4)
_fan_pwm_clock_slow = RWBit(_FAN_CONFIG, 3)
_fan_pwm_clock_override = RWBit(_FAN_CONFIG, 2)
_fan_tach_mode = RWBits(2, _FAN_CONFIG, 0)

_fan_lut_t1 = UnaryStruct(0x50, "<B")
_fan_lut_s1 = UnaryStruct(0x51, "<B")

_fan_lut_t2 = UnaryStruct(0x52, "<B")
_fan_lut_s2 = UnaryStruct(0x53, "<B")

_lut_temp_hyst = UnaryStruct(0x4F, "<B")

_lut_temp_hyst = UnaryStruct(_LUT_HYSTERESIS, "<B")

def __init__(self, i2c_bus):
self.i2c_device = i2cdevice.I2CDevice(i2c_bus, _I2C_ADDR)

if not self._part_id in [0x16, 0x28] or self._mfg_id is not 0x5D:
raise AttributeError("Cannot find a EMC2101")
self._lut = {}
self.initialize()

def initialize(self):
"""Reset the controller to an initial default configuration"""
print("initializing!")
self._lut_temp_hyst = 0
# self._lut_temp_hyst = 0
self._tach_mode_enable = True
# set lowest temp to temp on boot
self._fan_lut_prog = True
self._fan_lut_t1 = 30
self._fan_lut_s1 = 5

self._fan_lut_t2 = 40
self._fan_lut_s2 = 50
self._fan_lut_prog = False

self.lut_enabled = False

@property
def internal_temperature(self):
"""The temperature as measured by the EMC2101's internal temperature sensor"""
"""The temperature as measured by the EMC2101's internal 8-bit temperature sensor"""
return self._int_temp # !!! it's RAAAAAAAAARW)

@property
Expand All @@ -212,46 +228,97 @@ def external_temperature(self):
full_tmp *= 0.125

return full_tmp # !!! it's RAAAAAAAAARW

@property
def fan_speed(self):
"""The current speed in Revolutions per Minute (RPM)"""
"""The current speed in Revolutions per Minute (RPM)"""

val = self._tach_read_lsb
val |= self._tach_read_msb << 8
return _FAN_RPM_DIVISOR / val

val = self._tach_read_lsb
val |= (self._tach_read_msb<<8)
return _FAN_RPM_DIVISOR / val
@property
def manual_fan_speed(self):
"""The fan speed used while the LUT is being updated and is unavailable. Value is a
percentage of the fan's maximum speed"""
raw_setting = self._fan_setting & FAN_MAX_SPEED
return (raw_setting / FAN_MAX_SPEED) * 100

@manual_fan_speed.setter
def manual_fan_speed(self, fan_speed):
if fan_speed not in range(0, 101):
raise AttributeError("manual_fan_speed must be from 0-100 ")

# convert from a percentage to an lsb value
percentage = fan_speed / 100.0
fan_speed_lsb = round(percentage * FAN_MAX_SPEED)
lut_disabled = self._fan_lut_prog
self._fan_lut_prog = True
self._fan_setting = fan_speed_lsb
self._fan_lut_prog = lut_disabled

@property
def fan_fallback_speed(self):
"""The fan speed used while the LUT is being updated and is unavailable"""
return (self._fan_setting & 0b111111)
def lut_enabled(self):
"""Enable or disable the internal look up table used to map a given temperature
to a fan speed. When the LUT is disabled, fan speed can be changed with `manual_fan_speed`"""
return self._fan_lut_prog == False

@fan_fallback_speed.setter
def fan_fallback_speed(self, fan_speed):
self._fan_lut_prog = True
self._fan_setting = (fan_speed & 0b111111)
self._fan_lut_prog = False
@lut_enabled.setter
def lut_enabled(self, enable_lut):
self._fan_lut_prog = not enable_lut


if __name__ == "__main__":
# TODO:
# lut setter
# lut force
# lut hysteresis
# data rate
# _CONV_RATE = const(0x04)
# _CONV_RATE = const(0x0A)
# DAC output
# pwm polarity
# temp filter
# high low alerts
# min fan speed setter (max TACH counts)
# _TACH_LIMIT_LSB = const(0x48)
# _TACH_LIMIT_MSB = const(0x49)
# spinup config
# diode tuning
#
import board
import time
from adafruit_debug_i2c import DebugI2C

i2c = board.I2C()
i2c = DebugI2C(i2c)
#i2c = DebugI2C(i2c)
emc = EMC2101(i2c)
print("Early fallback speed:")
print(emc.fan_fallback_speed)
emc.fan_fallback_speed = 10
print("Early fallback speed after WRITE")
print(emc.fan_fallback_speed)
time.sleep(1)
emc.lut_enabled = False
while True:
print("Internal temp:", emc.internal_temperature)
print("External temp", emc.external_temperature)
print("Setting fan speed to 25%")
emc.manual_fan_speed = 25
time.sleep(2)
print("Fan speed", emc.fan_speed)
time.sleep(1)

print("Setting fan speed to 50%")
emc.manual_fan_speed = 50
time.sleep(1.5)
print("Fan speed", emc.fan_speed)
time.sleep(1)

print("Setting fan speed to 75%")
emc.manual_fan_speed = 75
time.sleep(1.5)
print("Fan speed", emc.fan_speed)
time.sleep(1)


print("Setting fan speed to 100%")
emc.manual_fan_speed = 100
time.sleep(1.5)
print("Fan speed", emc.fan_speed)
print("Fan fallback speed:", emc.fan_fallback_speed)
time.sleep(1)

print("")
time.sleep(0.5)
Loading

0 comments on commit 6c1ff14

Please sign in to comment.