NuttX for Raspberry Pi PicoでSSD1306 OLEDに画像表示 (I2C接続)

Raspberry Pi PicoのSoCに搭載されているペリフェラルのうち

  - UART (PrimeCell PL011)
  - I2C (Synopsis DW_apb_i2c)
  - SPI (PrimeCell PL022)

は、ソニーSPRESENSEと同じIPが使われています。
そこで、[NuttX](http://nuttx.apache.org/) for [Raspberry Pi Pico](https://qiita.com/yunkya2/items/55f1222e8b2b903dd7ff)から外部デバイスを利用できるように、SPRESENSE(cxd56)用ドライバを元にRP2040用I2Cドライバを追加しました。

I2Cで繋がる先のデバイスとして、Raspberry Pi PicoのMicroPythonでも多くの利用例のある、以下のOLEDディスプレイを使用して画像を表示してみます。

https://www.amazon.co.jp/dp/B071ZPFDWW?tag=pipinn-22&linkCode=ogi&th=1&psc=1

# 接続

Raspberry Pi PicoのI2C0と電源に、SSD1306 OLEDの各端子を以下のようにつなぎます。

|SSD1306 OLED|Pico端子|Pico ピン番号|
|:----------:|:-----------:|:-----------------------:|
|GND|GND|3, 38 などのGNDピンのどれか|
|VCC|3V3|36|
|SDA|GP4 (I2C0 SDA)|6|
|SCL|GP5 (I2C0 SCL)|7|

# NuttXのビルド

I2Cドライバも[公式リポジトリ](https://github.com/apache/incubator-nuttx)にマージ済みです。
OLEDのコントローラ SSD1306 をサポートするコンフィグレーションとして用意した、`raspberrypi-pico:ssd1306`を指定してビルドします。

```
$ git clone https://github.com/apache/incubator-nuttx.git nuttx
$ git clone https://github.com/apache/incubator-nuttx-apps.git apps
$ cd nuttx
$ ./tools/configure.sh raspberrypi-pico:ssd1306
$ make
```

SSD1306の接続先となるI2C0のGPIOピン番号は、コンフィグレーションファイル`nuttx/boards/arm/rp2040/raspberrypi-pico/configs/ssd1306/defconfig`の以下の箇所で指定されています。
指定した番号のGPIOがI2CのSDAに、その次の番号がSCLに使われます。[Raspberry Pi Picoのピンレイアウト図](https://datasheets.raspberrypi.org/pico/Pico-R3-A4-Pinout.pdf)でI2C0が出せるGPIOピンであれば、他の番号[^1]に変更することも可能です。

[^1]: 指定できるのは 0, 4, 8, 12, 16 ,20, 24, 28 のいずれかになります。

```
CONFIG_RP2040_I2C0_GPIO=4
```

# 起動

NuttXを起動すると、/devにI2Cデバイスが追加されています。helpを見ると、いくつかのBuiltin Appsが追加されています。

```

NuttShell (NSH) NuttX-10.0.1
nsh> ls -l /dev
/dev:
 crw-rw-rw-       0 console
 crw-rw-rw-       0 i2c0
 crw-rw-rw-       0 null
 crw-rw-rw-       0 ttyS0

nsh> help
help usage:  help [-v] [<cmd>]

  .         cd        df        free      mkdir     printf    set       truncate
  [         cp        echo      help      mkrd      ps        sleep     uname
  ?         cmp       env       hexdump   mh        pwd       source    umount
  basename  dirname   exec      kill      mount     reboot    test      unset
  break     date      exit      ls        mv        rm        time      usleep
  cat       dd        false     mb        mw        rmdir     true      xd

Builtin Apps:
  nxhello   sh        getprime  hello     nsh
  i2c       ostest    nx        nxdemo    nxlines
nsh>
```

### i2c

`i2c`コマンドは、I2Cバスをスキャンして応答のあったデバイスを表示するコマンドです。
SSD1306のアドレスである3cから応答があることが分かります。

```
nsh> i2c dev 00 7f
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
nsh>
```

### NX

NuttXは[NX](http://nuttx.apache.org/docs/latest/components/nxgraphics/index.html)というグラフィックサブシステムを持っています。今回のコンフィグレーションでSSD1306は既にNXにつながっているので、NX上で動作する以下のサンプルアプリが実行できます。

#### nxhello

以下のように、OLED上にメッセージが表示されます。

![nxhello.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642667/7ae8c59b-45b3-4410-e622-328f84bd4596.png)

#### nxlines

直線が画面中央でくるくる回ります。

https://twitter.com/yunkya2/status/1368067425829199874

#### nxdemo

各種描画のデモです。I2C接続で通信速度が遅いこともあって、だいぶのんびりした表示ですが。

https://twitter.com/yunkya2/status/1368067712744755201

#### nx

NXで実現されているウィンドウシステムのデモです。ウィンドウらしきものが表示されているのが分かりますが、OLEDがモノクロ表示なのでいまいちよく分かりませんね(笑)。

https://twitter.com/yunkya2/status/1368067946451329027