Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fan fixes #266

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions hardware/firmware/box_rp2040/flash.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

set -euo pipefail

cdir="$(dirname "$(readlink -f "${0}")")"

echo "Building firmware..."
"${cdir}"/build.sh

echo "Flashing firmware..."
"$cdir"/../tools/flash_rp2040_firmware.sh "$cdir"/build/src/box_rp2040.elf
145 changes: 99 additions & 46 deletions hardware/firmware/box_rp2040/src/pwr_brd_ctl/fan_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@
#include "fan_ctl_regs.h"
#include "pwr_brd_ctl.h"

uint64_t time_next_cmd[NUMFAN];
uint16_t desired_fan_speed[NUMFAN];
uint16_t fan_calibrated[NUMFAN][FAN_MAX_PWM+1];
unsigned int fan_state = 0;
bool fan_error[NUMFAN];

void fan_ctl_init() {
uint64_t now = time_us_64();

for (int i = 0; i < NUMFAN; i++) {
time_next_cmd[i] = now;
desired_fan_speed[i] = DESIRED_RPM;
fan_error[i] = false;

for (int j = 0; j < FAN_MAX_PWM; j++) {
fan_calibrated[i][j] = 0;
}
}

// Turn off the second fan by default, having both fans on makes it very noisy
desired_fan_speed[1] = 0;
}

bool fan_ctl_i2c_read(uint8_t reg_id, uint8_t* dest) {
Expand All @@ -43,7 +52,6 @@ void pwr_brd_fan_init() {

fan_ctl_set_pwm_frequency(0, 0, 0, 0, 0);
for (int i = 0; i < NUMFAN; i++) {
time_next_cmd[i] = now;
desired_fan_speed[i] = DESIRED_RPM;
}
}
Expand Down Expand Up @@ -156,59 +164,104 @@ Standard fan control:

*/

void fan_ctl_task() {
uint64_t now = time_us_64();

for (int i = 0; i < NUMFAN; i++) {
if (now < time_next_cmd[i]) {
continue;
}
uint8_t fan_get_stall_speed(uint8_t fan_id) {
for (int i = FAN_MAX_PWM; i > 0; i-- ) {
if (fan_calibrated[fan_id][i] == 0) {
return i;
}
}
}

time_next_cmd[i] = now + CMD_WAIT_TIME_US;
void fan_ctl_task_calibrate() {
static uint64_t fancal_last = 0;
static uint8_t fancal_step = FAN_MAX_PWM;
uint64_t now = time_us_64();
if (now < (fancal_last + 2000000)) {
return;
}

io_say_f("Calibration step %d\r\n", fancal_step);
// First iteration doesn't store the values since the fans still
// have to spin up
if (fancal_last > 0) {
uint16_t fanspeed;
fan_ctl_get_fan_speed(i, &fanspeed);
for(int i = 0; i < NUMFAN; i++) {
fan_ctl_get_fan_speed(i, &fanspeed);
fan_calibrated[i][fancal_step] = fanspeed;

if (desired_fan_speed[i] == 0) {
// fan should be off

if (fanspeed > 0) {
// turn off fan
fan_ctl_set_pwm(i, 0);
}
// otherwise, fan is off, as requested

continue;
}

int difference = desired_fan_speed[i] - fanspeed;
uint8_t pwm;
fan_ctl_get_pwm(i, &pwm);
float smooth = 0.0005f;
pwm += ((difference>>2) * (1.0f - exp(-smooth)));
fan_ctl_set_pwm(i, pwm);

if (pwm > FAN_MAX_PWM) {
// PWM was set by the fan controller's default power on value
// bring it back down to the max value
fan_ctl_set_pwm(i, FAN_MAX_PWM);
continue;
if (fancal_step == FAN_MAX_PWM && fanspeed == 0) {
fan_error[i] = true;
}
}
fancal_step--;
if (fancal_step == 0) {
// End calibration and move to the next state
fan_state = FAN_STATE_RUN;
/*
io_say_f("Calibration finished\r\n");
for (int fan =0; fan <NUMFAN;fan++){
io_say_f("FAN %d: ", fan);
if (fan_error[fan]) {
io_say_f("disconnected");
} else {
for(int step=0;step<FAN_MAX_PWM;step++){
io_say_f("%d, ", fan_calibrated[fan][step]);
}
}
io_say_f("\r\n");
}
*/
return;
}
}

if (fanspeed == 0) {
// initial spin-up
// set to full speed
for (int i = 0; i < NUMFAN; i++) {
if(!fan_ctl_set_pwm(i, fancal_step)) {
// io_say_f("Failed to set PWM on fan %d\r\n", i);
}
}
fancal_last = time_us_64();
}

if (pwm >= FAN_MAX_PWM) {
// fan is already at full speed
// it could be defective or disconnected
// nothing to do
continue;
}
void fan_ctl_task_run() {
uint64_t now = time_us_64();
static uint64_t time_last = 0;
if (now < (time_last + CMD_WAIT_TIME_US)) {
return;
}

fan_ctl_set_pwm(i, FAN_MAX_PWM);
for (int i = 0; i < NUMFAN; i++ ) {
if (fan_error[i]) {
continue;
}
uint16_t fanspeed;
fan_ctl_get_fan_speed(i, &fanspeed);

// Anti-stall
if (desired_fan_speed[i] > 0 && fanspeed == 0) {
// io_say_f("Stall on fan %d\r\n", i);
fan_ctl_set_pwm(i, fan_get_stall_speed(i) + 2);
continue;
}

// Apply requested fan speed relative to stall speed
uint8_t new_rpm = 0;
if (desired_fan_speed[i] > 0) {
new_rpm = fan_get_stall_speed(i) + desired_fan_speed[i];
}
fan_ctl_set_pwm(i, new_rpm);
}
time_last = time_us_64();
}

void fan_ctl_task() {
switch (fan_state) {
case FAN_STATE_CALIBRATE:
return fan_ctl_task_calibrate();
case FAN_STATE_RUN:
return fan_ctl_task_run();
default:
fan_state = FAN_STATE_CALIBRATE;
break;
}
}
7 changes: 5 additions & 2 deletions hardware/firmware/box_rp2040/src/pwr_brd_ctl/fan_ctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@

#define FAN_TACH_CONSTANT (7864320)
#define CMD_WAIT_TIME_US (3000 * 1000)
#define DESIRED_RPM (5000)
#define DESIRED_RPM (1)
#define DESIRED_RPM_THRESH_UPPER (1000)
#define DESIRED_RPM_THRESH_LOWER (2000)
#define FAN_MIN_HEALTHY_RPM (3000)
#define FAN_MAX_HEALTHY_RPM (10000)
#define NUMFAN (5)
#define FAN_MAX_PWM (10)
#define FAN_MAX_PWM (6)

#define FAN_STATE_CALIBRATE (0)
#define FAN_STATE_RUN (1)

bool fan_ctl_get_fan_speed(uint8_t fan_id, uint16_t* dest);
bool fan_ctl_get_fan_status(uint8_t* dest);
Expand Down