用意したもの
NanoPi NEO
3.2 インチ LCD:ILI9341 SPI接続 320×240
Amazon.co.jp: DIANN 3.2" ILI9341 SPI TFT LCD Display Touch Panel 320×240 TFT LCD Touch Screen Shield 5V/3.3V STM32 Display Module SPI Serial with Touch Pen : 産業・研究開発用品
Amazon.co.jp: DIANN 3.2" ILI9341 SPI TFT LCD Display Touch Panel 320×240 TFT LCD Touch Screen Shield 5V/3.3V STM32 Displ…
配線
SPI:4本 その他制御用:2本 電源:2本 LEDバックライト:1本
とりあえず、この9本配線されてればOK(削ろうと思えば削れるけど…)

NanoPi NEO の準備
まずは SPI の有効化。
$ sudo vi /boot/armbianEnv.txt
として設定ファイルを書き換える。
次の2行を末尾に付け加えて、保存し、再起動。
overlays=spi-spidev i2c0 usbhost1 usbhost2
param_spidev_spi_bus=0
※I2Cと同時に使おうと、 overlays=spi-spidev i2c0 としたら SPI が動かない…
何やってもダメなので、とりあえず、SPI 一本に絞って使うことにした。
で、
$ sudo reboot
として再起動後、SPIがちゃんと有効化されて起動してきたかを確認する。
$ ls -al /dev/spidev*
crw------- 1 root root 153, 0 6月 20 00:04 /dev/spidev0.0
$ lsmod | grep spi
spidev 20480 0
こんな感じで表示されればOK
続いて、Python の仮想環境をホームディレクトリは配下に作る。
$ cd ~
$ mkdir lcd_con
$ python3 -m venv ./lcd_con
$ cd lcd_con
$ source ./bin/activate
続いてライブラリの導入。
あ、ついでに pip も更新しておく。
(lcd_con)$ sudo apt update
(lcd_con)$ ./bin/pip install --upgrade pip
(lcd_con)$ ./bin/pip install spidev OPi.GPIO
また、NanoPi NEO の GPIO をどうやって使えるようにするかは別記事にてまとめてある。

NanoPi NEO の GPIO が使えるようになるまで
NanoPi NEO って?ちょっと今更感はある。(2025年11月)性能的にはAIの推論もほぼほぼできないし、WiFi も Bluetooth もない。だが、そこがいい。小さいのにGPIO豊富だし、UARTも複数持ってるので。そして、Ar…
準備完了。あとはコードを書いていくだけ。
ffmpeg で映像を流し込む
非力な NanoPi NEO に ffmpeg でエンコさせるなんて…サディスティック…
けどやってみた。
import OPi.GPIO as GPIO
import spidev, time, subprocess
DC = 18
RST = 16
GPIO.setmode(GPIO.CUSTOM)
GPIO.setup(DC, GPIO.OUT)
GPIO.setup(RST, GPIO.OUT)
spi = spidev.SpiDev()
spi.open(0, 0)
spi.mode = 0
spi.max_speed_hz = int(32 * 1000 * 1000)
def cmd(c):
GPIO.output(DC, 0)
spi.writebytes([c])
def cmd_with_data(c, data_list):
GPIO.output(DC, 0)
spi.writebytes([c])
GPIO.output(DC, 1)
spi.writebytes(data_list)
# LCD初期化
def init_lcd():
GPIO.output(RST, 0)
time.sleep(0.05)
GPIO.output(RST, 1)
time.sleep(0.05)
cmd(0x11)
time.sleep(0.12)
# 画面転送方向を横向き(320x240)に変更
cmd_with_data(0x36, [0x98])
time.sleep(0.01)
cmd(0x29)
time.sleep(0.02)
init_lcd()
# --- 配信・画面設定 ---
RTSP_URL = "rtsp://[ID]:[PW]@[Camera IP]/"
WIDTH = 240
HEIGHT = 320
FRAME_RATE = 5
FRAME_SIZE = WIDTH * HEIGHT * 3
# ffmpegのコマンド作成
ffmpeg_cmd = [
'ffmpeg',
'-rtsp_transport', 'tcp',
'-i', RTSP_URL,
'-vf', f'transpose=2,scale={WIDTH}:{HEIGHT}',
'-f', 'rawvideo',
'-pix_fmt', 'rgb24',
'-r', f'{FRAME_RATE}',
'-an', '-sn', '-loglevel', 'quiet',
'-'
]
proc = subprocess.Popen(ffmpeg_cmd, stdout=subprocess.PIPE, bufsize=FRAME_SIZE)
try:
while True:
t_start = time.time()
frame_data = proc.stdout.read(FRAME_SIZE)
if len(frame_data) < FRAME_SIZE:
break
# LCDへ書き込み
cmd(0x2C)
GPIO.output(DC, 1)
spi.writebytes2(frame_data)
# ウェイト
t_elasped = time.time() - t_start
t_sleep = 1.0 / FRAME_RATE - t_elasped
if t_sleep > 0:
time.sleep(t_sleep)
except KeyboardInterrupt:
print("\n終了")
finally:
if proc.stdout:
proc.stdout.close()
proc.terminate()
proc.wait()
spi.close()
GPIO.cleanup()
まぁ 30fps とか 20fps なんてのは到底無理よね。
せいぜい 5fps くらいかねぇ…
とはいえ、目的は達した。
3000円の NanoPi NEO に、2000円の LCD、それだけで超ポータブルな RTSP ビューアができた。
あとはモバイルバッテリーでどれだけ動くか、かな。
この記事にコメントしてみる