2017-12-31 85 views
0

ビーグルボーンブラックのGPIO2とGPIO3へのアクセスをカーネルモジュールで成功させようとしています。 GPIO 2とGPIO 3に出力値を割り当てようとするたびに、セグメンテーションフォルトが発生します。カーネルモジュール経由でGPIO2とGPIO3にアクセスするとBeaglebone Blackでセグメンテーションフォルトが発生するのはなぜですか?

GPIO0とGPIO1では全く同じコード(適切なピン割り当て)が機能します。

私は、GPIO2とGPIO3に関連するP8とP9の両方にさまざまなピンを試してみましたが、成功しませんでした。フリップ側では、GPIO0とGPIO1では、ピン割り当てが適切な場合と同じコードが機能します。

ピン値については、公式のBBBマニュアルを使用しています。適切なI/O GPIOの可用性のために私は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); 

を私は2つのライン *oe_addr &= (0xFFFFFFFF^(1<<19));*dataout_addr |= (1<<19);を遮断した場合、プログラムはグリッチなしで、すべてのGPIOのために実行されます。

$uname -a: Linux beaglebone 3.8.13-bone79

GPIO2とGPIO3にアクセスしたときに、なぜ私がセグメンテーションフォールトを取得していますか?

+1

"_私が2本のラインをブロックすると... [...]プログラムはグリッチなしですべてのGPIOで実行されます。" ...そうすると、IOは全くアクセスされません!さらに、これは実際のコードではありません。 'module_init()'と 'module_exit()'は関数の外部で呼び出されますが、これは不可能です。コードが実際ではない場合、どのようにして障害が発生すると信じることができますか? – Clifford

+0

@Cliffordコードではないということはどういう意味ですか?それは動く。ピンの1つにLEDが付いていて、走ったときにLEDが点灯します。これがカーネルモジュールのフォーマット方法です。 module_init(arg)は、モジュールが挿入されたときに呼び出され、moduleが削除されたときにmodule_exit(arg)が呼び出されます。argは、これらのマクロが指し示す関数です。 – CallMeTheMan

+0

私は(早いグーグルから) 'ioremap()'の前に 'request_mem_region()'を呼び出す必要があると思います。 – Clifford

答えて

0

多くの研究の結果、this onethis oneのような便利なリンクがいくつか見つかりました。

GPIOレジスタ1,2,3のデフォルト設定はクロックが無効で、であるため、レジスタにアクセスしようとするとセグメンテーションフォルトが発生することが指摘されています。システムがGPIOのエクスポートを要求すると、クロックがイネーブルされ、GPIOレジスタが使用可能になります。

問題を解決するには、これらのGPIOのクロックを手動で有効にする必要があります。私はリンクで見つけられたコードサンプルでこれを行うことができませんでした。

ただしMODを挿入する実行する前に

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

を使用することによって、私は正常に動作する事を発見しました。各GPIOのクロック値を監視することで、ある値から「2」に値が変化することがわかりました。しかし、これらの値に手動で2を入力するだけでは、GPIOを動作させるには十分ではありません。

メモリの制御によってクロックを適切に有効にする方法を見つけたら、この回答を更新します。

編集:

よりFussingの研究の後、私は正しく動作するコードを得ています。 #は表し(AM335x and AMIC110 Sitara™ ProcessorsTechnical Reference Manualから

#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); 

、我々はCM_PER_GPIO#_CLKCTRL登録の編成を把握することができます:私は別のモジュールとしてそれを書かれているし、それが問題に掲載モジュールを挿入する前に挿入します私たちが見ているGPIO銀行):

表8-60。 CM_PER_GPIO2_CLKCTRLレジスタのフィールドの説明 Table 8-60. CM_PER_GPIO2_CLKCTRL Register Field Descriptions

また、レジスタのリセット(デフォルト)値ということを教えてくれるを無効モジュールを意味CLOCK DISABLEDを意味し、 30000H です。

+1

GPIOピンに不正な方法でアクセスし続けるため、あなたの「答え」は必要です。あなたが投稿するコードは、あまり書き込まれていない "カーネル"コードです。** ioremap()**は、** request_mem_region()**、(2)マクロ** ioread ** N )と** iowrite ** N()は** ioremap()**からの仮想アドレスで使用されません、(3)読み取り - 変更 - 書き込みレジスタ操作は保護されていないクリティカル領域です、(4)** iounmap ()**、(5)カーネルコーディングスタイルではありません。あなたは***であり、************************************************************************************************** – sawdust

0

あなたのコードがセグメンテーションフォールトを得ている理由は、カーネルモジュールとして間違っていて、投げられる必要があり、書き直す必要があるため、実際には無関係です。あなたのモジュールは、ピンコントロール(pinctrl)サブシステムによって既に所有されている "GPIO(コントロール)レジスタ"に直接アクセスしようとするビジネスは全くありません。

GPIOピンは、カーネルが管理する(汎用の)リソースです。そのバッファに任意のメモリブロックを使用するだけのドライバを作成しますか?
メモリは(別の)リソースがカーネルによって管理されているため、うまくいきません。
しかしあなたのモジュールはちょうどGPIOピンを自分の気まぐれに使っています。

使用しているLinuxカーネルのバージョンは、適切なGPIOドキュメント(Documentation/gpio.txt for version 3.8.13)を参照してください。あなたのモジュールが使用できる

可能なルーチンが含まれます:

gpio_request() 
gpio_free() 

gpio_direction_input() 
gpio_direction_output() 

gpio_get_value() 
gpio_set_value() 

(ところで、あなたのコードは、に、ヌル、次に可能性の高いリードすることができた、ioremap()の戻り値をチェックするために無視しますセグメンテーションフォールト)

+0

入力いただきありがとうございますが、質問にはお答えしません。私は次のプロジェクトで提案しているgpioアクセスメソッドを使用する方法を検討していますが、問題はGPIOでクロックが無効になっているためです。 – CallMeTheMan

+0

* "質問には答えられません" * - あなたのコードにチェックを追加しましたか(答えの最後の行に記載されています)? * "しかし、私が抱えている問題は、時計が無効になっているためです" * - どのように確認されたのですか?私はペリフェラルが応答しないようにするために、ディセーブルされたペリフェラルクロックを見ましたが、セグメントフォルトを引き起こすことはありません。 ** pinctrl **サブシステムのほかに、クロックを有効にしているはずです。 * "私の次のプロジェクトでは、おそらく..." - あなたは実際に実際のOSを持っているときに、ベアメタルやマイクロコントローラ技術を使用しています。それは、信頼できないか、移植性がない、誤った振る舞いのコードです。 – sawdust

+0

私はあなたの点を感謝し、私はそれらを心に持っていきます。コミュニティが要求するように、それは私のコードの全身ではないことに注意してください。単純にエラーを複製するのは簡単です。私はそれをここに投稿するためにそれを書いた。私のコードは、メモリが正しくマップされているかどうかをチェックします。 GPIOがアクセス可能になるようにクロックを変更することで、自分の質問に答えを投稿しました。それらのレジスタに属するピンをエクスポートする前後にGPIOクロックを監視すると、クロックが2に切り替わります。 – CallMeTheMan

関連する問題