Jetson Xavier NX で Framebuffer Driver を使用する (JetPack 4.6対応)

# はじめに

Jetson Xavier NX (JetPack 4.6)でSPI接続の1.3' 240*240 IPS ST7789(CS ピン無し)ディスプレイの動作確認をしてみました。

https://qiita.com/kitazaki/items/676fdba01b0f145ba976

過去、JetPack 4.3 (r32.3.1)で動作しなかった部分がJetPack 4.6 (r32.6.1)で動作するようになりました。

| | OLED 128x 64 SSD1306 | 1.8' SPI 128x160 ST7735 | 1.3' 240*240 IPS ST7789 |
| --- | --- | --- | --- |
| Raspberry Pi 3B+ | OK | OK | OK |
| Jetson Nano | NG | OK | OK |
| Xavier NX | NG | OK | <font color=#0000FF><b>OK</b></font> |

### 環境

- Jetson Xavier NX
- IPS 240x240@ST7789ディスプレイ

# SPIを有効にする

Jetson-IO tool を使用してSPI (spi1)を有効にします。

https://qiita.com/kitazaki/items/34505828019c102b8701

## Jetson-IO

Configure Jetson 40pin Headerを選択します。(Enterキーを押す)

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/2de64311-7012-d958-6b13-8b24ba3995a7.jpeg)

Configure header pins manuallyを選択します。(矢印キーでカーソルを選択してEnterキーを押す)

![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/402037d5-5d41-6544-9330-9dd6cd6ada9e.jpeg)

spi1を選択します。(矢印キーでカーソルを移動してスペースキーを押すと[*]マークが付きます)
spi1を選択した後はBackで戻ります。(矢印キーでカーソルを移動してEnterキーを押す)

![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/64348724-24bb-3458-2e9a-7894cd25361e.jpeg)

Save and reboot to reconfigure pinsを選択します。(矢印キーでカーソルを選択してEnterキーを押す)

![4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/5d7bb204-77cb-0695-753a-22243543f9bc.jpeg)

DTBファイルが格納され、何かキーを押すとJetson Xavier NXが再起動します。

![5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/f3ba538d-d9e2-c9a3-e255-cd288dbe257d.jpeg)

再起動後にSPIが有効になっているか確認します。

# SPIデバイスを認識させる

https://qiita.com/kitazaki/items/b2d9e4b609f5de709e7e

SPIデバイスが認識されているかどうか確認します。spidev0とspidev2が認識されます。

```bash
$ ls /dev/spidev*
/dev/spidev0.0  /dev/spidev0.1  /dev/spidev2.0  /dev/spidev2.1
```

# SPIデバイスの動作確認

https://qiita.com/kitazaki/items/b2d9e4b609f5de709e7e

テストスクリプト(loop.py)を実行すると、1秒毎に"0x00 0x81"が出力されました。

```bash
$ python3 loop.py 
0x00 0x81
0x00 0x81
...
```

ジャンパーケーブルを接続しない場合は、1秒毎に"0x00 0x00"が出力されます。

```bash
$ python3 loop.py 
0x00 0x00
0x00 0x00
...
```

## 別のループバックテスト

```bash
$ git clone https://github.com/rm-hull/spidev-test
$ cd spidev-test
$ gcc spidev_test.c -o spidev_test
$ ./spidev_test -v
spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 KHz)
TX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  | ......@....?..................?.
RX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  | ......@....?..................?.
```

### ケーブルを接続しない場合

```bash
$ ./spidev_test -v
spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 KHz)
TX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D  | ......@.......................
RX | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | ................................
```

# ディスプレイ(CSピンが無い1.3' IPS 240*240 @ ST7789)の表示確認

ケーブル配線はJetson Nanoと同じです。

https://qiita.com/kitazaki/items/b2d9e4b609f5de709e7e

## ST7789 (Python_ST7789) ライブラリ

問題なく動作しました。

![IMG_9967.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/65f5ffa4-f6a0-4fca-284b-9e30403a4558.jpeg)

## Pimoroni ライブラリ

最初、display.pyは動きませんでした。動作速度(spi_speed_hz)を下げる(80 → 50 MHz)必要がありました。

```python
disp = ST7789.ST7789(port=0, cs=1, rst=24, dc=25, backlight=27, spi_speed_hz=80 * 1000 * 1000)
↓
disp = ST7789.ST7789(port=0, cs=1, rst=24, dc=25, backlight=27, spi_speed_hz=50 * 1000 * 1000)
```

# Framebufferの動作確認

## カーネルビルド

https://qiita.com/kitazaki/items/b2d9e4b609f5de709e7e

カーネルイメージのビルドにかかった時間は以下のとおりでした。

```bash
real	19m9.163s
user	85m15.628s
sys	6m29.704s
```

カーネルモジュールのビルドにかかった時間は以下のとおりでした。

```bash
real	28m1.726s
user	126m12.776s
sys	10m30.132s
```

ビルド完了後、新しい Image をコピーして再起動します。
OS起動後、カーネルモジュールの組み込みでエラーが出ました。

Jetson Xavier NXのGPIO番号は以下のSecond ( gpioXXXX ) is the global Linux GPIO numberを指定する必要がありました。

https://www.jetsonhacks.com/nvidia-jetson-xavier-nx-gpio-header-pinout/

![名称未設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/39b11b9d-df91-be1d-9410-88523aeb5356.jpeg)

```bash
$ sudo modprobe fbtft_device name=flexfb busnum=0 cs=1 gpios=reset:483,dc:481,led:480 speed=40000000 bgr=1 fps=60 custom=1 height=240 width=240 mode=3

$ sudo modprobe flexfb setaddrwin=0 width=240 height=240 init=-1,0x11,-2,120,-1,0x36,0x70,-1,0x3A,0x05,-1,0xB2,0x0C,0x0C,0x00,0x33,0x33,-1,0xB7,0x35,-1,0xBB,0x1A,-1,0xC0,0x2C,-1,0xC2,0x01,-1,0xC3,0x0B,-1,0xC4,0x20,-1,0xC6,0x0F,-1,0xD0,0xA4,0xA1,-1,0x21,-1,0xE0,0x00,0x19,0x1E,0x0A,0x09,0x15,0x3D,0x44,0x51,0x12,0x03,0x00,0x3F,0x3F,-1,0xE1,0x00,0x18,0x1E,0x0A,0x09,0x25,0x3F,0x43,0x52,0x33,0x03,0x00,0x3F,0x3F,-1,0x29,-3
```

```bash
$ dmesg
...
[  171.435983] fbtft: module is from the staging directory, the quality is unknown, you have been warned.
[  171.438672] fbtft_device: module is from the staging directory, the quality is unknown, you have been warned.
[  171.439707] spidev spi0.0: tegra-spidev spi0.0 50000kHz 8 bits mode=0x00
[  171.439715] spidev spi2.0: tegra-spidev spi2.0 50000kHz 8 bits mode=0x00
[  171.439721] spidev spi2.1: tegra-spidev spi2.1 50000kHz 8 bits mode=0x00
[  171.439728] qspi_mtd spi6.0: s25fs256s spi6.0 136000kHz 8 bits mode=0x00
[  171.440439] fbtft_device: GPIOS used by 'flexfb':
[  171.440445] fbtft_device: 'reset' = GPIO483
[  171.440451] fbtft_device: 'dc' = GPIO481
[  171.440455] fbtft_device: 'led' = GPIO480
[  171.440465] spidev spi0.0: tegra-spidev spi0.0 50000kHz 8 bits mode=0x00
[  171.440471] spidev spi2.0: tegra-spidev spi2.0 50000kHz 8 bits mode=0x00
[  171.440477] spidev spi2.1: tegra-spidev spi2.1 50000kHz 8 bits mode=0x00
[  171.440483] qspi_mtd spi6.0: s25fs256s spi6.0 136000kHz 8 bits mode=0x00
[  171.440495] spi spi0.1: flexfb spi0.1 40000kHz 8 bits mode=0x03
[  176.692595] flexfb: module is from the staging directory, the quality is unknown, you have been warned.
[  176.963999] graphics fb2: flexfb frame buffer, 240x240, 112 KiB video memory, 4 KiB DMA buffer memory, fps=62, spi0.1 at 40 MHz

$ ls -la /dev/fb*
crw-rw---- 1 root video 29, 0  2月 28 23:02 /dev/fb0
crw-rw---- 1 root video 29, 1  2月 28 23:02 /dev/fb1
crw-rw---- 1 root video 29, 2  2月 28 23:06 /dev/fb2
```

```bash
$ cd fbtest
$ ./fbtest --fbdev /dev/fb2
Using drawops cfb16 (16 bpp packed pixels)
Available visuals:
  Monochrome
  Grayscale 32
  Truecolor 5:6:5:0
Using visops truecolor
Running all tests
test001: PASSED
test002: PASSED
test003: PASSED
test004: PASSED
test005: PASSED
test006: PASSED
test008: PASSED
test009: PASSED
test010: PASSED
Benchmarking... 10x10 squares: 198.47 Mpixels/s
Benchmarking... 20x20 squares: 456.42 Mpixels/s
Benchmarking... 50x50 squares: 713.81 Mpixels/s
Benchmarking... 100x100 squares: 1232.68 Mpixels/s
Benchmarking... 200x200 squares: 1123.73 Mpixels/s
test012: PASSED
Benchmarking... R5 circles: 78.06 Mpixels/s
Benchmarking... R10 circles: 170.10 Mpixels/s
Benchmarking... R25 circles: 440.38 Mpixels/s
Benchmarking... R50 circles: 734.39 Mpixels/s
Benchmarking... R100 circles: 918.28 Mpixels/s
test013: PASSED
```

https://youtu.be/jBWq0xKLpAM