1 Star 0 Fork 1

hokhyk / cgminer

forked from actionchen / cgminer 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
dm_fan_ctrl.c 7.56 KB
一键复制 编辑 原始数据 按行查看 历史
/*
* Copyright 2018 Duan Hao
* Copyright 2018 Con Kolivas <kernel@kolivas.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version. See COPYING for more details.
*/
/******************************************************************************
* Description: fan control using simple PID
******************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "dragonmint_t1.h"
#include "dm_temp_ctrl.h"
#include "dm_fan_ctrl.h"
/******************************************************************************
* Macros & Constants
******************************************************************************/
#define FAN_MODE_DEF FAN_MODE_AUTO // default fan control mode
#define WORK_CYCLE_DEF (2) // default time interval between temperature checks
#define DEV_TMP_CHK_CNT (3)
#define DEV_TMP_CHK_SPAN (6)
#define TIMEOUT_GET_TMP (3)
/******************************************************************************
* Global variables
******************************************************************************/
volatile c_fan_cfg g_fan_cfg; // fan config
volatile int g_fan_profile; // fan profile: normal / overheat / preheat
static c_temp g_dev_tmp; // device temperature sequence
static c_temp g_dev_last_tmp; // device temperature sequence
extern int chain_flag[MAX_CHAIN_NUM];
/******************************************************************************
* Prototypes
******************************************************************************/
static bool dm_fanctrl_get_tmp(void);
static void dm_fanctrl_update_fan_speed(void);
static bool dm_fanctrl_check_overheat(void);
static bool dm_fanctrl_check_preheat(void);
/******************************************************************************
* Implementations
******************************************************************************/
void dm_fanctrl_get_defcfg(c_fan_cfg *p_cfg)
{
p_cfg->fan_mode = FAN_MODE_DEF;
p_cfg->fan_speed = FAN_SPEED_DEF;
p_cfg->fan_speed_preheat = FAN_SPEED_PREHEAT;
p_cfg->fan_ctrl_cycle = WORK_CYCLE_DEF;
p_cfg->preheat = true;
}
void dm_fanctrl_init(c_fan_cfg *p_cfg)
{
if (NULL == p_cfg) {
c_fan_cfg cfg;
dm_fanctrl_get_defcfg(&cfg); // avoid to pass volatile pointer directly
g_fan_cfg = cfg;
} else
g_fan_cfg = *p_cfg;
g_fan_profile = FAN_PF_NORMAL;
g_dev_tmp.tmp_avg = g_dev_last_tmp.tmp_avg = g_tmp_cfg.tmp_target;
}
void *dm_fanctrl_thread(void __maybe_unused *argv)
{
int timeout_get_tmp = 0;
// set default fan speed
// dm_fanctrl_set_fan_speed(g_fan_cfg.fan_speed);
while(true) {
if (dm_fanctrl_get_tmp()) {
dm_fanctrl_update_fan_speed();
timeout_get_tmp = 0;
} else
timeout_get_tmp++;
// force fan speed to 100% when failed to get temperature
if (timeout_get_tmp >= TIMEOUT_GET_TMP && g_fan_cfg.fan_speed < FAN_SPEED_MAX) {
applog(LOG_WARNING,
"WARNING: unable to read temperature, force fan speed to %d", FAN_SPEED_MAX);
dm_fanctrl_set_fan_speed(FAN_SPEED_MAX);
timeout_get_tmp = 0;
}
sleep(g_fan_cfg.fan_ctrl_cycle);
}
return NULL;
}
void dm_fanctrl_set_fan_speed(char speed)
{
if (speed > FAN_SPEED_MAX)
speed = FAN_SPEED_MAX;
else if (speed < g_fan_cfg.fan_speed_preheat)
speed = g_fan_cfg.fan_speed_preheat;
if (speed != g_fan_cfg.fan_speed) {
g_fan_cfg.fan_speed = speed;
mcompat_fan_speed_set(0, g_fan_cfg.fan_speed); // fan id is ignored
applog(LOG_ERR, "fan speed set to %d", g_fan_cfg.fan_speed);
}
}
static bool dm_fanctrl_get_tmp(void)
{
bool retval = false;
int i, chain_num = 0;
c_temp dev_temp;
// init
chain_num = 0;
dev_temp.tmp_hi = g_tmp_cfg.tmp_min;
dev_temp.tmp_lo = g_tmp_cfg.tmp_max;
dev_temp.tmp_avg = 0;
for(i = 0; i < MAX_CHAIN_NUM; ++i) {
if (chain_flag[i]
&& g_chain_tmp[i].tmp_avg > g_tmp_cfg.tmp_min
&& g_chain_tmp[i].tmp_avg < g_tmp_cfg.tmp_max) {
// temperature stat.
dev_temp.tmp_lo = MIN(dev_temp.tmp_lo, g_chain_tmp[i].tmp_lo);
dev_temp.tmp_hi = MAX(dev_temp.tmp_hi, g_chain_tmp[i].tmp_hi);
dev_temp.tmp_avg = MAX(dev_temp.tmp_avg, g_chain_tmp[i].tmp_avg);
chain_num++;
}
}
if (chain_num > 0) {
g_dev_tmp = dev_temp;
retval = true;
}
return retval;
}
static bool dm_fanctrl_check_overheat(void)
{
int tmp_tolerance = 0;
// if already in overheat mode, apply a small tolerance
if (FAN_PF_OVERHEAT == g_fan_profile)
tmp_tolerance = TEMP_TOLERANCE;
// overheat mode: force to max fan speed while tmp_hi >= tmp_thr_hi
if (g_dev_tmp.tmp_hi >= g_tmp_cfg.tmp_thr_hi - tmp_tolerance) {
dm_fanctrl_set_fan_speed(FAN_SPEED_MAX);
if (FAN_PF_OVERHEAT != g_fan_profile) {
g_fan_profile = FAN_PF_OVERHEAT;
applog(LOG_ERR, "OVERHEAT: temp_hi over %d, force fan speed to %d",
g_tmp_cfg.tmp_thr_hi, FAN_SPEED_MAX);
}
return true;
}
g_fan_profile = FAN_PF_NORMAL;
return false;
}
static bool dm_fanctrl_check_preheat(void)
{
int tmp_tolerance = 0;
// preheat mode: do preheating when tmp_avg < tmp_thr_lo
if (FAN_PF_PREHEAT != g_fan_profile)
tmp_tolerance = TEMP_TOLERANCE;
if (g_dev_tmp.tmp_avg < g_tmp_cfg.tmp_thr_lo - tmp_tolerance) {
dm_fanctrl_set_fan_speed(FAN_SPEED_PREHEAT);
g_fan_profile = FAN_PF_PREHEAT;
applog(LOG_ERR, "PREHEAT: tmp_avg under %d, force fan speed to %d",
g_tmp_cfg.tmp_thr_lo, FAN_SPEED_PREHEAT);
return true;
}
g_fan_profile = FAN_PF_NORMAL;
return false;
}
static int8_t last_tmp_rise[8];
static int64_t *last_tmp_int = (int64_t *)last_tmp_rise;
static int tmp_rise_cnt;
static void dm_fanctrl_update_fan_speed(void)
{
int fan_speed;
int delta_tmp_avg, delta_tmp_hi;
int tmp_rise, hi_raise;
// detect overheat first
if (dm_fanctrl_check_overheat())
return;
// preheat
if (g_fan_cfg.preheat && dm_fanctrl_check_preheat())
return;
// check average temperature rising to determining fan speed target
tmp_rise = g_dev_tmp.tmp_avg - g_dev_last_tmp.tmp_avg;
delta_tmp_avg = g_dev_tmp.tmp_avg - g_tmp_cfg.tmp_target;
hi_raise = g_dev_tmp.tmp_hi - g_dev_last_tmp.tmp_hi;
delta_tmp_hi = g_dev_tmp.tmp_hi - g_tmp_cfg.tmp_thr_hi;
/* If we have a hot spot, use that for fan speed control
* instead of the average temperature */
if (hi_raise > tmp_rise || delta_tmp_hi > delta_tmp_avg) {
tmp_rise = hi_raise;
delta_tmp_avg = delta_tmp_hi;
}
g_dev_last_tmp.tmp_avg = g_dev_tmp.tmp_avg;
g_dev_last_tmp.tmp_hi = g_dev_tmp.tmp_hi;
g_dev_last_tmp.tmp_lo = g_dev_tmp.tmp_lo;
if (delta_tmp_avg > 0) {
/* Over target temperature */
/* Is the temp already coming down */
if (tmp_rise < 0)
goto out;
/* Adjust fanspeed by temperature over and any further rise */
fan_speed = g_fan_cfg.fan_speed + delta_tmp_avg + tmp_rise;
} else {
/* Below target temperature */
int diff = tmp_rise;
if (tmp_rise > 0) {
int divisor = -delta_tmp_avg / TEMP_TOLERANCE + 1;
/* Adjust fanspeed by temperature change proportional to
* diff from optimal. */
diff /= divisor;
} else if (!tmp_rise) {
/* Is the temp below optimal and unchanging, gently
* lower speed. Allow tighter temperature tolerance if
* temperature is unchanged for longer. */
if ((g_dev_tmp.tmp_avg < g_tmp_cfg.tmp_target - TEMP_TOLERANCE) ||
(!(*last_tmp_int) && (g_dev_tmp.tmp_avg < g_tmp_cfg.tmp_target))) {
*last_tmp_int = 0xFFFFFFFFFFFFFFFF;
diff -= 1;
}
}
fan_speed = g_fan_cfg.fan_speed + diff;
}
// set fan speed
dm_fanctrl_set_fan_speed(fan_speed);
out:
last_tmp_rise[(tmp_rise_cnt++) % 8] = tmp_rise;
}
1
https://gitee.com/hokhyk/cgminer.git
git@gitee.com:hokhyk/cgminer.git
hokhyk
cgminer
cgminer
master

搜索帮助