Article HowTo pour développer des pilotes de périphériques Linux embarqués en tant que modules de noyau. Tout le contenu de cet article peut être exécuté sur Raspberry Pi.
https://github.com/take-iwiw/DeviceDriverLesson/tree/master/11_01
Jusqu'à présent, nous avons implémenté plusieurs pilotes de périphériques. Cependant, chaque pilote de périphérique avait des «informations spécifiques au matériel» directement dans le pilote de périphérique.
Par exemple, dans 5ème fois, GPIO Devadler a été implémenté en frappant directement le registre mappé en mémoire. À ce moment-là, j'avais des informations spécifiques à la puce (SoC) telles que l'adresse offset dans l'appareil. Ce n'est pas bien. (En premier lieu, GPIO lui-même n'est pas créé et les fonctions standard du noyau Linux sont généralement utilisées.)
Même si vous utilisez les fonctions standard du noyau Linux, Devadora peut toujours avoir des informations spécifiques au matériel. Dans 10th, les périphériques I2C étaient accessibles à l'aide des fonctions de contrôle I2C standard du noyau Linux. Cependant, les informations spécifiques à la carte telles que le bus I2C auquel le périphérique I2C cible est connecté et l'adresse de l'esclave ont été décrites dans le périphérique.
Cela n'est plus autorisé par les règles. La raison en est que le code augmente régulièrement avec chaque variation de SoC et de carte. Aujourd'hui, ces informations spécifiques au matériel sont gérées par l'arborescence des périphériques.
La dernière fois, j'ai créé un pilote de périphérique pour un capteur d'accélération (LIS3DH) connecté à I2C. Cependant, à ce moment, il était nécessaire de fournir manuellement au noyau des informations sur le périphérique I2C. Cette fois, je vais essayer d'incorporer ces informations dans l'arborescence des périphériques. Cet article concerne le Raspberry Pi2 Model B
Bien qu'il soit appelé "arborescence de périphériques", il s'agit en fait d'un micrologiciel au format binaire. L'extension sera .dtb. C'est sous / boot
dans Raspeye. Par exemple, pour RaspberryPi2 Model B, ce serait / boot / bcm2709-rpi-2-b.dtb
.
ls /boot/*.dtb
/boot/bcm2708-rpi-0-w.dtb /boot/bcm2709-rpi-2-b.dtb /boot/bcm2835-rpi-a-plus.dtb /boot/bcm2835-rpi-zero.dtb
/boot/bcm2708-rpi-b.dtb /boot/bcm2710-rpi-3-b.dtb /boot/bcm2835-rpi-b.dtb /boot/bcm2836-rpi-2-b.dtb
/boot/bcm2708-rpi-b-plus.dtb /boot/bcm2710-rpi-cm3.dtb /boot/bcm2835-rpi-b-plus.dtb
/boot/bcm2708-rpi-cm.dtb /boot/bcm2835-rpi-a.dtb /boot/bcm2835-rpi-b-rev2.dtb
Les informations spécifiques au SoC doivent être stockées dans le fichier DTSI et les informations spécifiques à la carte doivent être stockées dans le fichier DTS. En les compilant avec un compilateur spécial appelé DTC, le fichier DTB mentionné précédemment est créé. Pour Raspeye 2, il se trouve dans / linux / arch / arm / boot / dts / bcm2709-rpi-2-b.dts
.
Comme j'écrirai plus tard, la bonne façon est d'apporter dans l'arborescence des sources Linux, éditer / linux / arch / arm / boot / dts / bcm2709-rpi-2-b.dts
et compiler. Cependant, dans cette série, je l'ai vérifié aussi facilement que possible sur Razpai. Encore une fois, je vais l'essayer facilement d'abord.
Veuillez sauvegarder bcm2709-rpi-2-b.dts
de la carte SD sur un PC, etc. à l'avance. Au pire, cela peut ne pas démarrer. Il installe également le compilateur (DTC) pour l'arborescence des périphériques. sudo apt-get install device-tree-compiler
Puis recompilez le fichier DTB actuellement utilisé dans DTS.
dtc -I dtb -O dts /boot/bcm2709-rpi-2-b.dtb > dis_bcm2709-rpi-2-b.dts
Cela créera un fichier texte appelé dis_bcm2709-rpi-2-b.dts
. Ce fichier contient une arborescence d'informations de connexion de périphérique sur cette carte (Raspy 2). En outre, l'adresse du registre, etc. est également répertoriée. Cette fois, supposons que vous connectiez LIS3DH (adresse esclave = 0x18) à I2C_1. Tout d'abord, recherchez le nœud pour I2C1. Il est écrit dans l'adresse, mais il est à ʻi2c @ 7e804000. Ajoutez-y un nœud appelé
mydevice. En définissant «compatible» sur «mycompany, myoriginaldevice», il est spécifié comme «un périphérique nommé myoriginaldevice fabriqué par un fabricant nommé mycompany». Définissez également l'adresse de l'esclave à la place de
reg`. Cela amène le noyau à reconnaître que cette carte a un périphérique appelé "mycompany, myoriginaldevice" connecté à 0x18 sur I2C_1.
dis_bcm2709-rpi-2-b.dts
réduction
i2c@7e804000 {
compatible = "brcm,bcm2835-i2c";
reg = <0x7e804000 0x1000>;
interrupts = <0x2 0x15>;
clocks = <0x7 0x14>;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <0x10>;
clock-frequency = <0x186a0>;
phandle = <0x20>;
/*Ajoutez votre propre appareil*/
mydevice@18 {
compatible = "mycompany,myoriginaldevice";
reg = <0x18>;
};
};
réduction
Après l'édition, compilez avec la commande suivante et écrasez le fichier DTB d'origine. Pour le moment, définissez le droit d'accès.
dtc -O dtb -o bcm2709-rpi-2-b.dtb dis_bcm2709-rpi-2-b.dts
chmod 755 bcm2709-rpi-2-b.dtb
sudo cp bcm2709-rpi-2-b.dtb /boot/bcm2709-rpi-2-b.dtb
sudo reboot yes
Vous pouvez vérifier les informations de l'arborescence des périphériques dans / proc / device-tree
. Après le redémarrage, il réussit si mon appareil est ajouté sous I2C1.
ls /proc/device-tree/soc/i2c@7e804000/mydevice@18/
compatible name reg
Du côté du pilote de périphérique, il est nécessaire d'enregistrer le périphérique correspondant. Auparavant, j'avais enregistré un appareil appelé "mycompany, myoriginaldevice" dans l'arborescence des appareils, je vais donc le faire correspondre. Pour ce faire, définissez struct of_device_id
sur" mycompany, myoriginaldevice "et enregistrez-le dans
.of_match_table de
struct i2c_driver`. À part cela, c'est la même chose que l'implémentation précédente. Le code source est indiqué ci-dessous.
myDeviceDriver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/of_platform.h>
/***Informations sur cet appareil***/
MODULE_LICENSE("Dual BSD/GPL");
#define DRIVER_NAME "MyDevice" /* /proc/Nom de l'appareil affiché sur les appareils, etc.*/
/*Tableau de correspondance des périphériques gérés par ce pilote de périphérique*/
/*Correspond à ce qui suit en dts
i2c@7e804000 {
mydevice@18 {
compatible = "mycompany,myoriginaldevice";
reg = <0x18>;
};
*/
static const struct of_device_id mydevice_of_match_table[] = {
{.compatible = "mycompany,myoriginaldevice",},
{ },
};
MODULE_DEVICE_TABLE(of, mydevice_of_match_table);
/*Enregistrer une table qui identifie les périphériques gérés par ce pilote de périphérique*/
/*L'important est le champ du prénom. Cela détermine le nom de l'appareil. Le dos est des données qui peuvent être utilisées librement avec ce pilote. Insérer des pointeurs et des numéros d'identification*/
static struct i2c_device_id mydevice_i2c_idtable[] = {
{"MyI2CDevice", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, mydevice_i2c_idtable);
static int mydevice_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
printk("mydevice_i2c_probe\n");
if(id != NULL)
printk("id.name = %s, id.driver_data = %d", id->name, id->driver_data);
if(client != NULL)
printk("slave address = 0x%02X\n", client->addr);
/*Habituellement ici pour vérifier si l'appareil est pris en charge par ce Devadora*/
int version;
version = i2c_smbus_read_byte_data(client, 0x0f);
printk("id = 0x%02X\n", version);
return 0;
}
static int mydevice_i2c_remove(struct i2c_client *client)
{
printk("mydevice_i2c_remove\n");
return 0;
}
static struct i2c_driver mydevice_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = mydevice_of_match_table,
},
.id_table = mydevice_i2c_idtable, //Périphériques I2C pris en charge par ce pilote de périphérique
.probe = mydevice_i2c_probe, //Processus appelé lorsque le périphérique I2C cible est reconnu
.remove = mydevice_i2c_remove, //Processus appelé lorsque le périphérique I2C cible est supprimé
};
module_i2c_driver(mydevice_driver);
Le noyau appellera le pilote de périphérique correspondant en fonction des informations de connexion dans l'arborescence des périphériques. L'adresse de l'esclave définie dans l'arborescence des périphériques est stockée dans la struct i2c_client
passée à mydevice_i2c_probe ()
.
Un point à noter est que dans ce cas, struct i2c_device_id
contiendra NULL. Je ne sais pas si c'est la raison, mais il semble que «.probe» sera bientôt aboli. Il semble utiliser .probe_new
à la place. Dans .probe_new, struct i2c_device_id
est supprimé.
Construisez et chargez avec la commande suivante.
make && sudo insmod MyDeviceModule.ko
dmesg
[ 3507.003163] mydevice_i2c_probe
[ 3507.003175] slave address = 0x18
[ 3507.003656] id = 0x33
Si vous regardez le journal, vous pouvez voir que la sonde est appelée correctement et que la communication I2C est également possible. La dernière fois, j'avais besoin de notifier manuellement la connexion de l'appareil, mais cette fois je ne l'ai pas fait.
Faisons un DTB à partir du code source Linux pour Raspeye. Tout d'abord, récupérez le code source. Installez également les outils nécessaires à la construction. Fondamentalement, c'est comme (https://www.raspberrypi.org/documentation/linux/kernel/building.md). Puisqu'il s'agit d'une version native, aucune autre préparation n'est requise.
sudo apt-get install git bc
git clone https://github.com/raspberrypi/linux.git
Le fichier DTS pour Raspberry Pi 2 Model B est / linux / arch / arm / boot / dts / bcm2709-rpi-2-b.dts
. (Ce fichier est beaucoup plus propre que le fichier dts compilé à l'envers, car il est divisé en plusieurs fichiers. Ce fichier dts inclut bcm2709.dtsi
au début. Il semble que cela soit gâché car tous les fichiers dts compilés à l'envers sont inclus.)
Modifiez / linux / arch / arm / boot / dts / bcm2709-rpi-2-b.dts
de la même manière que précédemment. Ajoutez l'appareil à la place de I2C_1.
/linux/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
réduction
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
clock-frequency = <100000>;
/*Ajoutez votre propre appareil*/
mydevice@18 {
compatible = "mycompany,myoriginaldevice";
reg = <0x18>;
};
};
réduction
Après avoir modifié le fichier DTS, compilez uniquement le DTB avec la commande suivante. La compilation sur Raspeye prend moins d'une minute. Copiez le fichier DTB résultant dans / boot.
cd ~/linux
KERNEL=kernel7
make bcm2709_defconfig
make -j4 dtbs
sudo cp arch/arm/boot/dts/*.dtb /boot/
sudo cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/
sudo cp arch/arm/boot/dts/overlays/README /boot/overlays/
DTB pour les superpositions semble être utilisé lorsque l'état de la connexion change de manière dynamique après le démarrage du noyau. Vous n'avez donc pas à le copier.
Le pilote de périphérique est le même que la version découpée précédente et est OK. Le redémarrage devrait donner le même résultat.
J'ai essayé de jouer avec l'arborescence des appareils en utilisant un appareil I2C comme exemple. Le contenu mentionné dans cet article n'est qu'une touche de l'arborescence des appareils. Pour en savoir plus sur l'arborescence des appareils, veuillez consulter l'article + lien sur ici.
Recommended Posts