Skip to content

Instantly share code, notes, and snippets.

@zouppen
Last active October 31, 2022 13:13
Show Gist options
  • Save zouppen/535d147d73bd4c8561119d03c943ef3a to your computer and use it in GitHub Desktop.
Save zouppen/535d147d73bd4c8561119d03c943ef3a to your computer and use it in GitHub Desktop.
Throttle Raspberry Pi CPU to avoid overheating

Raspberry Pi overheating protection

If your Raspberry Pi is overheating, a common solution is to add a fan. Sometimes it's not feasible and in most cases the computer is runnning smoothly without a fan.

To limit heating, CPU throttling is a solution which keeps your computer not crashing during long compiles or so, but gives out the peak performance for shorter period of times. It depends of your application, if this is good enough solution. For me it is. I like my computer with no moving parts even though it sometimes leads to throttling.

CPU speeds speed_throttle and speed_max are for Raspberry Pi 4 and tuned for my environment. To check available frequencies, see file /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies.

Compiling

gcc -Wall -o throttle throttle.c

License: Public domain

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <unistd.h>
#include <stdbool.h>
long const temp_high_mark = 80000;
long const temp_low_mark = 76000;
char const *const speed_throttle = "700000\n";
char const *const speed_max = "1500000\n";
long measure(FILE *f);
void set_speed(FILE *f, char const *const speed, size_t n);
long measure(FILE *f)
{
static char *line = NULL;
ssize_t n = 0;
// Read a line
n = getline(&line, (size_t *)&n, f);
if (n == -1) return -1;
if (*line == '\0') return -2;
// Rewind the stream and ignore input buffer (kernel gives
// different response every read)
rewind(f);
if (fflush(f) == EOF) {
err(3,"Unable to read temperature (seek)\n");
}
// Convert to number
char *endptr;
long x = strtol(line, &endptr, 10);
if (*endptr != '\n') return -2;
return x;
}
void set_speed(FILE *f, char const *const speed, size_t n)
{
size_t wrote = fwrite(speed, n, 1, f);
if (wrote != 1) {
err(3,"Unable to set speed\n");
}
if (fflush(f) == EOF) {
err(3,"Unable to set speed (seek)\n");
}
}
int main(int argc, char **argv)
{
FILE *temp_f = fopen("/sys/class/thermal/thermal_zone0/temp", "r");
if (temp_f == NULL) {
err(1, "Unable to open temperature file");
}
FILE *speed_f = fopen("/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq", "w");
if (speed_f == NULL) {
err(1, "Unable to open CPU speed file. Are your root?");
}
bool throttling = true;
set_speed(speed_f, speed_throttle, sizeof(speed_throttle));
while (true) {
long temp = measure(temp_f);
if (temp == -1) {
err(1, "Unable to read temperature");
} else if (temp == -2) {
errx(2, "Unable to convert temperature");
}
if (throttling && temp < temp_low_mark) {
throttling = false;
set_speed(speed_f, speed_max, sizeof(speed_max));
printf("Max speed\n");
fflush(stdout);
} else if (!throttling && temp > temp_high_mark) {
throttling = true;
set_speed(speed_f, speed_throttle, sizeof(speed_throttle));
printf("Throttling\n");
fflush(stdout);
}
sleep(2);
}
}
[Unit]
Description=CPU speed throttle to avoid overheating
[Service]
Type=simple
User=root
Group=root
ExecStart=/usr/local/sbin/throttle
TimeoutSec=1min
Nice=-15
IOSchedulingClass=best-effort
IOSchedulingPriority=1
Restart=always
RestartSec=15sec
[Install]
WantedBy=multi-user.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment