Raspberry Pi Pico専用の液晶モジュール Pico Display Pack が秋月電子でも買えるようになりました。
この液晶モジュール、コントローラのST7789はNuttXにも既にドライバが存在するので、NuttXでも簡単に動かせるのではないかと試してみました(が、ちょっとハマりました)。
接続
まず最初の問題が、Display PackとPicoとの接続です。商品ページの写真の通り、Pico専用に作られたモジュールなのでピンヘッダを付けたPicoであればそのまま刺さります。が、挿してしまうと他のGPIOピンから信号を取れなくなってしまうため、UARTが繋げなくなってしまいます。現状USB CDCをサポートしていないPicoのNuttXではこれは大問題。
やむなく、Display Packの液晶関連の各ピンとPicoの同じピンをブレッドボード上で繋ぐことに。せっかくの専用モジュールが台無しですが仕方ない…。
以下のピン同士を接続します。
端子名 | ピン番号 |
---|---|
LCD_DC | 21 |
LCD_CS | 22 |
GND | 18,23 |
LCD_SCLK | 24 |
LCD_MOSI | 25 |
BL_EN | 26 |
LCD_RESET | 30 |
3V3 | 36 |
- モジュール上のスイッチやLEDは今回は使わないので、SW_*とLED_*はそのままです。
- どうやらモジュール側ではGNDがすべてつながっておらず、Pico側で全GNDピン同士がつながっていることを期待しているようです。最低限、18,23のGNDを繋いでおかないとうまく動きませんでした。
NuttX側の対応
前述したとおり、コントローラのST7789は既にドライバがあって、接続に使用するSPIも既にサポート済みです。後は、基本的にはPico対応コード側でSPIポートとST7789ドライバ間を繋いでやればよいのですが、以下の対応が必要でした。
CMD/DATA信号サポート
通常、SPIではホストからデバイスへのデータ(TX / MOSI)、デバイスからホストへのデータ(RX / MISO)、クロック(SCK)、チップセレクト(CS)の4つの線で制御しますが、ST7789にはRXが出ていない1一方で、CMD/DATA(LCD_DC)という信号で、これから送るのがコントローラへのコマンドなのかそのデータなのかを区別する必要があります。
NuttXのSPIドライバでもCONFIG_SPI_CMDDATA
というコンフィグレーションでこれをサポートしているので、これを有効にしたうえでLCD_DC信号を制御する関数を登録します。
#ifdef CONFIG_SPI_CMDDATA
int rp2040_spi0cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd)
{
#ifdef CONFIG_LCD_ST7789
if (devid == SPIDEV_DISPLAY(0))
{
/* This is the Data/Command control pad which determines whether the
* data bits are data or a command.
*/
rp2040_gpio_put(CONFIG_RP2040_SPI0_GPIO, !cmd);
return OK;
}
#endif
return -ENODEV;
}
#endif
#endif
表示位置オフセット、回転サポート
液晶コントローラの中にはフレームバッファRAMがあって、ホストはSPIのコマンドを使ってこのRAMにデータを書き込む一方で、液晶パネルはこのRAMを読んで表示を行います。
ST7789は240×320ピクセル分のRAMを搭載しているのですが、Display Packの液晶パネルにはなぜか、このRAMの中央の135×240ピクセルが表示されるようになっています。ST7789を使った液晶モジュールは240×240の液晶を搭載しているものがほとんどで、これは素直にフレームバッファの上側をそのまま使っているのですが、何故こんなややこしいことを。
ST7789のコマンドでは、データを書き込む際の位置をフレームバッファ上のX,Y座標で指定するようになっているので、ずれている分だけのオフセットを指定してやればよいのですが、NuttXのドライバにはその機能がなかったので追加が必要でした。
また、ST7789を使った既存の液晶モジュールではこのフレームバッファを横方向にスキャンする使い方をするのですが、Display Packは縦方向にスキャンするようになっていたため、スキャン方向を指定するコマンドをコントローラに送信する対応を追加しています。
コンフィグレーション CONFIG_LCD_LANDSCAPE
を有効にするとスキャン方向が横に90度傾きます。
ちなみに CONFIG_LCD_RLANDSCAPE
を有効にすると、表示方向の天地が逆になります。
/****************************************************************************
* Name: st7789_setorientation
*
* Description:
* Set screen orientation.
*
****************************************************************************/
static void st7789_setorientation(FAR struct st7789_dev_s *dev)
{
/* No need to change the orientation in PORTRAIT mode */
#if !defined(CONFIG_LCD_PORTRAIT)
st7789_sendcmd(dev, ST7789_MADCTL);
st7789_select(dev->spi, 8);
# if defined(CONFIG_LCD_RLANDSCAPE)
/* RLANDSCAPE : MY=1 MV=1 */
SPI_SEND(dev->spi, 0xa0);
# elif defined(CONFIG_LCD_LANDSCAPE)
/* LANDSCAPE : MX=1 MV=1 */
SPI_SEND(dev->spi, 0x70);
# elif defined(CONFIG_LCD_RPORTRAIT)
/* RPORTRAIT : MX=1 MY=1 */
SPI_SEND(dev->spi, 0xc0);
# endif
st7789_deselect(dev->spi);
#endif
}
ビルドと起動
NuttXのコンフィグレーション raspberrypi-pico:displaypack
を指定してビルドします。
$ 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:displaypack
$ make
nxhello
コマンドで、以下のようにHello Worldが表示されます2。
ターミナルエミュレータの実行
NuttXのappsには、ウィンドウシステムやターミナルエミュレータも含まれているので、そのコンフィグレーションも有効にしてみます。
以下のdefconfigを使用しました。
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_FS_PROCFS_EXCLUDE_ENVIRON is not set
# CONFIG_LIBC_LONG_LONG is not set
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
# CONFIG_NSH_DISABLE_DATE is not set
# CONFIG_NSH_DISABLE_LOSMART is not set
# CONFIG_NSH_DISABLE_PRINTF is not set
# CONFIG_NSH_DISABLE_TRUNCATE is not set
# CONFIG_NXFONTS_DISABLE_16BPP is not set
# CONFIG_NX_DISABLE_16BPP is not set
# CONFIG_NX_PACKEDMSFIRST is not set
# CONFIG_NX_WRITEONLY is not set
# CONFIG_STANDARD_SERIAL is not set
CONFIG_ARCH="arm"
CONFIG_ARCH_BOARD="raspberrypi-pico"
CONFIG_ARCH_BOARD_RASPBERRYPI_PICO=y
CONFIG_ARCH_CHIP="rp2040"
CONFIG_ARCH_CHIP_RP2040=y
CONFIG_ARCH_RAMVECTORS=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=10450
CONFIG_BUILTIN=y
CONFIG_DEBUG_ASSERTIONS=y
CONFIG_DEBUG_ERROR=y
CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_WARN=y
CONFIG_DISABLE_POSIX_TIMERS=y
CONFIG_DRIVERS_VIDEO=y
CONFIG_EXAMPLES_FB=y
CONFIG_EXAMPLES_HELLO=y
CONFIG_EXAMPLES_NXDEMO=y
CONFIG_EXAMPLES_NXDEMO_BPP=16
CONFIG_EXAMPLES_NXHELLO=y
CONFIG_EXAMPLES_NXHELLO_BPP=16
CONFIG_EXAMPLES_NXTERM=y
CONFIG_EXAMPLES_NXTEXT=y
CONFIG_EXAMPLES_NXTEXT_BPP=16
CONFIG_FS_PROCFS=y
CONFIG_FS_PROCFS_REGISTER=y
CONFIG_HAVE_CXX=y
CONFIG_I2C=y
CONFIG_LCD=y
CONFIG_LCD_DEV=y
CONFIG_LCD_FRAMEBUFFER=y
CONFIG_LCD_MAXCONTRAST=255
CONFIG_LCD_NOGETRUN=y
CONFIG_LCD_ST7789=y
CONFIG_LCD_ST7789_FREQUENCY=64000000
CONFIG_LCD_ST7789_XOFFSET=53
CONFIG_LCD_ST7789_XRES=135
CONFIG_LCD_ST7789_YOFFSET=40
CONFIG_LCD_ST7789_YRES=240
CONFIG_MAX_TASKS=8
CONFIG_MQ_MAXMSGSIZE=64
CONFIG_NFILE_DESCRIPTORS=6
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_READLINE=y
CONFIG_NX=y
CONFIG_NXFONTS_PACKEDMSFIRST=y
CONFIG_NXFONT_SANS17X23B=y
CONFIG_NXTERM=y
CONFIG_NXWIDGETS=y
CONFIG_NXWIDGETS_BPP=16
CONFIG_NXWIDGETS_SIZEOFCHAR=1
CONFIG_NXWM=y
CONFIG_NX_BLOCKING=y
CONFIG_NX_KBD=y
CONFIG_NX_XYINPUT_MOUSE=y
CONFIG_RAM_SIZE=270336
CONFIG_RAM_START=0x20000000
CONFIG_READLINE_CMD_HISTORY=y
CONFIG_RP2040_SPI0=y
CONFIG_RP2040_SPI0_GPIO=16
CONFIG_RP2040_SPI=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_LPWORK=y
CONFIG_SCHED_ONEXIT=y
CONFIG_SCHED_WAITPID=y
CONFIG_SDCLONE_DISABLE=y
CONFIG_SPI_CMDDATA=y
CONFIG_START_DAY=9
CONFIG_START_MONTH=2
CONFIG_START_YEAR=2021
CONFIG_SYSLOG_CONSOLE=y
CONFIG_SYSTEM_I2CTOOL=y
CONFIG_SYSTEM_NSH=y
CONFIG_SYSTEM_SPITOOL=y
CONFIG_TESTING_GETPRIME=y
CONFIG_TESTING_OSTEST=y
CONFIG_UART0_SERIAL_CONSOLE=y
CONFIG_USER_ENTRYPOINT="nsh_main"
CONFIG_VIDEO=y
CONFIG_VIDEO_FB=y
有線LANとの同時使用
更に、NuttX for Raspberry Pi Picoで有線LAN接続で行ったENC28J60による有線LAN接続と同時に使ってみました。
Display PackがSPI0、ENC28J60がSPI1を使用します。
双方を合体させて、以下のようなコンフィグレーションになります。
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_FS_PROCFS_EXCLUDE_ENVIRON is not set
# CONFIG_LIBC_LONG_LONG is not set
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
# CONFIG_NSH_DISABLE_DATE is not set
# CONFIG_NSH_DISABLE_LOSMART is not set
# CONFIG_NSH_DISABLE_PRINTF is not set
# CONFIG_NSH_DISABLE_TRUNCATE is not set
# CONFIG_NXFONTS_DISABLE_16BPP is not set
# CONFIG_NX_DISABLE_16BPP is not set
# CONFIG_NX_PACKEDMSFIRST is not set
# CONFIG_NX_WRITEONLY is not set
# CONFIG_RP2040_DMAC is not set
# CONFIG_STANDARD_SERIAL is not set
CONFIG_ARCH="arm"
CONFIG_ARCH_BOARD="raspberrypi-pico"
CONFIG_ARCH_BOARD_RASPBERRYPI_PICO=y
CONFIG_ARCH_CHIP="rp2040"
CONFIG_ARCH_CHIP_RP2040=y
CONFIG_ARCH_RAMVECTORS=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=10450
CONFIG_BUILTIN=y
CONFIG_DEV_ZERO=y
CONFIG_DISABLE_POSIX_TIMERS=y
CONFIG_ENC28J60=y
CONFIG_EXAMPLES_HELLO=y
CONFIG_EXAMPLES_NXDEMO=y
CONFIG_EXAMPLES_NXDEMO_BPP=16
CONFIG_EXAMPLES_NXHELLO=y
CONFIG_EXAMPLES_NXHELLO_BPP=16
CONFIG_EXAMPLES_NXTERM=y
CONFIG_EXAMPLES_NXTEXT=y
CONFIG_EXAMPLES_NXTEXT_BPP=16
CONFIG_FS_PROCFS=y
CONFIG_FS_PROCFS_REGISTER=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_I2C=y
CONFIG_LCD=y
CONFIG_LCD_DEV=y
CONFIG_LCD_FRAMEBUFFER=y
CONFIG_LCD_MAXCONTRAST=255
CONFIG_LCD_NOGETRUN=y
CONFIG_LCD_ST7789=y
CONFIG_LCD_ST7789_FREQUENCY=64000000
CONFIG_LCD_ST7789_XOFFSET=53
CONFIG_LCD_ST7789_XRES=135
CONFIG_LCD_ST7789_YOFFSET=40
CONFIG_LCD_ST7789_YRES=240
CONFIG_MQ_MAXMSGSIZE=64
CONFIG_NET=y
CONFIG_NETDB_DNSCLIENT=y
CONFIG_NETDB_DNSSERVER_NOADDR=y
CONFIG_NETDEVICES=y
CONFIG_NETINIT_DHCPC=y
CONFIG_NETINIT_DNS=y
CONFIG_NETINIT_DNSIPADDR=0x08080808
CONFIG_NETINIT_NOMAC=y
CONFIG_NETINIT_THREAD=y
CONFIG_NETUTILS_DHCPC=y
CONFIG_NETUTILS_TELNETD=y
CONFIG_NET_BROADCAST=y
CONFIG_NET_ICMP=y
CONFIG_NET_ICMP_SOCKET=y
CONFIG_NET_LOOPBACK=y
CONFIG_NET_ROUTE=y
CONFIG_NET_SOCKOPTS=y
CONFIG_NET_TCP=y
CONFIG_NET_UDP=y
CONFIG_NET_UDP_CHECKSUMS=y
CONFIG_NFILE_DESCRIPTORS=8
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_READLINE=y
CONFIG_NX=y
CONFIG_NXFONTS_PACKEDMSFIRST=y
CONFIG_NXFONT_SANS17X23B=y
CONFIG_NXTERM=y
CONFIG_NXWIDGETS=y
CONFIG_NXWIDGETS_BPP=16
CONFIG_NXWIDGETS_SIZEOFCHAR=1
CONFIG_NXWM=y
CONFIG_NX_BLOCKING=y
CONFIG_NX_KBD=y
CONFIG_NX_XYINPUT_MOUSE=y
CONFIG_RAM_SIZE=270336
CONFIG_RAM_START=0x20000000
CONFIG_READLINE_CMD_HISTORY=y
CONFIG_RP2040_ENC28J60_INTR_GPIO=11
CONFIG_RP2040_ENC28J60_RESET_GPIO=10
CONFIG_RP2040_SPI0=y
CONFIG_RP2040_SPI0_GPIO=16
CONFIG_RP2040_SPI1=y
CONFIG_RP2040_SPI1_GPIO=12
CONFIG_RP2040_SPI=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_HPWORKPRIORITY=192
CONFIG_SCHED_ONEXIT=y
CONFIG_SCHED_WAITPID=y
CONFIG_SDCLONE_DISABLE=y
CONFIG_SMP=y
CONFIG_SMP_NCPUS=2
CONFIG_SPI_CMDDATA=y
CONFIG_START_DAY=9
CONFIG_START_MONTH=2
CONFIG_START_YEAR=2021
CONFIG_SYSLOG_CONSOLE=y
CONFIG_SYSTEM_I2CTOOL=y
CONFIG_SYSTEM_NSH=y
CONFIG_SYSTEM_NTPC=y
CONFIG_SYSTEM_PING=y
CONFIG_SYSTEM_SPITOOL=y
CONFIG_TESTING_GETPRIME=y
CONFIG_TESTING_OSTEST=y
CONFIG_UART0_SERIAL_CONSOLE=y
CONFIG_USER_ENTRYPOINT="nsh_main"
CONFIG_WQUEUE_NOTIFIER=y
ビルドして起動し、コンソールからnxtermを起動します。
動画の34秒あたりから背景が変わって文字が出ているのは、telnetで接続してnxtextという別のデモを実行させたものです。
実用性はともかく、かなり複雑なことができるようになってきました。
すべてNuttXのappsに入っているデモをそのまま使っています。まだアプリケーションコードはまったく書いていません(笑)。