メモリマップドI / Oアドレス指定はどのように機能しますか?


29

メモリマップドI / Oアドレス指定はどのように機能しますか?

I2Sが提供するサンプルを理解しようとしています。誰もが実行していますか?

クロックの構成:

#define BCM2708_PERI_BASE        0x20000000
#define CLOCK_BASE               (BCM2708_PERI_BASE + 0x101000) /* Clocks */

最初に次のようにコードをマッピングします...

clk_map = (unsigned char *)mmap(
      (caddr_t)clk_mem,
      MAP_BLOCK_SIZE,
      PROT_READ|PROT_WRITE,
      MAP_SHARED|MAP_FIXED,
      mem_fd,
      CLOCK_BASE
   );

それから何かをする...

 // Always use volatile pointer!
   clk = (volatile unsigned *)clk_map;

そして、それが参照されるとき、0x26と0x27のこれらの奇妙な追加があります、それはどうですか?

 printf("Disabling I2S clock\n");
 *(clk+0x26) = 0x5A000000;
 *(clk+0x27) = 0x5A000000;

 usleep(10);

 printf("Confiure I2S clock\n");
 *(clk+0x26) = 0x5A000001;
 *(clk+0x27) = 0x5A000000 | 3<<12 | 1<<9; // divider: 3.125==0b11.001

 usleep(10);
 printf("Enabling I2S clock\n");
 *(clk+0x26) = 0x5A000011;

データシートを見ると、ベースアドレスなど、これらの値の一部がどこにあるかがわかりますが、他の値を理解するのに苦労しています。それはどこでCLOCK_BASE決定され、何が起こっていますか?


1
これはおそらくStackOverflowに最適です。RPiに関連していますが、プログラミングの質問に対する回答が得られる可能性が高くなります。
Jivings

4
たぶん、しかし、データシートの解釈とPiハードウェアを組み合わせた、より一般的なPiプログラミング関連の質問だと思います。良い情報が得られるかどうか見てみましょう。
犬の耳

はい。それがどうなるか見てみましょう:)
Jivings

1
これはStack Overflowではあまりうまくいかないと思います。かなり専門的であり、ここでより専門的な注意を引くでしょう。
フレキソ

回答:


18

コンピューターでは、指定された「メモリアドレス」に書き込みます。このアドレスは、システムによってハードウェアアドレスとして認識され、適切なハードウェアが適切な値を受信または送信します。

ほとんどのハードウェアシステムには、設定または読み取り可能なさまざまなレジスタがあります。いくつかの可能性があり、いくつかの可能性があります。これらのレジスタは連続した範囲にグループ化されます。ベースポインターは範囲内の最初のポインターを指し、たとえばbase_pointer + 1で2番目のポートに書き込みます。ポインターに直接書き込む必要はありませんが、オフセットを使用すると作業が簡単になります。

Raspberry Piは、アドレス0x20000000で広範なハードウェアレジスタを認識します。クロックシステムを制御するレジスタの範囲には、BCM2708_PERI_BASE + 0x101000からアクセスします。I2Sクロックを制御するレジスタは、そのブロックの38番目と39番目のレジスタであり、BCM2708_PERI_BASE + 0x101000 + 0x26および0x27を使用して書き込まれます

ただし、クロック値を変更することはできません。クロックを無効にし、値を変更して再起動する必要があります。

この答えが基本的すぎる場合、おIfび申し上げます。その場合、あなたの質問は本当にハードコアで幸運です。このリンクは役に立つかもしれません

更新:mmapを使用し、メモリに直接書き込まないのはなぜですか?

プログラムがメモリアドレスを実行しているとき、プログラムは実際のアドレスではないと判断し、メモリマネージャによって実際のアドレスにマッピングされます。これにより、あるプログラムが別のプログラムに影響を与えることができなくなります。2つのプロセスは独自のアドレス1234に対して完全に読み書きでき、メモリマネージャーは2つの場所を完全に分離します。

ただし、ハードウェアポートは絶対的な物理アドレスにあります。ただし、メモリマネージャがアドレスを取得して個人のメモリ領域にマッピングするため、直接書き込むことはできません。

Linuxでは、/ dev / memは「コンピューターメインメモリのイメージであるキャラクターデバイスファイル」です。

これをファイルのように開くと、ファイルのように読み書きできます。提供されたサンプルでは、​​mem_fdは/ dev / memを開いた結果のファイルハンドルです。

人生をもっと楽にするもう1つのシステムは、ファイルをメモリにマップし、メモリのように書き込む機能です。したがって、異なる特定のビットを読み書きするファイルがある場合は、ファイルポインターを前後に移動する代わりに、メモリ内の場所にマップしてから、メモリのように直接書き込むことができます。

そのため、このサンプルでは、​​コードはディスク上のファイルであるかのように物理メモリへのハンドルを作成し、それをメモリであるかのように処理するようシステムに要求しています。少し複雑ですが、仮想メモリマネージャを回って実際の物理アドレスに書き込むために必要です。値0x20000000は、赤いニシンのようです。コードはこのアドレスをヒントとして提案しているため、システムは/ dev / memをここでマップする必要はありませんが、おそらくそうします。通常、値nullが渡され、システムはファイルハンドルを最適と思われるアドレスにマップします。

これで、物理メモリがプロセスの仮想メモリにマップされ、読み取りと書き込みが期待どおりに行われます。

参照:

http://www.kernel.org/doc/man-pages/online/pages/man2/mmap.2.html

http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=8496&p=104359

https://superuser.com/questions/71389/what-is-dev-mem


私はまだいくつかの質問があります:なぜ彼らはmmapですか?メモリに直接アクセスしないのはなぜですか?
アレックスチェンバレン

@AlexChamberlainコードはLinuxで実行されるため、各プロセスが独自の仮想メモリスペースを取得するため、メモリに直接アクセスすることはできません。しかし、一つは開くことができるとmmapは/ dev / memの物理メモリに直接アクセスするために
番号

1

@AlexChamberlainこれはOS構造によるものです。なくてもかまいませんmmapが、ページングが宣言されているため、直接アクセスできません。カーネルモードmmapでは、たとえばを必要とせずにドライバーをカーネルモジュールとして挿入することで、なしで実行できますmmap。また、ページテーブルメモリが使用されていない最も単純なOSの場合、mmapどちらでもなく、つまりでアクセスできます。物理アドレスへの直接アクセス。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.