Eigener Treiber
-
Hallo,
ich habe mir einen I²C Treiber für einen A/D Wandler geschrieben (bzw. bin noch dabei).
#include <linux/fs.h> #include <linux/version.h> #include <linux/module.h> #include <linux/init.h> #include <asm/uaccess.h> #include <linux/ioctl.h> #include <asm/io.h> // Peripherieinformationen #define Peripherie_Basis 0x20000000 // Startadresse der Peripherie #define GPIO_Basis (Peripherie_Basis + 0x200000) // Startadresse des GPIO-Controllers #define I2C1_Basis (Peripherie_Basis + 0x804000) // Startadresse des I2C-Controllers // Treiberinformationen #define NAME "ADS1015" // Name des Treibers #define DRIVER_MAJOR 240 // Major Nummer // BSC Status #define DONE (1 << 1) // ADC #define ADC_Data 0 #define ADC_Config 1 #define LO_Tresh 2 #define HI_Tresh 3 static volatile uint32_t Bus = 1; static volatile uint32_t Address = 0x48; static volatile uint32_t Config = 0x40E3; // Programmierer MODULE_AUTHOR("Daniel Kampert"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Driver for ADS1015 I2C ADC"); MODULE_SUPPORTED_DEVICE("Raspberry Pi 512MB"); static volatile uint32_t *GPIO; static volatile uint32_t *I2C1; void I2C_Send_SingleByte(int Bus, int Data, int Address) { // Adresse speichern *(I2C1 + 3) = Address; // Anzahl zu übermittelnder Bytes festlegen *(I2C1 + 2) = 1; // Daten speichern *(I2C1 + 4) = Data; // Statusbits löschen *(I2C1 + 1) = (1 << 9) | (1 << 8) | (1 << 1); // Übertragung starten *(I2C1) = (1 << 15) | (1 << 7); while(!(*(I2C1 + 1) & DONE)); } void I2C_Send_Byte(int Bus, int Register, int Data, int Address) { // Adresse speichern *(I2C1 + 3) = Address; // Anzahl zu übermittelnder Bytes festlegen *(I2C1 + 2) = 2; // Daten speichern *(I2C1 + 4) = Register; *(I2C1 + 4) = Data; // Statusbits löschen *(I2C1 + 1) = (1 << 9) | (1 << 8) | (1 << 1); // Übertragung starten *(I2C1) = (1 << 15) | (1 << 7); while(!(*(I2C1 + 1) & DONE)); } void I2C_Send_Short(int Bus, int Register, int Data, int Address) { int MSB = 0; int LSB = 0; // Daten aufteilen MSB = Data & 0xFF00; MSB = MSB >> 8; LSB = Data & 0xFF; // Adresse speichern *(I2C1 + 3) = Address; // Anzahl zu übermittelnder Bytes festlegen *(I2C1 + 2) = 3; // Daten im FIFO speichern *(I2C1 + 4) = Register; *(I2C1 + 4) = MSB; *(I2C1 + 4) = LSB; // Statusbits löschen *(I2C1 + 1) = (1 << 9) | (1 << 8) | (1 << 1); // Übertragung starten *(I2C1) = (1 << 15) | (1 << 7); while(!(*(I2C1 + 1) & DONE)); } int I2C_Read_Short(int Bus, int Register, int Address) { int MSB = 0; int LSB = 0; // Registeradresse setzen I2C_Send_SingleByte(Bus, Register, Address); // Adresse speichern *(I2C1 + 3) = Address; // Anzahl zu übermittelnder Bytes festlegen *(I2C1 + 2) = 2; // Statusbits löschen *(I2C1 + 1) = (1 << 9) | (1 << 8) | (1 << 1); // Übertragung starten *(I2C1) = (1 << 15) | (1 << 7) | (1 << 4) | (1 << 0); // Auf Daten warten while(!(*(I2C1 + 1) & DONE)); // Daten empfangen MSB = (*(I2C1 + 4) & 255); LSB = (*(I2C1 + 4) & 255); return (MSB << 8) | LSB; } static int driver_open(struct inode *geraete_datei, struct file *instanz ) { // Speicherbereich der IO maskieren GPIO = (uint32_t *)ioremap(GPIO_Basis, 4096); // Speicherplatz des I2C Controllers maskieren I2C1 = (uint32_t *)ioremap(I2C1_Basis, 4096); // Bitmuster löschen *(GPIO) &= ~(7 << 6); *(GPIO) &= ~(7 << 9); // Alternative Funktion 1 aktivieren *(GPIO) |= 4 << 6; *(GPIO) |= 4 << 9; // Systemlog Ausgabe printk("Treiber geoeffnet\n"); printk("ADC wird konfiguriert\n"); // ADC konfigurieren I2C_Send_Short(Bus, ADC_Config, Config, Address); return 0; } static int driver_close(struct inode *geraete_datei, struct file *instanz ) { printk(NAME); printk(" wird beendet....\n"); return 0; } static ssize_t driver_read(struct file *instanz, char *User, size_t Count, loff_t *offset ) { int ret; int Data = 0; int Konfiguration = 0; Konfiguration = I2C_Read_Short(Bus, ADC_Config, Address); // ADC auslesen Data = I2C_Read_Short(Bus, ADC_Data, Address); Data = Data >> 4; // Ausgabe im Systemlog printk("Konfiguration: %i\n", Konfiguration); printk("ADC wird ausgelesen: %i\n", Data); // Daten in den Userspace kopieren ret = copy_to_user(User, &Data, Count); return Count; } static ssize_t driver_write(struct file *Instanz, const char *Buffer, size_t Count, loff_t *offs) { return Count; } // Fileoperations static struct file_operations fops = { .owner= THIS_MODULE, .read= driver_read, .write= driver_write, .open= driver_open, .release= driver_close, }; // Treiber beim Betriebssystem anmelden static int __init Init(void) { if(register_chrdev(DRIVER_MAJOR, NAME, &fops) == 0) { printk(NAME); printk(" erfolgreich angemeldet!\n"); return 0; } else { printk("Anmeldung fehlgeschlagen!\n"); return -EIO; } } // Treiber vom Betriebssystem abmelden static void __exit Exit(void) { unregister_chrdev(DRIVER_MAJOR, NAME); } module_init(Init); module_exit(Exit);
Im Prinzip funktioniert er auch, allerdings nur wenn ich den Treiber über ein C-Programm auslese:
#include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> int main(int argc, char** argv) { int fd; int Status; fd = open("/dev/ADC", O_RDWR); read(fd, &Status, 2); printf("Status: %i", Status); printf("\n"); sleep(1); close (fd); return 0; }
Wenn ich den Treiber nun aber in Python auslesen will, kommt da kein Wert wie 1625 raus, sondern immer ein Buchstabe (z.B. X).
ADC = open("/dev/ADC", "r") ADC_W = 0 ADC_W = ADC.read(2) print ADC_W
Woran kann das liegen?
Und dann habe ich noch eine weitere Frage.
Bisher muss ich den Treiber immer über die Befehleinsmod ADS1015_Driver.ko
mknod /dev/ADC c 240 0einfügen und die Gerätedatei dafür anlegen.
Gibt es eine Möglichkeit das über "modprobe" zu machen?
Bzw. was ist der Unterschied zwischen den beiden Befehlen von mir und "modprobe"?Danke für die Hilfe!
-
Kampi schrieb:
Woran kann das liegen?
Das Python das ADC_W als Text auffasst.
1625 = 0x659 -> 0x06 0x59 in ASCII ist das nicht druckbare Zeichen ACK und das 'Y'
(bei 1624 hast du dann das 'X')Ich kenne Python nicht, aber nach kurzem googeln denke ich, dass es mit struct.unpack gehen sollte.