]> Eric's Git Repo - fanduino.git/commitdiff
first commit
authorEric Wertz <ericdwertz@gmail.com>
Fri, 20 Jan 2023 16:38:36 +0000 (11:38 -0500)
committerEric Wertz <ericdwertz@gmail.com>
Fri, 20 Jan 2023 16:38:36 +0000 (11:38 -0500)
Makefile [new file with mode: 0644]
fancom.sh [new file with mode: 0755]
fanduino.ino [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (executable)
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 (file)
index 0000000..db014c5
--- /dev/null
@@ -0,0 +1,240 @@
+#include <math.h>
+
+#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;
+    }
+
+}