Système de fichiers
Contexte
La carte NanoPi NEO Plus2 est équipée de deux LEDs. La LED rouge est en principe prévue pour indiquer si la cible est sous tension (power) et la LED verte est là pour donner des indications d’état (status). Avec la configuration actuelle du noyau Linux, ces deux LEDs sont à libre disposition des développeurs.
Travail à réaliser
Vous trouverez ci-dessous une application qui contrôle la fréquence de clignotement d’une
LED. Ce code n’a pas été très bien programmé et utilise le 100% d’un cœur du processeur (à mesurer
avec top
).
silly_led_control.c
/**
* Copyright 2018 University of Applied Sciences Western Switzerland / Fribourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Project: HEIA-FR / HES-SO MSE - MA-CSEL1 Laboratory
*
* Abstract: System programming - file system
*
* Purpose: NanoPi silly status led control system
*
* Autĥor: Daniel Gachet
* Date: 07.11.2018
*/
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
/*
* status led - gpioa.10 --> gpio10
* power led - gpiol.10 --> gpio362
*/
#define GPIO_EXPORT "/sys/class/gpio/export"
#define GPIO_UNEXPORT "/sys/class/gpio/unexport"
#define GPIO_LED "/sys/class/gpio/gpio10"
#define LED "10"
static int open_led()
{
// unexport pin out of sysfs (reinitialization)
int f = open(GPIO_UNEXPORT, O_WRONLY);
write(f, LED, strlen(LED));
close(f);
// export pin to sysfs
f = open(GPIO_EXPORT, O_WRONLY);
write(f, LED, strlen(LED));
close(f);
// config pin
f = open(GPIO_LED "/direction", O_WRONLY);
write(f, "out", 3);
close(f);
// open gpio value attribute
f = open(GPIO_LED "/value", O_RDWR);
return f;
}
int main(int argc, char* argv[])
{
long duty = 2; // %
long period = 1000; // ms
if (argc >= 2) period = atoi(argv[1]);
period *= 1000000; // in ns
// compute duty period...
long p1 = period / 100 * duty;
long p2 = period - p1;
int led = open_led();
pwrite(led, "1", sizeof("1"), 0);
struct timespec t1;
clock_gettime(CLOCK_MONOTONIC, &t1);
int k = 0;
while (1) {
struct timespec t2;
clock_gettime(CLOCK_MONOTONIC, &t2);
long delta =
(t2.tv_sec - t1.tv_sec) * 1000000000 + (t2.tv_nsec - t1.tv_nsec);
int toggle = ((k == 0) && (delta >= p1)) | ((k == 1) && (delta >= p2));
if (toggle) {
t1 = t2;
k = (k + 1) % 2;
if (k == 0)
pwrite(led, "1", sizeof("1"), 0);
else
pwrite(led, "0", sizeof("0"), 0);
}
}
return 0;
}
Concevez une application permettant de gérer la fréquence de clignotement de la LED status
de la
carte NanoPi à l’aide des trois boutons-poussoirs.
Quelques indications pour la réalisation de l’application :
- Au démarrage la fréquence de clignotement sera réglée à 2 Hz
- Utilisation des boutons-poussoirs
k1
pour augmenter la fréquencek2
pour remettre la fréquence à sa valeur initialek3
pour diminuer la fréquence- optionnel : une pression continue exercée sur un bouton indiquera une auto incrémentation ou décrémentation de la fréquence.
- Tous les changements de fréquence seront logger avec
syslog
de Linux. - Le multiplexage des entrées/sorties devra être utilisé.
Infos pratiques
GPIO
L’accès aux entrées/sorties est proposé sous le système de fichiers virtuels sysfs, dans le
répertoire /sys/class/gpio/*
. Cette interface est décrite dans la documentation du noyau
Linux (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).
Quelques informations utiles pour l’utilisation du module GPIO sous Linux :
Pour lire ou écrire une valeur sur une pin d’entrée/sortie, il faut tout d’abord configurer le GPIO, soit :
- Exporter la porte dans le sysfs à l’aide de la commande :
# echo <pin_nr> > /sys/class/gpio/export
- Configurer la porte en entrée ou en sortie :
# echo in > /sys/class/gpio/gpio<pin_nr>/direction # echo out > /sys/class/gpio/gpio<pin_nr>/direction
- Lire l’état de la pin (input) :
# cat /sys/class/gpio/gpio<pin_nr>/value
- Changer l’état de la pin (output) :
# echo 0 > /sys/class/gpio/gpio<pin_nr>/value # echo 1 > /sys/class/gpio/gpio<pin_nr>/value
- Pour traiter les entrées/sorties en mode événementiel :
# echo rising > /sys/class/gpio/gpio<pin_nr>/edge # echo falling > /sys/class/gpio/gpio<pin_nr>/edge # echo both > /sys/class/gpio/gpio<pin_nr>/edge
Pour obtenir le numéro du GPIO correspondant à un pin il faut lire la configuration sur le debugfs, soit :
# mount -t debugfs none /sys/kernel/debug
# cat /sys/kernel/debug/gpio
Timer
La librairie timerfd
offre des services très intéressants pour la génération d’une horloge à haute
résolution et surtout une interface permettant le multiplexage des entrées/sorties.
Archives 2021/2022