LoginSignup
2
0

More than 5 years have passed since last update.

gpiospiを使ってみた

Last updated at Posted at 2016-12-11

今年の5月にsys/dev/gpio/gpiospi.cというコードがheadに入りました。このコードはZRouterのrayさんが作ったもので、gpioiicと同様にgpioを使ってbitbangでspibusを実現するコードになります。

今のところ、このコードはhintsベースで作られていてFDT対応はおこなわれていません。

利用するにはカーネルのコンフィグレーションに以下を追加します。

device      gpiospi

とりあえずこのコードをFON2100用のビルドにつっこんでみました。

なぜFON2100をターゲットしたかというとちょうど4本のGPIOのパターンが基板にあるからです。もちろん自分がポートしたar531xってのもあります。
FON2100_GPIO1.jpg
ビルドしたカーネルをredbootでloadしてexecすると、ar531xのspiの前にgpiospiがprobeされspibusがaddされてしまいmx25lが見えなくなりrootfsがマウントできなくなりました。いろいろhintsを書いて試したのですがうまくいきません。

spibus1がでてきません。spibusはspiのコードで直にdevice_add_childされています。よく見直してみると自分の書いたar5315_spi.cに問題がありました。

       device_add_child(dev, "spibus", 0);

これだとspibus0として追加される事になりgpiospiが先にspibus0を追加しているので追加できません。マイナーナンバーをインクリメントしてaddするには第三引数を-1にする必要がありました。SOCではbusが増える事は想定していないで、決めうちにしちゃってるんですが、こういう問題が起きちゃうんですね。

これでhintsのmx25lをspibus1にしてgpiospiを追加して、mx25lが見えてrootfsのマウントができるようになりました。

gpiospiのhintsの書き方は以下のようになります。

hint.gpiospi.0.at="gpiobus0"
hint.gpiospi.0.pins=0x9a
hint.gpiospi.0.cs0=0
hint.gpiospi.0.sclk=3
hint.gpiospi.0.mosi=1
hint.gpiospi.0.miso=2

pinsはビットフィールドでcs0などはビットの順番になります。gpioiicと同じです。

これで作ったカーネルを起動してもcs0などが全く出力されません。調べてみるとgpiospi.cのGPIOBUS_PIN_SETFLAGSしているところで、GPIO_PIN_PULLUPなどを指定していて、実際に呼び出されるgpiobus.cを読むと、これに対応していないar5315_spi.cでは設定がおこなわれないためでした。このためとりあえずGPIO_PIN_PULLUPなどを外しました。

信号線は出るようになったのですがSPIスレーブからの返答がありません。オシロで信号線を見たところCLKがLOに落ちる前にHIになっているような状態で、奇麗な波形になっていません。モード0の場合にsc_sclkを0にした後にgpio_delay(sc)を入れてHI/LOがきっちり出るようにしてみました。
nodelay.jpg
delay.jpg
でも、まだうまくいきません。

カーネル内での確認は手間がかかるのでユーザーランドのmrubyのスクリプトでgpioを直接叩いて確認してみる事にしました。これでもうまくいきません。SPIスレーブの機器はArduinoで動作を確認していたので、もはや電気的な問題ぐらいしか考えられなく、プルアップなども試しましたがうまくいかなくて、バッファに74HC126を入れてMOSIをプルアップしたら動くようになりました。

もともとFON2100のGPIO1などは10Kでプルダウンされているのですが、これを外してしまっていたために、プルアップが必要になりました。

余談ですが、gpio上のデバイスの排他制御はおこなわれていないので、gpiospiが組み込まれていても、そのピンをユーザランドからアクセスできます。通常は危険なのでやらない方が良いです。
FON2100_SPI.png
ユーザーランドでうまくいったので、カーネルで試したら以下を設定したらうまくいきました。

hint.gpiospi.0.freq=100000000

bitbangのクロック(スピード)はデバイスやホストによって変わってくるのでトライ&エラーになってしまいます。gpiospi.cの中のgpio_delay()は上記のhintの値を10000000で割っているのでDELAY(10)になるのですが、ちょっと分かりにくいですね。

起動ログはこんな感じでspibus0にもデバイスが追加できる状態になります。

gpio0: <Atheros AR531x GPIO driver> on apb0
gpio0: [GIANT-LOCKED]
gpio0: gpio pinmask=0x7fffff
gpiobus0: <GPIO bus> on gpio0
gpioled2: <GPIO led> at pin 2 on gpiobus0
gpiospi0: <GPIO SPI bit-banging driver> at pins 1,3-4,7 on gpiobus0
spibus0: <spibus bus> on gpiospi0
spibus0: <unknown card> at cs 0 mode 0
gpioc0: <GPIO controller> on gpio0
ar5315_wdog0: <Atheros AR531x watchdog timer> on apb0
spi0: <AR5315 SPI> at mem 0x11300000-0x1130000b on nexus0
spibus1: <spibus bus> on spi0
mx25l0: <M25Pxx Flash Family> at cs 0 mode 0 on spibus1
mx25l0: m25p64, sector 65536 bytes, 128 sectors

カーネル内でSPIをreadするコードはこんな風になります。

        uint8_t txBuf[8], rxBuf[8];
        struct spi_command cmd;
        int err;

        memset(&cmd, 0, sizeof(cmd));
        memset(txBuf, 0, sizeof(txBuf));
        memset(rxBuf, 0, sizeof(rxBuf));  

        /* read spi */
        txBuf[0] = 0x03;
        txBuf[1] = 0x00;
        cmd.tx_cmd = &txBuf;
        cmd.rx_cmd = &rxBuf;
        cmd.tx_cmd_sz = 3;
        cmd.rx_cmd_sz = 3;
        err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd);
        if (err)
                return(0);

        printf("SPI Trans %x¥n", rxBuf[2]);

spiがあるデバイスでgpiospiを追加すると、元々のspiがspibus1となりgpiospiがspibus0となります。これだとflashのmx25lの親が変わってしまい、ちょっと不便です。逆にする方法を考えてみたのですが、良い解決策が思いつきません。

ワイヤリングはこんな感じにしてみました。
写真(2018-09-23 9.30) #2.jpg
なぜこれが必要だったかというとKSZ8995MAのeherswitchのコードを作ろうと思ったからです。今年中に作れるかな。

この修正のレビュー出してみました。

Aitendoの液晶も試してみました。Onion Omegaに小型液晶をつないでみた

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