From 4fecb00cbbe1d59599c4889090a678cd96ce36d2 Mon Sep 17 00:00:00 2001 From: Eric Wertz Date: Fri, 20 Jan 2023 11:38:36 -0500 Subject: [PATCH 1/1] first commit --- Makefile | 18 ++++ fancom.sh | 53 ++++++++++++ fanduino.ino | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 Makefile create mode 100755 fancom.sh create mode 100644 fanduino.ino diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9c9e43e --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +ALTERNATE_CORE_PATH = /usr/share/arduino/hardware/archlinux-arduino/avr +USER_LIB_PATH = /home/eric/fanduino +ARDUINO_DIR = /usr/share/arduino/hardware/archlinux-arduino/avr +ARDMK_DIR = /usr/share/arduino +AVR_TOOLS_DIR = /usr + +ARDUINO_LIBS = Wire +#BOARD_TAG = nano +BOARD_SUB = 16MHzatmega328 +MONITOR_PORT = /dev/ttyUSB0 +#CFLAGS_STD = -std=gnu11 -flto -fno-fat-lto-objects +#CXXFLAGS_STD = -std=gnu++11 -fno-threadsafe-statics -flto +CXXFLAGS += -fno-devirtualize + +AVRDUDE = /usr/bin/avrdude +AVRDUDE_CONF = /etc/avrdude.conf + +include /usr/share/arduino/Arduino.mk diff --git a/fancom.sh b/fancom.sh new file mode 100755 index 0000000..c83ed90 --- /dev/null +++ b/fancom.sh @@ -0,0 +1,53 @@ +#! /bin/bash + +hdparm -B 100 /dev/sda +hdparm -B 100 /dev/sdb + +hddtemp -d /dev/sda /dev/sdb + +#stty -F /dev/ttyUSB0 115200 cs8 cread clocal +killall tail +avrdude -q -V -p atmega328p -C /etc/avrdude.conf -D -c arduino -b 115200 -P /dev/ttyUSB0 -U flash:r:/tmp/fancom_firmware.hex:i +#avrdude -q -V -p atmega328p -C /etc/avrdude.conf -D -c arduino -b 115200 -P /dev/ttyUSB0 -U flash:w:/tmp/fancom_firmware.hex:i +ard-reset-arduino /dev/ttyUSB0 +sleep 3 +tail -f /dev/ttyUSB0 >> /var/log/fancom.log & + +purgecount=0 +hddupdate=0 +cputemp=0 +hddtemp=0 +outtemp=0 +while true +do + cputemp=`cat /sys/class/thermal/thermal_zone0/temp | awk '{print $1/1000}' RS="\n"` + #sensors -u | sed -rn 's/.*temp1_input: ([0-9.]+)/\1/p' | awk '{s+=$1}END{print "$",s/NR}' RS="\n" > /dev/ttyUSB0 + + if [ $hddtemp != 0 ]; then + if [ $hddtemp > $cputemp ]; then + outtemp=`echo $cputemp` + else + outtemp=`echo $hddtemp` + fi + #outtemp=`echo $hddtemp $cputemp | awk '{print ($1+$2)/2}'` + else + outtemp=`echo $cputemp` + fi + + echo $ $outtemp >> /dev/ttyUSB0 + + ((purgecount++)) + ((hddupdate++)) + if [ $purgecount == 3600 ]; then + purgecount=0 + kill $! + tail -n 3600 /var/log/fancom.log > /var/log/fancom.log.new + cat /var/log/fancom.log.new > /var/log/fancom.log + rm /var/log/fancom.log.new + tail -f /dev/ttyUSB0 >> /var/log/fancom.log & + fi + if [ $hddupdate == 30 ]; then + hddtemp=`nc localhost 7634 | awk -F '|' '{print (($4=="SLP"?0:$4)+($9=="SLP"?0:$9))/2*1.28}'` + fi + sleep 1 +done diff --git a/fanduino.ino b/fanduino.ino new file mode 100644 index 0000000..db014c5 --- /dev/null +++ b/fanduino.ino @@ -0,0 +1,240 @@ +#include + +#define MATH_E 2.718281f + +#define TARGET_TEMP_CPU 60.0f +#define TARGET_TEMP_HEATSINK 42.0f +#define TARGET_TEMP_HEATSINK_MAX 42.0f +#define TEMP_PERIOD 3 + +#define TEMP_R1 10000 +#define TEMP_SENSOR 10000 +#define TEMP_SENSOR_NOMINAL 25 +#define TEMP_SENSOR_BCOEFFICIENT 3435 +#define TEMP_PIN A7 + +#define FALLBACK_TIMEOUT 10 + +#define FAN_SPINDOWN_MAX 5.0f/320.0f + +float fanSpeed; +float fanInterval; +float deltaTSerial; +float deltaTSensor; +float targetDeltaT; +float serialTemp; +float sensorTemp; +float previousTempSerial; +float previousTempSensor; +float tAdjust; +float currentTemp; +float targetTemp; + +unsigned int lastSerialRead; + +unsigned long currentTick; +unsigned long previousTick; + +//configure Timer 1 (pins 9,10) to output 25kHz PWM +void setupTimer1(){ + //Set PWM frequency to about 25khz on pins 9,10 (timer 1 mode 10, no prescale, count to 320) + TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); + TCCR1B = (1 << CS10) | (1 << WGM13); + ICR1 = 320; + OCR1A = 0; + OCR1B = 0; +} +//equivalent of analogWrite on pin 9 +void setFanSpeed() +{ + fanSpeed=fanSpeed<0?0:fanSpeed>1?1:fanSpeed; + OCR1A = (uint16_t)(320*fanSpeed); +} + +void writeCSVLine( float* values, int count ) +{ + char buffer[10]; + for( int i = 0; i < count; i++ ) + { + dtostrf( values[i], 4, 4, buffer ); + Serial.write( buffer, strlen(buffer) ); + if( i != count - 1 ) + Serial.write( ", ", 1 ); + } + Serial.write( "\r\n", 2 ); +} + +float movingAverage( float avg, float val, float period ) +{ + float w = 1.0f/period; + return (avg*(1.0f-w))+(val*w); +} + +#define BUF_MAX 16 +void readSerialTemp() +{ + char buffer[BUF_MAX]; + float val = 0; + int i; + char r; + + i = 0; + r = Serial.read(); + while( r != -1 && i < BUF_MAX - 1 ) + { + buffer[i] = r; + i++; + r = Serial.read(); + } + if( buffer[0] == '$' && buffer[i-1] == '\n' ) + { + buffer[i-1] = '\0'; + val = atof( buffer + 1 ); + } + + if( val != 0 ) + { + lastSerialRead = 0; + + if( serialTemp == 0.0f ) + serialTemp = val; + else + serialTemp = movingAverage( serialTemp, val, TEMP_PERIOD ); + + if( tAdjust == 0.0f ) + tAdjust = serialTemp / sensorTemp; + } + else + lastSerialRead++; +} + +void readSensorTemp() +{ + float reads = 0; + float reading; + + for( int i=0; i<10; i++ ) + { + reads += analogRead( TEMP_PIN ); + delay( 10 ); + } + + reading = reads / 10; + reading = ( 1023 / reading ) - 1; + reading = TEMP_R1 / reading; + + float steinhart; + steinhart = reading / TEMP_SENSOR; // (R/Ro) + steinhart = log(steinhart); // ln(R/Ro) + steinhart /= TEMP_SENSOR_BCOEFFICIENT; // 1/B * ln(R/Ro) + steinhart += 1.0 / (TEMP_SENSOR_NOMINAL + 273.15); // + (1/To) + steinhart = 1.0 / steinhart; // Invert + steinhart -= 273.15; // convert to C + + if( sensorTemp == 0.0f ) + sensorTemp = steinhart; + else + sensorTemp = movingAverage( sensorTemp, steinhart, TEMP_PERIOD ); +} + +void calculateAdjustment() +{ + float adjust; + + adjust = powf( MATH_E, ( serialTemp / sensorTemp ) ) - sensorTemp; + tAdjust = movingAverage( tAdjust, adjust, 60 ); +} + +void setup() +{ + Serial.begin( 115200 ); + //enable outputs for Timer 1 + pinMode(9,OUTPUT); //1A + pinMode(10,OUTPUT); //1B + + setupTimer1(); + //example... + setFanSpeed(); //set duty to 50% on pin 9 + fanSpeed = 0; + fanInterval = 1.0f / 320.0f; + serialTemp = 0; + sensorTemp = 0; + previousTempSerial = 0; + previousTempSensor = 0; + deltaTSerial = 0; + deltaTSensor = 0; + tAdjust = 0; + lastSerialRead = 0; + targetTemp = TARGET_TEMP_HEATSINK; +} + +void loop() +{ + float outVals[10]; + float deltaT; + + float sensorDiff, serialDiff; + + currentTick = millis()/1000; + if( currentTick != previousTick ) + { + readSensorTemp(); + readSerialTemp(); + + if( serialTemp != 0.0f ) + calculateAdjustment(); + + deltaTSensor = movingAverage( deltaTSensor, sensorTemp - previousTempSensor, 3 ); + deltaTSerial = movingAverage( deltaTSerial, serialTemp - previousTempSerial, 3 ); + + if( lastSerialRead < FALLBACK_TIMEOUT ) + { + sensorDiff = TARGET_TEMP_HEATSINK_MAX - sensorTemp; + serialDiff = TARGET_TEMP_CPU - serialTemp; + if( serialDiff < sensorDiff ) + { + currentTemp = serialTemp; + targetTemp = TARGET_TEMP_CPU; + deltaT = deltaTSerial; + } + else + { + currentTemp = sensorTemp; + targetTemp = TARGET_TEMP_HEATSINK_MAX; + deltaT = deltaTSensor; + } + } + else + { + currentTemp = sensorTemp; + targetTemp = TARGET_TEMP_HEATSINK; + deltaT = deltaTSensor; + } + + + targetDeltaT = (targetTemp - currentTemp) / 60.0f; + fanInterval = max( 1.0f / 320.0f, abs( deltaT - targetDeltaT ) * 0.25f ); + + if( targetDeltaT < deltaT ) + fanSpeed += fanInterval; + else if( targetDeltaT > deltaT ) + fanSpeed -= fanInterval > FAN_SPINDOWN_MAX ? FAN_SPINDOWN_MAX : fanInterval; + + setFanSpeed(); + + outVals[0] = serialTemp; + outVals[1] = sensorTemp; + outVals[2] = currentTemp; + outVals[3] = targetTemp; + outVals[4] = deltaT; + outVals[5] = targetDeltaT; + outVals[6] = fanInterval; + outVals[7] = fanSpeed; + writeCSVLine( outVals, 8 ); + + previousTick = currentTick; + previousTempSerial = serialTemp; + previousTempSensor = sensorTemp; + } + +} -- 2.47.0