2017-12-31 160 views
0

Ich habe versucht, Zugriff auf GPIO2 und GPIO3 auf dem Beaglebone Black über Kernel-Modul ohne Erfolg. Jedes Mal, wenn ich versuche, den GPIOs 2 und 3 einen Ausgabewert zuzuweisen, erhalte ich einen Segmentierungsfehler.Warum bekomme ich bei Beaglebone Black beim Zugriff auf GPIO2 und GPIO3 durch Kernelmodul einen Segmentierungsfehler?

Der exakt gleiche Code (mit der entsprechenden Pinbelegung) funktioniert für GPIO0 und GPIO1.

Ich habe versucht, verschiedene Pins auf P8 und P9 im Zusammenhang mit GPIO2 und GPIO3 ohne Erfolg. Auf der anderen Seite funktioniert derselbe genaue Code für GPIO0 und GPIO1 mit entsprechender Pinbelegung.

Für Pin-Werte verwende ich das offizielle BBB-Handbuch. Für eine entsprechende E/A-GPIO Verfügbarkeit Ich bin Überprüfung dieses Diagramm von beagleboard.com: http://beagleboard.org/support/bone101 65 possible digital I/O

#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <net/tcp.h> 

//Macros 
#define GPIO1_START_ADDR 0x4804C000 
#define GPIO2_START_ADDR 0x481AC000 
#define GPIO2_END_ADDR 0x481ACFFF 
#define GPIO3_START_ADDR 0x481AE000 

#define SIZE (GPIO2_END_ADDR - GPIO2_START_ADDR) 
#define GPIO_OE 0x134 
#define GPIO_DATAOUT 0x13C 

//A couple of standard descriptions 
MODULE_LICENSE("GPL"); 

static int hello_init(void) 
{ 
    volatile void *gpio_addr; 
    volatile unsigned int *oe_addr; 
    volatile unsigned int *dataout_addr; 

    printk(KERN_NOTICE "Module: Initializing module\n"); 

    printk(KERN_NOTICE "Module: Map GPIO\n"); 
    gpio_addr = ioremap(GPIO3_START_ADDR,SIZE); 

    printk(KERN_NOTICE "Module: Set oe_addr\n"); 
    oe_addr = gpio_addr + GPIO_OE; 

    printk(KERN_NOTICE "Module: Set dataout_addr\n"); 
    dataout_addr = gpio_addr + GPIO_DATAOUT; 

    //Code will work up to here for any GPIO. 
    //It crashes on the following for GPIO2 and GPIO3: 

    printk(KERN_NOTICE "Module: Set pin to OUTPUT\n"); 
    *oe_addr &= (0xFFFFFFFF^(1<<19)); 

    printk(KERN_NOTICE "Module: Set pin output to HIGH\n"); 
    *dataout_addr |= (1<<19); 

    return 0; 
} 

static void hello_exit(void) 
{ 
    printk(KERN_INFO "Exit module.\n"); 
} 

module_init(hello_init); 
module_exit(hello_exit); 

Wenn ich die beiden Linien *oe_addr &= (0xFFFFFFFF^(1<<19)); und *dataout_addr |= (1<<19); blockieren, läuft das Programm für alle GPIOs ohne Panne.

$uname -a: Linux beaglebone 3.8.13-bone79

Warum bin ich Segmentierungsfehler bekommen, wenn GPIO2 und GPIO3 zugreifen?

+1

"_Ist ich die zwei Zeilen aussperren, läuft das Programm für alle GPIOs ohne Glitch._" ... Wenn Sie das tun, dann wird der IO überhaupt nicht zugegriffen !? Außerdem ist dies kein realer Code - 'module_init()' und 'module_exit()' werden außerhalb jeder Funktion "aufgerufen", was nicht möglich ist. Wenn der Code nicht real ist, wie können wir dann darauf vertrauen, dass der Fehler auftritt? – Clifford

+0

@Clifford Was meinst du, es ist kein Code? Es läuft. Ich habe eine LED an einem der Pins und die LED schaltet sich an, wenn ich es betreibe. So werden Kernel-Module formatiert. module_init (arg) wird aufgerufen, wenn das Modul eingefügt wird, und module_exit (arg) wird aufgerufen, wenn das Modul entfernt wird, wobei arg die Funktion ist, auf die diese Makros zeigen. – CallMeTheMan

+0

Ich denke (von einem schnellen Google), dass Sie 'request_mem_region()' vor 'ioremap()' aufrufen müssen. – Clifford

Antwort

0

Nach viel Forschung habe ich ein paar nützliche Links wie this one und this one gefunden.

Es wird darauf hingewiesen, dass die Standardeinstellung für die GPIOs-Register 1, 2 und 3 Uhr deaktiviert ist, daher der Segmentierungsfehler beim Versuch, auf die Register zuzugreifen. Wenn das System einen GPIO zum Exportieren anfordert, ermöglicht es dann, dass der Takt und die GPIO-Register zur Verwendung verfügbar sind.

Um das Problem zu beheben, müssen wir die Uhren für diese GPIOs manuell aktivieren. Ich konnte dies nicht mit den Code-Beispielen in den Links tun.

jedoch unter Verwendung

echo 5 > /sys/class/gpio/export 
echo 65 > /sys/class/gpio/export 
echo 105 > /sys/class/gpio/export 

Bevor Sie die Mod Einfügen, ich habe Dinge gefunden richtig zu arbeiten. Durch Überwachen des Taktwerts an jedem GPIO habe ich festgestellt, dass sich der Wert von einem Wert zu "2" ändert. Die manuelle Eingabe von 2 in diese Werte reicht jedoch nicht aus, um die GPIOs zum Funktionieren zu bringen.

Wenn ich einen Weg finde, die Uhr durch Speicherkontrolle richtig zu aktivieren, werde ich diese Antwort aktualisieren.

Edit:

Nach mehr Getue und Forschung, die ich den Code bekommen haben, richtig zu arbeiten. Ich habe es als separates Modul geschrieben und es ist eingesetzt werden, bevor das Modul auf die Frage gestellt Einfügen:

#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <net/tcp.h> 

#define CM_PER_ADDR 0x44E00000 
#define CM_PER_SIZE 0x3FF 
#define CM_PER_GPIO1_ADDR 0xAC 
#define CM_PER_GPIO2_ADDR 0xB0 
#define CM_PER_GPIO3_ADDR 0xB4 

#define GPIO_COUNT 3 


//A couple of standard descriptions 
MODULE_LICENSE("GPL"); 

static int hello_init(void) 
{ 
    static volatile void* cm_per; 
    static volatile unsigned int* cm_per_gpio[GPIO_COUNT]; 

    static volatile int cm_per_addr[GPIO_COUNT] = {CM_PER_GPIO1_ADDR, CM_PER_GPIO2_ADDR, CM_PER_GPIO3_ADDR}; 

    static int i = 0; 

    printk(KERN_NOTICE "Module2: Initializing module\n"); 

    cm_per = ioremap(CM_PER_ADDR, CM_PER_SIZE); 
     if(!cm_per){ 
      printk (KERN_ERR "Error: Failed to map GM_PER.\n"); 
      return -1; //Break to avoid segfault 
     } 

    for(i = 0; i < GPIO_COUNT; i++){ 
     cm_per_gpio[i] = cm_per + cm_per_addr[i]; 

     //Check if clock is disabled 
     if(*cm_per_gpio[i] != 0x2){ 
     printk(KERN_NOTICE "Enabling clock on GPIO[%d] bank...\n", (i+1)); 
      *cm_per_gpio[i] = 0x2; //Enable clock 
      //Wait for enabled clock to be set 
      while(*cm_per_gpio[i] != 0x2){} 
     } 

     //Print hex value of clock 
     printk(KERN_NOTICE "cm_per_gpio[%d]: %04x\n", (i+1), *(cm_per_gpio[i])); 
    } 


    return 0; 
} 

static void hello_exit(void) 
{ 
    printk(KERN_INFO "Module: Exit module.\n"); //Print exit notice and exit without exploding anythin 
} 

module_init(hello_init); 
module_exit(hello_exit); 

Vom AM335x and AMIC110 Sitara™ ProcessorsTechnical Reference Manual, können wir sehen, wie CM_PER_GPIO # _CLKCTRL Register organisiert ist (wobei # repräsentiert die GPIO-Bank, die wir betrachten):

Tabelle 8-60. CM_PER_GPIO2_CLKCTRL Register Feldbeschreibungen Table 8-60. CM_PER_GPIO2_CLKCTRL Register Field Descriptions

Es sagt uns auch, dass der Reset (default) Wert des Registers ist 30000h, CLOCK GESPERRT Bedeutung, was bedeutet, Modul deaktiviert.

+1

Ihre "Antwort" ist nur notwendig, weil Sie weiterhin schlecht auf die GPIO-Pins zugreifen. Der von Ihnen gepostete Code ist schlecht geschriebener "Kernel" -Code: (1) ** ioremap() ** ist kein Aufruf an ** request_mem_region() **, (2) die Makros ** ioread ** N () und ** iowrite ** N() werden nicht mit der virtuellen Adresse von ** ioremap() ** verwendet, (3) die Read-Modify-Write-Registeroperationen sind ungeschützte kritische Bereiche, (4) es gibt keine ** iounmap() **, (5) es ist kein Kernel-Codierungsstil. Sie leisten *** keinen Dienst für die Gemeinschaft, indem Sie schlecht geschriebenen, unzuverlässigen Code als "Lösung" veröffentlichen. – sawdust

0

Die Antwort, warum Ihr Code einen Segmentierungsfehler erhält, ist eigentlich irrelevant, weil er als Kernel-Modul fehlgeleitet ist, geworfen werden muss und Sie ihn neu schreiben müssen. Ihr Modul hat absolut keine Probleme, einen direkten Zugriff auf die "GPIO (Kontroll-) Register" zu erhalten, die bereits im Besitz des Pin-Control-Systems (pictrl) sind.

GPIO-Pins sind eine (generische) Ressource, die der Kernel verwaltet. Würden Sie einen Treiber schreiben, der gerade einen willkürlichen Speicherblock für seine Puffer verwendet?
Hoffentlich nicht, weil Speicher (eine andere) Ressource vom Kernel verwaltet wird.
Aber Ihr Modul ist nur mutwillig mit GPIO-Pins nach seiner eigenen Laune!

Die genaue Version des Linux-Kernels, die Sie verwenden, finden Sie im entsprechenden GPIO-Dokument: Documentation/gpio.txt for version 3.8.13.

Die verfügbaren Routinen, die das Modul verwenden können, gehören:

gpio_request() 
gpio_free() 

gpio_direction_input() 
gpio_direction_output() 

gpio_get_value() 
gpio_set_value() 

(BTW Code vernachlässigt den Rückgabewert von ioremap(), zu prüfen, welche null und dann wahrscheinlich führen könnte zu ein Segmentierungsfehler.)

+0

Vielen Dank für die Eingabe, aber es beantwortet die Frage nicht. Ich werde wahrscheinlich versuchen, die gpio Zugriffsmethode zu verwenden, die Sie in meinem nächsten Projekt vorgeschlagen haben, aber das Problem, das ich habe, liegt daran, dass die Uhr auf den GPIOs deaktiviert ist. – CallMeTheMan

+0

* "beantwortet die Frage jedoch nicht" * - Haben Sie Ihrem Code Prüfungen hinzugefügt (wie in der letzten Zeile der Antwort erwähnt)? * "Aber das Problem, das ich habe, ist aufgrund der Uhr deaktiviert werden" * - Wie wurde das bestätigt? Ich habe eine deaktivierte periphere Uhr gesehen, die dazu führt, dass das Peripheriegerät nicht reagiert, aber niemals einen Segmentfehler verursacht. Außerdem sollte das Subsystem ** pinctrl ** die Uhr aktiviert haben. * "Ich werde wahrscheinlich ... bei meinem nächsten Projekt" * - Sie verwenden Barmetal oder Mikrocontroller-Techniken, wenn Sie tatsächlich ein echtes Betriebssystem haben. Es ist ein schlechter Code, der nicht zuverlässig oder tragbar ist. – sawdust

+0

Ich schätze Ihre Punkte und nehme sie zu Herzen. Bitte beachten Sie, dass, wie die Community anfragt, dies nicht der vollständige Code ist, es ist ein Fehler, den Fehler einfach zu replizieren. Ich habe es speziell geschrieben, um es hier zu posten. Mein Code überprüft, ob Speicher korrekt zugeordnet wurde. Ich habe eine Antwort auf meine eigene Frage gepostet, wo es darauf hinweist, dass durch Ändern der Uhr die GPIOs zugreifbar werden. Das Überwachen der GPIO-Uhr vor und nach dem Exportieren von Pins, die zu diesen Registern gehören, zeigt das Umschalten der Uhr auf 2 an. Ich werde die Antwort aktualisieren, wenn ich weiter komme. – CallMeTheMan

Verwandte Themen