-- Leo's gemini proxy
-- Connecting to home.gegeweb.org:1965...
-- Connected
-- Sending request
-- Meta line: 20 text/gemini; lang=fr
Ce programme [1] pilote le ventilateur du boîtier Raspberry Pi 4 [2] avec une modulation matérielle à largeur d'impulsion (PWM [3]).
Si vous utilisez le boitier officiel du Raspberry Pi 4 [4], le ventilateur officiel pour ce boitier est une bonne solution de refroidissement.
Cependant… dans ce cas le ventilateur fonctionne en permanence (et n'est pas silencieux !) sauf à utiliser l'option de microprogramme suivante dans /boot/config.txt, le ventilateur connecté comme préconisé sur la broche GPIO 14 (fil bleu).
dtoverlay=gpio-fan,gpiopin=14,temp=80000
Avec l'option ci-dessus, le ventilateur se met en route lorsque la température du processeur atteint 80°C.
Avec ce programme, le ventilateur fonctionne donc plus silencieusement et l'unité centrale connaît des cycles thermiques plus doux qu'avec l'option de microprogramme.
Ce programme consomme mois de 0,1 % d'un cœur en fonctionnement, contre 12 % pour le logiciel PWM. Seules deux broches GPIO exposées sont capables de PWM matériel (GPIO 13 et GPIO 18) et une d'entre elles (GPIO 13) interfère avec le support du ventilateur, donc la broche GPIO 18 est le meilleur choix.
Le programme fonctionne en tant que root et crée deux fichiers pour la surveillance :
/run/pi_fan_hwpwm.pid
et
/run/pi_fan_hwpwm.state
Ce dernier fichier contient trois nombres, par exemple "1337, 68.95, 74.3", qui représentent les boucles d'environ une seconde depuis le démarrage, la température du processeur lissée et le niveau de PWM en pourcentage. Le PWM fonctionne à une fréquence de 20 kHz, ce qui est généralement acceptable pour les ventilateurs et n'est pas gênant pour les animaux de compagnie ou les enfants.
Le programme a été testé par l'auteur du logiciel avec un Raspberry pi 4 sous Ubuntu 20.04 64 bits et Raspbian Pi OS Lite 32 bits. Pour ma part je l'utilise sous Raspberry Pi OS (buster) 64 bits, machine utilisée en « desktop ».
Les options pour /boot/config.txt suggérées dans le code source ne sont pas nécessaires.
Ce programme utilise la librairie C pour Broadcom BCM 2835 [5] utilisée dans les Raspberry Pi, son installation est relativement simple :
cd wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.68.tar.gz tar zxvf bcm2835-1.68.tar.gz cd bcm2835-1.68 ./configure make sudo make install
cd sudo apt install -y git stress-ng git clone https://gist.github.com/1c13096c4cd675f38405702e89e0c536.git cd 1c13096c4cd675f38405702e89e0c536 make sudo make install
stress-ng -c 4 -t 3m -q & watch -n1 cat /run/pi_fan_hwpwm.state
CC = gcc RM = rm -f CFLAGS = -Wall LIBS = -lbcm2835 TARGET = pi_fan_hwpwm all: $(TARGET) $(TARGET): $(TARGET).c $(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c $(LIBS) install: $(TARGET) install $(TARGET) /usr/local/sbin cp $(TARGET).service /etc/systemd/system/ systemctl enable $(TARGET) ! systemctl is-active --quiet $(TARGET) || systemctl stop $(TARGET) systemctl start $(TARGET) uninstall: clean systemctl stop $(TARGET) systemctl disable $(TARGET) $(RM) /usr/local/sbin/$(TARGET) $(RM) /etc/systemd/system/$(TARGET).service $(RM) /run/$(TARGET).* @echo @echo "To remove the source directory" @echo " $$ cd && rm -rf ${CURDIR}" @echo clean: $(RM) $(TARGET)
/* / / pi_fan_hwpwm.c, alwynallan@gmail.com 12/2020, no license / latest version: https://gist.github.com/alwynallan/1c13096c4cd675f38405702e89e0c536 / / Need http://www.airspayce.com/mikem/bcm2835/index.html / / Compile $ gcc -Wall pi_fan_hwpwm.c -lbcm2835 -o pi_fan_hwpwm / / Disable $ sudo nano /boot/config.txt [Raspbian, or use GUI] / $ sudo nano /boot/firmware/usercfg.txt [Ubuntu] / # dtoverlay=gpio-fan,gpiopin=14,temp=80000 <- commented out, reboot / enable_uart=0 <- needed? not Ubuntu / dtparam=audio=off <- needed? not Ubuntu / dtparam=i2c_arm=off <- needed? not Ubuntu / dtparam=spi=off <- needed? not Ubuntu / / Run $ sudo ./pi_fan_hwpwm -v / / Forget $ sudo ./pi_fan_hwpwm & / $ disown -a / */ #include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <stdarg.h> #include <stdarg.h> #include <bcm2835.h> #define PWM_PIN 0 // default, uses both GPIO 13 and GPIO 18 #define HIGH_TEMP 80. #define ON_TEMP 65. #define OFF_TEMP 60. #define MIN_FAN 150 #define KICK_FAN 200 #define MAX_FAN 480 unsigned pin = PWM_PIN; int verbose = 0; int fan_state = 0; double temp = 25.0; pid_t global_pid; int pwm_level = -555; void usage() { fprintf (stderr, "\n" \ "Usage: sudo ./pi_fan_hwpwm [OPTION]...\n" \ "\n" \ " -g <n> Use GPIO n for fan's PWM input, default 0 (both).\n" \ " Only hardware PWM capable GPIO 18 and GPIO 13 are present on\n" \ " the RasPi 4B pin header, and only GPIO 18 can be used with\n" \ " the unmodified case fan.\n" \ " -v Verbose output\n" \ "\n" ); } void fatal(int show_usage, char *fmt, ...) { char buf[128]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); fprintf(stderr, "%s\n", buf); if (show_usage) usage(); fflush(stderr); exit(EXIT_FAILURE); } void run_write(const char *fname, const char *data) { // https://opensource.com/article/19/4/interprocess-communication-linux-storage struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; lock.l_pid = global_pid; int fd; if ((fd = open(fname, O_RDWR | O_CREAT, 0666)) < 0) fatal(0, "failed to open %s for writing", fname); if (fcntl(fd, F_SETLK, &lock) < 0) fatal(0, "fcntl failed to get lock on %s", fname); if (ftruncate(fd, 0) < 0) fatal(0, "truncate failed to on %s", fname); write(fd, data, strlen(data)); close(fd); } void PWM_out(int level) { if(level > pwm_level && (level - pwm_level) < 5) return; if(level < pwm_level && (pwm_level - level) < 10) return; if(level != pwm_level) { if(pin == 0 || pin == 13) bcm2835_pwm_set_data(1, level); if(pin == 0 || pin == 18) bcm2835_pwm_set_data(0, level); pwm_level = level; } } void fan_loop(void) { if(!fan_state && (temp > ON_TEMP)) { PWM_out(KICK_FAN); fan_state = 1; return; } if(fan_state && (temp < OFF_TEMP)) { PWM_out(0); fan_state = 0; return; } if(fan_state) { unsigned out = (double) MIN_FAN + (temp - OFF_TEMP) / (HIGH_TEMP - OFF_TEMP) * (double)(MAX_FAN - MIN_FAN); if(out > MAX_FAN) out = MAX_FAN; PWM_out(out); } } int main(int argc, char *argv[]) { int opt; unsigned loop = 0; int t; FILE *ft; char buf[100]; while ((opt = getopt(argc, argv, "g:v")) != -1) { switch (opt) { case 'g': pin = atoi(optarg); if(pin != 0 && pin != 13 && pin != 18) fatal(0, "Invalid GPIO"); break; case 'v': verbose = 1; break; default: usage(); exit(EXIT_FAILURE); } } if(optind != argc) fatal(1, "optind=%d argc=%d Unrecognized parameter %s", optind, argc, argv[optind]); global_pid = getpid(); sprintf(buf, "%d\n", global_pid); run_write("/run/pi_fan_hwpwm.pid", buf); if(!bcm2835_init()) fatal(0, "bcm2835_init() failed"); if(pin==0 || pin==13) bcm2835_gpio_fsel(13, BCM2835_GPIO_FSEL_ALT0); if(pin==0 || pin==18) bcm2835_gpio_fsel(18, BCM2835_GPIO_FSEL_ALT5); bcm2835_pwm_set_clock(2); // 19.2 / 2 MHz if(pin==0 || pin==13) bcm2835_pwm_set_mode(1, 1, 1); if(pin==0 || pin==13) bcm2835_pwm_set_range(1, 480); if(pin==0 || pin==18) bcm2835_pwm_set_mode(0, 1, 1); if(pin==0 || pin==18) bcm2835_pwm_set_range(0, 480); PWM_out(0); while(1) { loop++; ft = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); fscanf(ft, "%d", &t); fclose(ft); temp = 0.0001 * (double)t + 0.9 * temp; if((loop%4) == 0) { // every second fan_loop(); sprintf(buf, "%u, %.2f, %.1f\n", loop/4, temp, (float)pwm_level/(float)MAX_FAN*100.); run_write("/run/pi_fan_hwpwm.state", buf); if(verbose) fputs(buf, stdout); } usleep(250000); } exit(EXIT_SUCCESS); }
[Unit] Description=Hardware PWM control for Raspberry Pi 4 Case Fan After=syslog.target [Service] Type=simple User=root WorkingDirectory=/run PIDFile=/run/pi_fan_hwpwm.pid ExecStart=/usr/local/sbin/pi_fan_hwpwm Restart=on-failure [Install] WantedBy=multi-user.target
________________________________________________________________________________
-- Response ended
-- Page fetched on Sun Jun 2 00:10:51 2024