Skip to content

Commit 694c542

Browse files
committed
init thermal-control
1 parent 6d77046 commit 694c542

File tree

8 files changed

+152
-16
lines changed

8 files changed

+152
-16
lines changed

main/NvsManager/inc/nvs_config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#define NVS_CONFIG_PRODUCTION_TEST "productiontest"
2828
#define NVS_CONFIG_OVERHEAT_MODE "overheat_mode"
2929
#define NVS_CONFIG_OVERCLOCK_ENABLED "oc_enabled"
30+
#define NVS_CONFIG_THERMAL_CTRL "thermalctrl"
31+
#define NVS_CONFIG_THERMAL_TARGET "thermaltarget"
3032
#define NVS_CONFIG_SWARM "swarmconfig"
3133

3234
// Theme configuration

main/http_server/axe-os/src/app/components/edit/edit.component.html

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,27 @@ <h1 class="text-2xl font-bold mb-3">Performance Mode</h1>
8484
</div>
8585
</div>
8686

87+
<!-- Thermal Control Section (manual fan mode only) -->
88+
<div class="col-12" *ngIf="form.controls['autofanspeed'].value != true">
89+
<div class="field-checkbox">
90+
<p-checkbox name="thermalControl" formControlName="thermalControl" inputId="thermalControl"
91+
[binary]="true"></p-checkbox>
92+
<label for="thermalControl">Thermal Control (Auto-Frequency)</label>
93+
</div>
94+
</div>
95+
96+
<div *ngIf="form.controls['thermalControl'].value == true">
97+
<div class="col-12">
98+
<label>Target Temperature: {{form.controls['thermalTarget'].value}}°C</label>
99+
<p-slider formControlName="thermalTarget" [min]="45" [max]="72" [step]="1"></p-slider>
100+
<small class="block mt-1" style="color: #aaa;">
101+
Frequency adjusts automatically (±25 MHz every 2s) to maintain this temperature.
102+
Both ASIC chip temp and VR temperature are monitored.
103+
<span *ngIf="frequencyActual">Current running frequency: {{frequencyActual}} MHz</span>
104+
</small>
105+
</div>
106+
</div>
107+
87108
<div class="mt-2">
88109
<button pButton [disabled]="!form.dirty || form.invalid" (click)="updateSystem()"
89110
class="btn btn-primary mr-2">Save</button>

main/http_server/axe-os/src/app/components/edit/edit.component.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class EditComponent implements OnInit, OnDestroy {
2121
public websiteUpdateProgress: number | null = null;
2222

2323
public savedChanges: boolean = false;
24+
public frequencyActual: number | undefined;
2425
public settingsUnlocked: boolean = false;
2526
public eASICModel = eASICModel;
2627
public ASICModel!: eASICModel;
@@ -103,6 +104,7 @@ export class EditComponent implements OnInit, OnDestroy {
103104
)
104105
.subscribe(info => {
105106
this.ASICModel = info.ASICModel;
107+
this.frequencyActual = info.frequencyActual;
106108

107109
// Check if overclock is enabled in NVS
108110
if (info.overclockEnabled === 1) {
@@ -118,7 +120,9 @@ export class EditComponent implements OnInit, OnDestroy {
118120
frequency: [info.frequency, [Validators.required]],
119121
autofanspeed: [info.autofanspeed == 1, [Validators.required]],
120122
manualFanSpeed: [info.manualFanSpeed, [Validators.required]],
121-
overheat_mode: [info.overheat_mode, [Validators.required]]
123+
overheat_mode: [info.overheat_mode, [Validators.required]],
124+
thermalControl: [info.thermalControl == 1, [Validators.required]],
125+
thermalTarget: [info.thermalTarget ?? 65, [Validators.required, Validators.min(45), Validators.max(72)]],
122126
});
123127

124128
this.form.controls['autofanspeed'].valueChanges.pipe(
@@ -127,8 +131,22 @@ export class EditComponent implements OnInit, OnDestroy {
127131
).subscribe(autofanspeed => {
128132
if (autofanspeed) {
129133
this.form.controls['manualFanSpeed'].disable();
134+
this.form.controls['thermalControl'].setValue(false);
135+
this.form.controls['thermalControl'].disable();
130136
} else {
131137
this.form.controls['manualFanSpeed'].enable();
138+
this.form.controls['thermalControl'].enable();
139+
}
140+
});
141+
142+
this.form.controls['thermalControl'].valueChanges.pipe(
143+
startWith(this.form.controls['thermalControl'].value),
144+
takeUntil(this.destroy$)
145+
).subscribe(enabled => {
146+
if (enabled) {
147+
this.form.controls['thermalTarget'].enable();
148+
} else {
149+
this.form.controls['thermalTarget'].disable();
132150
}
133151
});
134152
});
@@ -147,6 +165,8 @@ export class EditComponent implements OnInit, OnDestroy {
147165
delete form.stratumPassword;
148166
}
149167

168+
form.thermalControl = form.thermalControl ? 1 : 0;
169+
150170
this.systemService.updateSystem(this.uri, form)
151171
.pipe(this.loadingService.lockUIUntilComplete())
152172
.subscribe({

main/http_server/axe-os/src/app/services/system.service.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ export class SystemService {
6868

6969
chiptemp1: 30,
7070
chiptemp2: 40,
71-
overheat_mode: 0
71+
overheat_mode: 0,
72+
thermalControl: 0,
73+
thermalTarget: 65,
74+
frequencyActual: 525,
7275
}
7376
).pipe(delay(1000));
7477
}

main/http_server/axe-os/src/models/ISystemInfo.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,7 @@ export interface ISystemInfo {
5656
overheat_mode: number,
5757
power_fault?: string
5858
overclockEnabled?: number
59+
frequencyActual?: number,
60+
thermalControl?: number,
61+
thermalTarget?: number,
5962
}

main/http_server/http_server.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,15 @@ static esp_err_t PATCH_update_settings(httpd_req_t * req)
591591
if ((item = cJSON_GetObjectItem(root, "overclockEnabled")) != NULL) {
592592
nvs_config_set_u16(NVS_CONFIG_OVERCLOCK_ENABLED, item->valueint);
593593
}
594+
if ((item = cJSON_GetObjectItem(root, "thermalControl")) != NULL) {
595+
nvs_config_set_u16(NVS_CONFIG_THERMAL_CTRL, item->valueint);
596+
}
597+
if ((item = cJSON_GetObjectItem(root, "thermalTarget")) != NULL) {
598+
uint16_t target = (uint16_t)item->valueint;
599+
if (target < 45) target = 45;
600+
if (target > 72) target = 72;
601+
nvs_config_set_u16(NVS_CONFIG_THERMAL_TARGET, target);
602+
}
594603

595604
cJSON_Delete(root);
596605
httpd_resp_send_chunk(req, NULL, 0);
@@ -683,6 +692,9 @@ static esp_err_t GET_system_info(httpd_req_t * req)
683692
cJSON_AddNumberToObject(root, "coreVoltage", nvs_config_get_u16(NVS_CONFIG_ASIC_VOLTAGE, CONFIG_ASIC_VOLTAGE));
684693
cJSON_AddNumberToObject(root, "coreVoltageActual", VCORE_get_voltage_mv(GLOBAL_STATE));
685694
cJSON_AddNumberToObject(root, "frequency", nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY));
695+
cJSON_AddNumberToObject(root, "frequencyActual", GLOBAL_STATE->POWER_MANAGEMENT_MODULE.thermal_freq);
696+
cJSON_AddNumberToObject(root, "thermalControl", nvs_config_get_u16(NVS_CONFIG_THERMAL_CTRL, 0));
697+
cJSON_AddNumberToObject(root, "thermalTarget", nvs_config_get_u16(NVS_CONFIG_THERMAL_TARGET, 65));
686698
cJSON_AddStringToObject(root, "ssid", ssid);
687699
cJSON_AddStringToObject(root, "macAddr", formattedMac);
688700
cJSON_AddStringToObject(root, "hostname", hostname);

main/tasks/power_management_task.c

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
#define TPS546_THROTTLE_TEMP 105.0
2929
#define TPS546_MAX_TEMP 145.0
3030

31+
#define THERMAL_CTRL_STEP_MHZ 25.0f
32+
#define THERMAL_CTRL_MIN_MHZ 400.0f
33+
#define THERMAL_CTRL_MAX_MHZ 650.0f
34+
#define THERMAL_CTRL_HYSTERESIS 3.0f
35+
#define THERMAL_TARGET_DEFAULT 65
36+
3137
static const char * TAG = "power_management";
3238

3339
static bool even = false;
@@ -85,6 +91,55 @@ static double automatic_fan_speed(float chip_temp, float vr_temp, GlobalState *
8591
return result;
8692
}
8793

94+
// Adjust ASIC frequency to maintain target temperature.
95+
// Uses max(chip_temp_max, vr_temp_normalized) as effective temperature.
96+
// VR range 60-85°C is mapped to ASIC 45-75°C scale.
97+
static void thermal_control_adjust_frequency(PowerManagementModule * pm, float nvs_base_freq, GlobalState * GLOBAL_STATE)
98+
{
99+
// Get max ASIC chip temperature
100+
float chip_max = 0.0f;
101+
if (pm->chip_temp[0] > 0.0f && pm->chip_temp[1] > 0.0f) {
102+
chip_max = (pm->chip_temp[0] > pm->chip_temp[1]) ? pm->chip_temp[0] : pm->chip_temp[1];
103+
} else if (pm->chip_temp[0] > 0.0f) {
104+
chip_max = pm->chip_temp[0];
105+
} else if (pm->chip_temp[1] > 0.0f) {
106+
chip_max = pm->chip_temp[1];
107+
} else {
108+
chip_max = 50.0f; // fallback if both sensors zero
109+
}
110+
111+
// Normalize VR temp to ASIC scale: 60-85°C → 45-75°C
112+
float vr_normalized = 45.0f + (pm->vr_temp - 60.0f) * (30.0f / 25.0f);
113+
float effective_temp = (chip_max > vr_normalized) ? chip_max : vr_normalized;
114+
115+
uint16_t target = nvs_config_get_u16(NVS_CONFIG_THERMAL_TARGET, THERMAL_TARGET_DEFAULT);
116+
// Clamp target to valid range
117+
if (target < 45) target = 45;
118+
if (target > 72) target = 72;
119+
120+
float new_freq = pm->thermal_freq;
121+
122+
if (effective_temp > (float)target) {
123+
new_freq -= THERMAL_CTRL_STEP_MHZ;
124+
if (new_freq < THERMAL_CTRL_MIN_MHZ) new_freq = THERMAL_CTRL_MIN_MHZ;
125+
} else if (effective_temp < (float)target - THERMAL_CTRL_HYSTERESIS) {
126+
new_freq += THERMAL_CTRL_STEP_MHZ;
127+
float ceiling = (nvs_base_freq < THERMAL_CTRL_MAX_MHZ) ? nvs_base_freq : THERMAL_CTRL_MAX_MHZ;
128+
if (new_freq > ceiling) new_freq = ceiling;
129+
} else {
130+
return; // within dead band, no change
131+
}
132+
133+
ESP_LOGI(TAG, "ThermalCtrl: eff=%.1f°C target=%u°C freq %.0f->%.0f MHz",
134+
effective_temp, target, pm->thermal_freq, new_freq);
135+
136+
bool success = ASIC_set_frequency(GLOBAL_STATE, new_freq);
137+
if (success) {
138+
pm->thermal_freq = new_freq;
139+
pm->frequency_value = new_freq;
140+
}
141+
}
142+
88143
void POWER_MANAGEMENT_task(void * pvParameters)
89144
{
90145
ESP_LOGI(TAG, "Starting");
@@ -95,13 +150,12 @@ void POWER_MANAGEMENT_task(void * pvParameters)
95150
SystemModule * sys_module = &GLOBAL_STATE->SYSTEM_MODULE;
96151

97152
power_management->frequency_multiplier = 1;
98-
99-
//int last_frequency_increase = 0;
100-
//uint16_t frequency_target = nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY);
153+
power_management->thermal_freq = (float)nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY);
154+
uint16_t last_thermal_ctrl = nvs_config_get_u16(NVS_CONFIG_THERMAL_CTRL, 0);
101155

102156
vTaskDelay(500 / portTICK_PERIOD_MS);
103157
uint16_t last_core_voltage = 0.0;
104-
uint16_t last_asic_frequency = power_management->frequency_value;
158+
uint16_t last_asic_frequency = nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY);
105159

106160
while (1) {
107161
PAC9544_selectChannel(even + 2U);
@@ -189,7 +243,7 @@ void POWER_MANAGEMENT_task(void * pvParameters)
189243
Thermal_setFanSpeedPercent((float) fs / 100.0);
190244
}
191245

192-
// New voltage and frequency adjustment code
246+
// Voltage adjustment
193247
uint16_t core_voltage = nvs_config_get_u16(NVS_CONFIG_ASIC_VOLTAGE, CONFIG_ASIC_VOLTAGE);
194248
uint16_t asic_frequency = nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY);
195249

@@ -199,17 +253,37 @@ void POWER_MANAGEMENT_task(void * pvParameters)
199253
last_core_voltage = core_voltage;
200254
}
201255

202-
if (asic_frequency != last_asic_frequency) {
203-
ESP_LOGI(TAG, "New ASIC frequency requested: %uMHz (current: %uMHz)", asic_frequency, last_asic_frequency);
204-
205-
bool success = ASIC_set_frequency(GLOBAL_STATE, (float)asic_frequency);
206-
207-
if (success) {
208-
power_management->frequency_value = (float)asic_frequency;
256+
// Thermal control / frequency adjustment
257+
uint16_t thermal_ctrl_enabled = nvs_config_get_u16(NVS_CONFIG_THERMAL_CTRL, 0);
258+
259+
if (thermal_ctrl_enabled) {
260+
// Clamp thermal_freq ceiling to current NVS base freq in case user lowered it
261+
if (power_management->thermal_freq > (float)asic_frequency) {
262+
power_management->thermal_freq = (float)asic_frequency;
263+
}
264+
thermal_control_adjust_frequency(power_management, (float)asic_frequency, GLOBAL_STATE);
265+
last_asic_frequency = (uint16_t)power_management->thermal_freq;
266+
} else {
267+
if (last_thermal_ctrl) {
268+
// Thermal control was just disabled — restore NVS base frequency
269+
ESP_LOGI(TAG, "ThermalCtrl disabled, restoring NVS freq %uMHz", asic_frequency);
270+
bool success = ASIC_set_frequency(GLOBAL_STATE, (float)asic_frequency);
271+
if (success) {
272+
power_management->frequency_value = (float)asic_frequency;
273+
power_management->thermal_freq = (float)asic_frequency;
274+
}
275+
last_asic_frequency = asic_frequency;
276+
} else if (asic_frequency != last_asic_frequency) {
277+
ESP_LOGI(TAG, "New ASIC frequency requested: %uMHz (current: %uMHz)", asic_frequency, last_asic_frequency);
278+
bool success = ASIC_set_frequency(GLOBAL_STATE, (float)asic_frequency);
279+
if (success) {
280+
power_management->frequency_value = (float)asic_frequency;
281+
power_management->thermal_freq = (float)asic_frequency;
282+
}
283+
last_asic_frequency = asic_frequency;
209284
}
210-
211-
last_asic_frequency = asic_frequency;
212285
}
286+
last_thermal_ctrl = thermal_ctrl_enabled;
213287

214288
// Check for changing of overheat mode
215289
uint16_t new_overheat_mode = nvs_config_get_u16(NVS_CONFIG_OVERHEAT_MODE, 0);

main/tasks/power_management_task.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ typedef struct
1616
float frequency_value;
1717
float power;
1818
float current;
19+
float thermal_freq; // current thermally-adjusted running frequency (MHz)
1920
} PowerManagementModule;
2021

2122
void POWER_MANAGEMENT_task(void * pvParameters);

0 commit comments

Comments
 (0)