LoginSignup
1
0

RaspberryPi2 + CommonLisp(SBCL) で LED をチカチカさせる

Posted at

動機

  • Raspberry Pi があるのだからLチカくらいやってみたくなった
  • どうせなら便利ライブラリを使わずにやってみたい
  • 今後の展開を考えてCommon Lispで作ってみたい

GPIOを使ったLEDの点灯・消灯

手順は以下の通り。

  1. 指定したピンのモードを出力に指定
  2. 指定したピンをHIGHに指定で点灯
  3. 指定したピンをLOWに指定で消灯

今回はGPIOの17ピン、物理ピンだと11番を使います。

回路図

回路図

抵抗は手元にあった1KΩを使いました
(本当は10mAくらい流すと良いようなので300Ωくらいで良い)

RaspberryPiのI/Oへのアクセス

いわゆるメモリマップドI/Oなので、然るべきメモリにアクセスできればI/Oにアクセスすることができます。

Raspberry Pi のメモリ配置

手持ちは Raspberry Pi 2 で、 CPU は BCM2836 です。
BCM2836 は BCM2835 と同じなので、BCM2835のデータシートを参照します。

BCM2835 ARM Peripherals

I/O ペリフェラルは 7E000000 からで、実アドレスの 20000000 にマッピングされているのですが、 BCM2836 は 3F000000 に読み替えが必要とのこと。

アウトプットモードのON

GPIO 17番ピンをアウトプットモードにセットするには、 FSEL17001 にセットします。

image.png

c で書くとこんな感じになるはず。

uint32_t FSEL17_OUT = 1 << 21;
*(ADDRESS) = FSEL17_OUT;

アドレスは GPFSEL1 で、 7E0000003F000000 に読み替えなので、 3F200004 になります。

image.png

Cで書くとこんな感じです。

ちなみに、 /dev/mem を読み書きする関係で root での実行が必要です。

#define GPIO_BASE 0x3F200000
#define BLOCK_SIZE (4 * 1024)

void gpio17_out() {
    int fd;
    volatile uint32_t * gpio;

    fd = open("/dev/mem", O_RDWR | O_SYNC);

    gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);

    close(fd);

    *(gpio + 1) = 1 << 21;
}

gpio コマンドで実行前後のステータスを確認すると、GPIO17番(BCM17)の MODE が IN から OUT にちゃんと変更されてました。

実行前
gpio readall
 +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 1 | ALT0 | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | ALT0 | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |  OUT | 0 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |  OUT | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | OUT  | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
 |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+
実行後
gpio readall
 +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 0 | IN   | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | IN   | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |  OUT | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |  OUT | 0 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |  OUT | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | OUT  | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
 |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+

GPIOをHIGHに設定

GPIO 17番ピンをHIGHにするには、 GPSET0SET171 をセットします。

image.png

cだとこんな感じ。

uint32_t SET17 = 1 << 17;
*(ADDRESS) = SET17;

GPIOをLOWに設定

GPIO 17番ピンをLOWにするには、GPCLR0CLR171 をセットします。

image.png

cのサンプルは割愛。

SBCL で書く

SBCL のインストール

上記のページから Linux の ARMhf 版をダウンロードします。

image.png

適当なディレクトリで展開して完了です。

Quicklisp のインストール

SBCL を展開したディレクトリで Quicklisp のコードを落としてきます。

$ curl -O https://beta.quicklisp.org/quicklisp.lisp

そうしたら Quicklisp を読み込みつつ起動します。
/dev/mem をアクセスする関係で root で起動します。

$ sudo ./run-sbcl.sh --load quicklisp.lisp

Quicklisp 本体のインストールを行います。

(quicklisp-quickstart:install)

インストールが完了したら、次回起動時に Quicklisp を自動で読み込むように .sbclrc に設定を追記します。

(ql:add-to-init-file)

実装

mmap ライブラリは以下のものを使用するので、 Quicklisp で落としておきます。

(ql:quickload :mmap)

コードです。

(let ((gpio (mmap:mmap #P"/dev/mem" :open '(:read :write :data-sync)
                                    :protection '(:read :write)
                                    :mmap '(:shared)
                                    :size (* 4 1024)
                                    :offset #x3F200000))
      (gpfsel1 1)
      (gpset0 7)
      (gpclr0 10)
      (gpfsel17-out (ash 1 21))
      (set17 (ash 1 17))
      (clr17 (ash 1 17)))
  ;; GPFSEL1 を OUT にセット
  (setf (cffi:mem-aref gpio :uint32 gpfsel1) gpfsel17-out)
  (loop repeat 10
        do
           ;; 点灯
           (setf (cffi:mem-aref gpio :uint32 gpset0) set17)
           (sleep 1)
           ;; 消灯
           (setf (cffi:mem-aref gpio :uint32 gpclr0) clr17)
           (sleep 1)))

実行結果です。

led.gif

(暗いのでわかりにくいですが1秒おきに点滅してます)

参考

RaspberryPi で GPIO のアクセスを簡単にできるようにするライブラリ

BCM2835のデータシート。Raspberry Pi 2のCPU BCM2836 もこれを見ればOK。

Raspberry Pi 2 で GPIO のアドレスが違っているなんてここを見るまで気付きませんでした。

1
0
0

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
1
0