So erstellen Sie einen eingebetteten Linux-Gerätetreiber (11)

11. Hinzufügen eines I2C-Geräts zum Gerätebaum

Über diese Serie

HowTo-Artikel zum Entwickeln eingebetteter Linux-Gerätetreiber als Kernelmodule. Der gesamte Inhalt dieses Artikels kann auf Raspberry Pi ausgeführt werden.

Der gesamte Quellcode, der in diesem Artikel angezeigt wird

https://github.com/take-iwiw/DeviceDriverLesson/tree/master/11_01

Inhalt dieser Zeit

Bisher haben wir mehrere Gerätetreiber implementiert. Jeder Gerätetreiber hatte jedoch "hardwarespezifische Informationen" direkt im Gerätetreiber.

Zum Beispiel habe ich in 5. Mal GPIO Devadler implementiert, indem ich direkt auf das speicherabgebildete Register geklickt habe. Zu diesem Zeitpunkt hatte ich Chip (SoC) -spezifische Informationen wie die Offset-Adresse im Gerät. Das ist nicht gut. (Erstens wird GPIO selbst nicht erstellt, und normalerweise werden Standardfunktionen des Linux-Kernels verwendet.)

Selbst wenn Sie die Standardfunktionen des Linux-Kernels verwenden, kann Devadora über hardwarespezifische Informationen verfügen. In 10th wurde auf I2C-Geräte mit Standard-I2C-Steuerfunktionen des Linux-Kernels zugegriffen. Die kartenspezifischen Informationen wie der I2C-Bus, an den das Ziel-I2C-Gerät angeschlossen ist, und die Slave-Adresse wurden jedoch im Gerät beschrieben.

Dies ist nach den Regeln nicht mehr zulässig. Der Grund ist, dass der Code mit jeder Variation von SoC und Board stetig zunimmt. Diese Art von hardwarespezifischen Informationen wird heute vom Gerätebaum verwaltet.

Letztes Mal habe ich einen Gerätetreiber für einen an I2C angeschlossenen Beschleunigungssensor (LIS3DH) erstellt. Zu diesem Zeitpunkt war es jedoch erforderlich, dem Kernel manuell Informationen zum I2C-Gerät bereitzustellen. Dieses Mal werde ich versuchen, diese Informationen in den Gerätebaum aufzunehmen. Dieser Artikel ist für Raspberry Pi2 Model B.

Dateien, die sich auf den Gerätebaum beziehen

Obwohl es als "Gerätebaum" bezeichnet wird, handelt es sich tatsächlich um eine Firmware im Binärformat. Die Erweiterung lautet .dtb. Es ist unter / boot in Raspeye. Für RaspberryPi2 Modell B wäre dies beispielsweise "/ 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

SoC-spezifische Informationen sollen in der DTSI-Datei gespeichert werden, und kartenspezifische Informationen sollen in der DTS-Datei gespeichert werden. Durch Kompilieren dieser mit einem speziellen Compiler namens DTC wird die zuvor erwähnte DTB-Datei erstellt. Für Raspeye 2 befindet es sich unter / linux / arch / arm / boot / dts / bcm2709-rpi-2-b.dts.

Schreiben Sie die dtb-Datei direkt neu (ausgeschnittene Version)

Zum Gerätebaum hinzufügen

Wie ich später schreiben werde, ist der richtige Weg, den Linux-Quellbaum einzubringen, / linux / arch / arm / boot / dts / bcm2709-rpi-2-b.dts zu bearbeiten und zu kompilieren. In dieser Serie habe ich es jedoch auf Razpai so einfach wie möglich überprüft. Wieder werde ich es zuerst einfach versuchen.

Bitte sichern Sie bcm2709-rpi-2-b.dts auf der SD-Karte im Voraus auf einem PC usw. Im schlimmsten Fall startet es möglicherweise nicht. Außerdem wird der Compiler (DTC) für den Gerätebaum installiert. sudo apt-get install device-tree-compiler

Kompilieren Sie anschließend die aktuell verwendete DTB-Datei in DTS zurück.

dtc -I dtb -O dts /boot/bcm2709-rpi-2-b.dtb > dis_bcm2709-rpi-2-b.dts

Dadurch wird eine Textdatei mit dem Namen "dis_bcm2709-rpi-2-b.dts" erstellt. Diese Datei enthält einen Baum mit Geräteverbindungsinformationen auf dieser Karte (Raspy 2). Zusätzlich werden auch die Registeradresse etc. aufgelistet. Angenommen, Sie verbinden diesmal LIS3DH (Slave-Adresse = 0x18) mit I2C_1. Suchen Sie zuerst den Knoten für I2C1. Es steht in der Adresse, aber anstelle von "i2c @ 7e804000". Fügen Sie dort einen Knoten namens "mydevice" hinzu. Wenn Sie "kompatibel" auf "mycompany, myoriginaldevice" setzen, wird dies als "Gerät mit dem Namen myoriginaldevice eines Herstellers namens mycompany" angegeben. Stellen Sie außerdem die Slave-Adresse anstelle von reg ein. Dadurch erkennt der Kernel, dass auf dieser Karte ein Gerät namens "mycompany, myoriginaldevice" mit 0x18 auf I2C_1 verbunden ist.

dis_bcm2709-rpi-2-b.dts


Kürzung
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>;

	/*Fügen Sie Ihr eigenes Gerät hinzu*/
	mydevice@18 {
		compatible = "mycompany,myoriginaldevice";
		reg = <0x18>;
	};
};
Kürzung

Kompilieren Sie nach der Bearbeitung mit dem folgenden Befehl und überschreiben Sie die ursprüngliche DTB-Datei. Stellen Sie vorerst das Zugriffsrecht ein.

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

Sie können die Gerätebauminformationen unter / proc / device-tree überprüfen. Nach dem Neustart ist es erfolgreich, wenn mydevice unter I2C1 hinzugefügt wird.

ls /proc/device-tree/soc/i2c@7e804000/mydevice@18/
   compatible  name  reg

Unterstützung auf der Gerätetreiberseite

Auf der Gerätetreiberseite muss das entsprechende Gerät registriert werden. Zuvor habe ich ein Gerät mit dem Namen "mycompany, myoriginaldevice" im Gerätebaum registriert, damit es diesem entspricht. Setzen Sie dazu "struct of_device_id" auf "mycompany, myoriginaldevice" und registrieren Sie es in ".of_match_table" von "struct i2c_driver". Davon abgesehen ist es dasselbe wie bei der vorherigen Implementierung. Der Quellcode wird unten angezeigt.

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>

/***Informationen zu diesem Gerät***/
MODULE_LICENSE("Dual BSD/GPL");
#define DRIVER_NAME "MyDevice"				/* /proc/Gerätename in Geräten usw. angezeigt.*/

/*Übereinstimmende Tabelle der Geräte, die von diesem Gerätetreiber verarbeitet werden*/
/*Entspricht dem folgenden in 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);

/*Registrieren Sie eine Tabelle, in der Geräte aufgeführt sind, die von diesem Gerätetreiber verarbeitet werden*/
/*Wichtig ist das Vornamenfeld. Dies bestimmt den Gerätenamen. Die Rückseite enthält Daten, die mit diesem Treiber frei verwendet werden können. Fügen Sie Zeiger und Identifikationsnummern ein*/
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);

	/*Normalerweise hier, um zu überprüfen, ob das Gerät von diesem Devadora unterstützt wird*/

	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,		//Von diesem Gerätetreiber unterstützte I2C-Geräte
	.probe			= mydevice_i2c_probe,		//Prozess, der aufgerufen wird, wenn das Ziel-I2C-Gerät erkannt wird
	.remove			= mydevice_i2c_remove,		//Prozess wird aufgerufen, wenn das Ziel-I2C-Gerät entfernt wird
};

module_i2c_driver(mydevice_driver);

Der Kernel ruft den entsprechenden Gerätetreiber basierend auf den Verbindungsinformationen in der Gerätestruktur auf. Die im Gerätebaum festgelegte Slave-Adresse wird in der an mydevice_i2c_probe () übergebenen Struktur i2c_client gespeichert.

Ein zu beachtender Punkt ist, dass in diesem Fall struct i2c_device_id NULL enthält. Ich weiß nicht, ob das der Grund ist, aber es scheint, dass ".probe" bald abgeschafft wird. Es scheint stattdessen ".probe_new" zu verwenden. In .probe_new wird struct i2c_device_id gelöscht.

Versuche dich zu bewegen

Erstellen und laden Sie mit dem folgenden Befehl.

make && sudo insmod MyDeviceModule.ko
dmesg
[ 3507.003163] mydevice_i2c_probe
[ 3507.003175] slave address = 0x18
[ 3507.003656] id = 0x33

Wenn Sie sich das Protokoll ansehen, sehen Sie, dass die Sonde ordnungsgemäß aufgerufen wird und auch eine I2C-Kommunikation möglich ist. Beim letzten Mal musste ich die Geräteverbindung manuell benachrichtigen, diesmal jedoch nicht.

Machen Sie DTB aus dem Quellcode

Umweltvorbereitung

Erstellen wir einen DTB aus dem Linux-Quellcode für Raspeye. Holen Sie sich zuerst den Quellcode. Installieren Sie auch die zum Erstellen erforderlichen Werkzeuge. Grundsätzlich ist es wie folgt (https://www.raspberrypi.org/documentation/linux/kernel/building.md). Da es sich um einen nativen Build handelt, ist keine weitere Vorbereitung erforderlich.

sudo apt-get install git bc
git clone https://github.com/raspberrypi/linux.git

Versuchen Sie, die DTS-Datei für Raspeye zu bearbeiten

Die DTS-Datei für Raspberry Pi 2 Model B lautet "/ linux / arch / arm / boot / dts / bcm2709-rpi-2-b.dts". (Diese Datei ist viel sauberer als die zuvor kompilierte dts-Datei, da sie in mehrere Dateien aufgeteilt ist. Diese dts-Datei enthält am Anfang bcm2709.dtsi. Es scheint, dass es durcheinander ist, weil alle umgekehrt kompilierten dts-Dateien enthalten sind.)

Bearbeiten Sie / linux / arch / arm / boot / dts / bcm2709-rpi-2-b.dts auf die gleiche Weise wie zuvor. Fügen Sie das Gerät anstelle von I2C_1 hinzu.

/linux/arch/arm/boot/dts/bcm2709-rpi-2-b.dts


Kürzung
&i2c1 {
	pinctrl-names = "default";
	pinctrl-0 = <&i2c1_pins>;
	clock-frequency = <100000>;

	/*Fügen Sie Ihr eigenes Gerät hinzu*/
	mydevice@18 {
		compatible = "mycompany,myoriginaldevice";
		reg = <0x18>;
	};
};
Kürzung

Versuchen Sie, einen DTB zu erstellen

Kompilieren Sie nach dem Bearbeiten der DTS-Datei nur den DTB mit dem folgenden Befehl. Das Kompilieren auf Raspeye dauert weniger als eine Minute. Kopieren Sie die resultierende DTB-Datei nach / 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/

Hinweis

DTB für Overlays scheint verwendet zu werden, wenn sich der Verbindungsstatus nach dem Start des Kernels dynamisch ändert. Sie müssen es also nicht kopieren.

Versuche dich zu bewegen

Der Gerätetreiber ist derselbe wie die vorherige ausgeschnittene Version und in Ordnung. Ein Neustart sollte das gleiche Ergebnis liefern.

abschließend

Ich habe versucht, mit dem Gerätebaum am Beispiel eines I2C-Geräts zu spielen. Was ich in diesem Artikel angesprochen habe, ist nur eine Berührung des Gerätebaums. Weitere Informationen zum Gerätebaum finden Sie im Artikel + Link unter hier.

Recommended Posts

So erstellen Sie einen eingebetteten Linux-Gerätetreiber (11)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (8)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (1)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (4)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (7)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (2)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (3)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (6)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (5)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (10)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (9)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (12) (vollständig)
Wie man Yubico Yubikey von Manjaro Linux erkennt
So erstellen Sie ein interaktives CLI-Tool mit Golang
So erstellen Sie einen HTTPS-Server mit Go / Gin
[Python] Erstellen einer Adjazenzmatrix / Adjazenzliste [Graphentheorie]
So erstellen Sie ein Hacking-Labor - Kali Linux (2020.1) VirtualBox 64-Bit Teil 2-
So erstellen Sie ein Hacking-Labor - Kali Linux (2020.1) VirtualBox 64-Bit-Edition -
Wie erstelle ich ein Python-Paket (geschrieben für Praktikanten)
So erstellen Sie eine ISO-Datei (CD-Image) unter Linux
Wie erstelle ich eine japanisch-englische Übersetzung?
Wie man einen lockeren Bot macht
So installieren Sie VMware-Tools unter Linux
Wie erstelle ich einen Crawler?
So erstellen Sie eine rekursive Funktion
So installieren Sie MBDyn (Linux Ubuntu)
[Blender] So erstellen Sie ein Blender-Plug-In
[Blender] So erstellen Sie Blender-Skripte mehrsprachig
Wie erstelle ich einen Crawler?
So erstellen Sie den MongoDB C-Sprachtreiber
So überprüfen Sie die Linux-Betriebssystemversion
So machen Sie einen String in Python zu einem Array oder ein Array zu einem String
So bringen Sie den Druckertreiber für Oki Mac in Linux
So machen Sie Word Cloud-Zeichen monochromatisch
Wie baue ich meinen eigenen Linux-Server?
Wie man Selen so leicht wie möglich macht
[Linux] Unterteilen von Dateien und Ordnern
So erstellen Sie einen LINE-Bot mit künstlicher Intelligenz mit der Flask + LINE Messaging-API
So installieren Sie das aws-session-manager-Plugin unter Manajro Linux
[Python] Wie man eine Klasse iterierbar macht
python3 So installieren Sie ein externes Modul
So erstellen Sie eine NVIDIA Docker-Umgebung
So konvertieren Sie Python in eine exe-Datei
Ich möchte wissen, wie LINUX funktioniert!
[Linux] Verwendung des Befehls echo
So aktualisieren Sie PHP unter Amazon Linux 2
So zeigen Sie Piktogramme unter Manjaro Linux an
So installieren Sie Pakete unter Alpine Linux
[Cocos2d-x] So erstellen Sie eine Skriptbindung (Teil 2)
So bedienen Sie Linux von der Konsole aus
So installieren Sie das Windows-Subsystem für Linux
So schalten Sie Linux unter Ultra96-V2 aus
So aktualisieren Sie die Sicherheit unter CentOS Linux 8
Ich möchte ein Automatisierungsprogramm erstellen!