LoginSignup
0

More than 1 year has passed since last update.

RaspberryPiでLチカ(/dev/gpiomem経由)

Posted at

やりたいこと

/dev/gpiomemを操作してLEDをチカチカさせます。
以下のページを参考にさせていただきました。
https://www.ei.tohoku.ac.jp/xkozima/lab/raspTutorial3.html

なるべくナイーブに実装して、GPIO4にLEDを繋いでチカチカさせます。

ソースとか

ソース

main.c
//for printf
#include <stdio.h>
//for O_RDWR, O_SYNC
#include <fcntl.h>
//for mmap
#include <sys/mman.h>
//for sleep, open, close
#include <unistd.h>
//for uint32_t
#include <stdint.h>

#define PERI_BASE    0x20200000
#define BLOCK_SIZE   4096

int main() {

    printf("start\n");

    // ①/dev/gpiomemを開く
    int fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
    if( fd == -1 ) {
        printf("cannot open device file\n");
        return 1; 
    }

    // ②物理アドレス 0x20200000 を仮想アドレスにマッピング
    void *gpiomem = mmap(NULL, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PERI_BASE);
    if( (long)gpiomem == -1 ) {
        printf("cannot mmap gpio mem\n");
        return 1;
    } 
    close(fd);
    volatile uint32_t *gpio = (uint32_t*)gpiomem; 

    // ③GPIO4に対応するGPFSELのビット列(3bit)を出力(0b001)に設定
    gpio[0]  = 0b00000000000000000001000000000000;
    for(int i = 0; i < 10; ++i) {
        // ④GPIO4に対応するGPSETを1にする(Highを出力)
        gpio[7]  = 0b00000000000000000000000000010000;
        sleep(1);
        // ⑤GPIO4に対応するGPCLRを1にする(Lowを出力)
        gpio[10] = 0b00000000000000000000000000010000;
        sleep(1);
    }

    printf("end\n");

    return 0;
}

コンパイル

gcc main.c

実行

./a.out

解説

①/dev/gpiomemを開く

物理メモリの特定のアドレスに特定の値を書き込むとそれがGPIOへの命令と解釈されて、GPIOを操作することができます。
Linuxのプロセスからメモリは通常、仮想メモリとしてしか見えません。物理メモリの特定のアドレスにアクセスするためにLinuxは物理メモリへのアクセス経路としてデバイスファイルの/dev/memを用意してくれています。このファイルの先頭が0x00000000の物理アドレスに対応していて、このファイルの特定のアドレスにwirteしてあげると、物理メモリの対応するアドレスに書き込まれます。
通常、この/dev/memはroot所有になっているので通常ユーザからはアクセスできません。RaspberryPiOSでは通常ユーザから物理メモリへアクセスできるようにするため、同じ意味合いの/dev/gpiomemを用意してくれています。
おそらく、/dev/memと/dev/gpiomemは同じもので権限が異なるだけだと思われます。

②物理アドレス 0x20200000 を仮想アドレスにマッピング

Linuxにはファイルのread/writeをメモリへのread/writeに対応させるmmapというシステムコールが用意されてます。
これを/dev/gpiomemに対して呼び出して、仮想メモリ上に/dev/gpiomemの内容を展開するイメージです。
GPIOへの命令は0x20200000以降のアドレスに書き込むので、0x20200000からmmapします。

③GPIO4に対応するGPFSELのビット列(3bit)を出力(0b001)に設定

gpip[0]〜gpio[3]の各ビットがGPIOピンごとの3bitのGPFSELという命令に対応しています。
"出力"とか"入力"などのどういうふうにGPIOを使うかの設定を行うことができます。
今回は、GPIO4を出力ピンとして使用したいので、対応するビットに0b001を書き込みます。

④GPIO4に対応するGPSETを1にする(Highを出力)

gpio[7]の各ビットがGPIOピンごとのHigh出力命令に対応しています。
ここでは、GPIO4にHighを出力するので、対応するビットに0b1を書き込みます。

⑤GPIO4に対応するGPCLRを1にする(Lowを出力)

gpio[10]の各ビットがGPIOピンごとのLow出力命令に対応しています。
ここでは、GPIO4にLowを出力するので、対応するビットに0b1を書き込みます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0