Rock64でSPIを使う方法

これはRock64でSPIを使う方法の解説です。  

# Rock64について
Rock64はRaspberryPiのような形をした、RaspberryPiのような機能を持ったシングルボードコンピューターです。
RaspberryPiと比べあまり違わない値段にもかかわらず、高い性能を持ちます。すき。

# 使用した環境
インストールしたOSはArmbian Xenial Desktopです。

SPI通信はL6470ステッピングモータドライバを動かすために使用しました。SPIもL6470もここでは解説しませんが、SPIの概要は理解しておくと本稿を読みやすいと思います。

プログラミング言語はC++を使いました。

# Rock64でSPIする際の問題点
Rock64にはRaspberryPiと同様にGPIOが設置されており、RaspberryPiとほぼ同様のピンアサインを持っているため、多くのHATを繋げそうな見た目をしています(後述の理由によりRock64のバージョンによっては動かない)。

しかし、調べた所以下の問題があることが分かりました。
1. raspi-configなんて無いのでSPIを使用可能にする単純な方法が無い
2. SPIラインに組み込みFlashが既に接続されている
3. **ピンアサイン間違えて製造されてる**

3番・・・


この順に解決方法を紹介します。

# デバイスファイルを出現させる
RaspberryPiではraspi-configでspiのデバイスファイルが/dev/spidev*といった形で現れますが、Rock64にはそんな便利機能はありません。

これは[pine64のフォーラム](https://forum.pine64.org/showthread.php?tid=6282&pid=40056#pid40056)の通りの方法で解決出来ます。

```
# cat >spi1.dts <<EOF
/dts-v1/;
/plugin/;

/ {
        compatible = "pine64,rock64";

        fragment@0 {
                target-path = "/spi@ff190000";
                __overlay__ {
                        spidev@1 {
                                compatible="rockchip,spidev";
                                reg=<1>;
                                spi-max-frequency=<10000000>;
                        };
                };
        };
};
EOF
# dtc spi1.dts -o spi1.dtbo
# mkdir /sys/kernel/config/device-tree/overlays/spi1
# cat spi1.dtbo > /sys/kernel/config/device-tree/overlays/spi1/dtbo
# ls /dev/spidev*
/dev/spidev32766.1
```

これだけでデバイスが出てきます。

# CSが潰されていることへの対策
Rock64のSPIラインには組み込みFlashメモリが接続されています。たちの悪いことにSPI_CSN0_M2は外部に配線されているにも関わらずFlashメモリのCSにも接続されています。また、外に出ているもう一つのCSは何故かSPI_CSN1_M0という別のSPIラインのものでこれは利用できません。
よってCSをRaspberryPiのように自動で動かすことは出来ません。
残された方法は他のGPIOピンをいちいち操作してCS代わりに使うことです。美しくありませんが、そんな方法で問題なく動かすことが出来ます。

GPIOの操作は[こちらのコード](http://independence-sys.net/main/?p=2181)を参考に以下のように書きました。

```
int gpio_init(){
  int fd = 0;

  fd = open("/sys/class/gpio/export", O_WRONLY);
  if (fd < 0) {
          printf("GPIO export open error.\n");
          exit(1);
  }
  write(fd,"101",3);
  close(fd);

  usleep(100000);

  fd = open("/sys/class/gpio/gpio101/direction", O_WRONLY);
  if (fd < 0) {
          printf("GPIO direction open error.\n");
          exit(1);
  }
  write(fd,"out",4);
  close(fd);

  pinfd = open("/sys/class/gpio/gpio101/value", O_WRONLY);
  if (pinfd < 0) {
          printf("GPIO value open error.\n");
          exit(1);
  }
  return 0;
}

int gpio_high(){
  if(pinfd==0) exit(1);
  write(pinfd,"1",2);
  return 0;
}

int gpio_low(){
  if(pinfd==0) exit(1);
  write(pinfd,"0",2);
  return 0;
}

int gpio_clear(){
  close(pinfd);
  pinfd = 0;
  int fd;
  fd = open("/sys/class/gpio/unexport", O_WRONLY);
  if (fd < 0) {
          printf("GPIO unexport open error.\n");
          exit(1);
  }
  write(fd,"101",3);
  close(fd);
  return 0;
}
```

このコードを実行することで、Pi-2 Busの16番ピンであるGPIO3_A5を操作することが出来るようになります。ここを選んだ理由は特にありません。
コード内で度々登場するマジックナンバー101は、[Rock64のGPIOをpythonで動かした人のコード](https://github.com/Leapo/Rock64-R64.GPIO/blob/master/R64/_GPIO.py)のBOARD_to_ROCKに登場するもので、その要素番号16の数字が101でした。この数字はどこかの資料に書いてあるのだろうか？(無知)

# L6470のSPIによる操作
wiringPiSPIで使うデバイスファイルを/dev/spidev32766.1に指定するだけで、世に溢れるwirinPiSPIを使った例をそのまま使ってプログラムが書けますのでここでは省略します。

ただし、wiringPiSPIDataRWの前にCSをLOWに、後にHIGHにするのは忘れないでください。

# Rock64のハードウェアバグ
以上の準備をして動作させたところ、L6470は全く反応を示しませんでした。
これについては[pine64のフォーラム](https://forum.pine64.org/showthread.php?tid=6282&pid=40056#pid40056)に衝撃の情報が書かれていました。

**There is bug in v2.0 hardware that swapped pins 23/24!**

えっっっっっ！！！！
手元のボードを見てみると、V2.0という文字がありました。23番ピンはCLKなので、この影響をモロに受けています。24番ピンにCLKを接続したところ、正しく動作しました。

# まとめ
RaspberryPiの使いやすさを思い知りました。

ただRock64も手間はかかるものの同じようなことが出来ますので、みなさんどうぞお使いください。

数々の情報をネットに置いてくださった先達に感謝します。
ところで[pine64のフォーラムで、情報と共にビールも送られてる](https://forum.pine64.org/showthread.php?tid=6282&pid=40063#pid40063)の面白いですね。