| Version 9 (modified by , 11 years ago) (diff) |
|---|
Premier pilote
Objectif
L'objectif de la séance est de commander les LEDS et les boutons poussoir en passant par un pilote. Lors de la dernière séance pour commander les LEDS et accéder aux boutons, vous aviez dû mapper dans l'espace virtuel de l'utilisateur la zone de mémoire permettant l'accès aux GPIO. Il vous fallait avoir les droits du root pour cela. Désormais, les LED et boutons seront accessibles en mode utilisateur.
Nous allons donc créer un pilote pour le périphérique LED+BoutonsPoussoir.
Ce pilote sera accessible dans par le pseudo-fichier /dev/ledbtn (noter que vous serez peut-être obligé de changer un peu le nom pour éviter les conflits avec vos camarades).
Par exemple vous pourrez écrire cela dans un fichier test.c ci-dessous. Ce que fait ce programme importe peu. Ce qui est important c'est que ce programme s'exécute entièrement en mode utilisateur.
Le comportement proposé ici du pilote est le suivant.
- Pour les LEDS, on envoie un tableau de caractère de 4 cases. La case 0 définit l'état de la LED 0 (
'0'LED éteinte sinon LED allumée). - Pour les boutons, on propose un tableau de caractères de 2 cases. Le pilote lit l'état du bouton 0 et le met dans la case 0, et l'état du bouton 1 et le met dans la case 1. Quand le bouton est relâché, le pilote met le caractère
'0', quand le bouton est enfoncé, le pilote met la valeur'1'.
C'est une proposition, vous pouvez faire comme bon vous semble.
#include <stdio.h>
char led[4];
char btn[2];
int main()
{
int fd = open("/dev/ledbtn", O_RDWR);
if (fd < 0) {
fprintf(stderr, "Erreur d'ouverture du pilote LED et Boutons\n");
exit(1);
}
do {
for ( i=0; i<4; i++) {
memcpy( LED, "0000", 4);
LED[i] = '1';
write( fd, LED, 4);
sleep( 1);
}
read( fd, btn, 2);
} while (btn[0] == '0');
return 0;
}
Étape 1 : création et test d'un module noyau
La première étape consiste à créer un module noyau, l'insérer puis l'effacer du noyau.
Le module minimal se compose d'une fonction d'initialisation et d'une fonction de cleanup, dans le fichier module.csuivant:
include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Charlie, 2015");
MODULE_DESCRIPTION("Module, aussitot insere, aussitot efface");
static int __init mon_module_init(void)
{
printk(KERN_DEBUG "Hello World !\n");
return 0;
}
static void __exit mon_module_cleanup(void)
{
printk(KERN_DEBUG "Goodbye World!\n");
}
module_init(mon_module_init);
module_exit(mon_module_cleanup);
Ce fichier est cross compilé et copié sur le raspberry cible avec le fichier Makefile suivant:
CARD_NUMB = 23
ROUTER = 132.227.102.36
LOGIN = franck
LAB = lab2
MODULE = module
CROSSDIR = /users/enseig/franck/peri
KERNELDIR = $(CROSSDIR)/linux-rpi-3.18.y
CROSS_COMPILE = $(CROSSDIR)/arm-bcm2708hardfp-linux-gnueabi/bin/bcm2708hardfp-
obj-m += $(MODULE).o
default:; make -C $(KERNELDIR) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modules
clean:; make -C $(KERNELDIR) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) clean
upload:; scp -P50$(CARD_NUMB) $(MODULE).ko pi@$(ROUTER):$(LOGIN)/$(LAB)
Sur votre compte enseignement, vous devez:
- Créer ces fichiers et bien sûr, les comprendre.
- changer la valeur des variables
CARD_NUMB,LOGINetLABafin de les adapter respectivement au numéro de la carte choisie, au nom du répertoire créé par vous sur la raspberry et au nom du sous-répertoire créé par vous pour ce TP. Les répertoires et sous-répertoires doivent exister et vous devez donc commencer par vous logger sur votre carte Raspberry PI avecsshpour les créer. - Compiler le module avec la commande
make. - Copier sur la raspberry avec scp avec la commande
make upload.
Sur la carte Raspberry PI, vous devez:
- Dans le répertoire
$(LOGIN)/$(LAB)'(par exemplefranck/lab2`) où vous avez copié votre module
$ sudo insmod ./module.ko $ lsmod $ dmesg $ sudo rmmod module $ lsmod $ dmesg
- Les commandes
lsmodetdmesgpermettent de voir que les actions du module.
Étape 2 : ajout des paramètres au module
Votre driver devra être paramétré pour lui indiquer le numéro de ports utilisés pour les LEDS et les boutons. Dans un premier temps vous allez vous contenter d'indiquer le nombre de LED et de boutons pour le module de test, mais il faudra être plus précis pour le vrai driver.
Vous devez ajouter dans module.c (faite d'équivalent pour les boutons):
static int led;
module_param(LED, int, 0);
MODULE_PARM_DESC(LED, "Nombre de led");
static int __init mon_module_init(void)
{
printk(KERN_DEBUG "Hello World !\n");
printk(KERN_DEBUG "LED=%d !\n", LED);
return 0;
}
Le paramètre est défini au moment de l'insertion.
$ insmod ./module.o led=4
Étape 3 : création d'un driver qui ne fait rien mais dans le noyau
Votre driver va être intégré dans un module. Vous allez donc créer un module nommé ledbtn paramétré avec les numéros de ports pour les LEDS et les boutons. Vous utiliserez un nouveau répertoire. Vous modifierez le Makefile en conséquence.
- Vous ajoutez dans le fichier
.cdu module:
struct file_operations fops_ledbtn =
{
.open = open_ledbtn,
.read = read_ledbtn,
.write = write_ledbtn,
.release = release_ledbtn
};
static int
open_ledbtn(struct inode *inode, struct file *file) {
printk(KERN_DEBUG "open()\n");
return 0;
}
static ssize_t
read_ledbtn(struct file *file, char *buf, size_t count, loff_t *ppos) {
printk(KERN_DEBUG "read()\n");
return count;
}
static ssize_t
write_ledbtn(struct file *file, const char *buf, size_t count, loff_t *ppos) {
printk(KERN_DEBUG "write()\n");
return count;
}
static int
release_ledbtn(struct inode *inode, struct file *file) {
printk(KERN_DEBUG "close()\n");
return 0;
}
- Vous allez enregistrer ce driver dans ce module en ajoutant la fonction d'enregistrement dans la fonction init du module. Vous devez aussi prendre en compte les paramètres. C'est à vous de décider comment.
int major = register_chrdev(0, "ledbtn" &fops_ledbtn); // 0 est le numéro majeur qu'on laisse choisir par linux
- Vous allez décharger le driver dans ce module en ajoutant dans la fonction init du module:
unregister_chrdev(major, "ledbtn");
- Vous devez compiler, déplacer le module (upload) et le charger (insmod).
- Vous allez chercher dans le fichier
/proc/devicesle numéromajorchoisi par linux. - vous allez maintenant créer le noeud dans le répertoire
/devet le rendre accessible par tous. Le numéro mineur est 0 car il n'y a qu'une seule instance.
sudo mknod /dev/ledbtn c major 0 sudo chmod a+rw /dev/ledbtn
Le test de votre driver peut se faire par les commandes suivantes (avant de faire un vrai programme):
$ echo "rien" > /dev/ledbtn $ dd bs=1 count=1 < /dev/ledbtn $ dmesg
Étape 4 : accès aux GPIO depuis les fonctions du pilote
[à suivre]
