5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

NuttX for Raspberry Pi PicoでPico Display Packを使う

Posted at

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信号を制御する関数を登録します。

boards/arm/rp2040/raspberrypi-pico/src/rp2040_spi.c
#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.png

ST7789のコマンドでは、データを書き込む際の位置をフレームバッファ上のX,Y座標で指定するようになっているので、ずれている分だけのオフセットを指定してやればよいのですが、NuttXのドライバにはその機能がなかったので追加が必要でした。

また、ST7789を使った既存の液晶モジュールではこのフレームバッファを横方向にスキャンする使い方をするのですが、Display Packは縦方向にスキャンするようになっていたため、スキャン方向を指定するコマンドをコントローラに送信する対応を追加しています。
コンフィグレーション CONFIG_LCD_LANDSCAPE を有効にするとスキャン方向が横に90度傾きます。
ちなみに CONFIG_LCD_RLANDSCAPE を有効にすると、表示方向の天地が逆になります。

drivers/lcd/st7789.c
/****************************************************************************
 * 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に入っているデモをそのまま使っています。まだアプリケーションコードはまったく書いていません(笑)。

  1. 正確には、ST7789自体はRX(MISO)の信号が出ていますがDisplay Packがそれを端子側に出していません。基本的にはホスト側からのコマンド/データ送信のみで表示には使えるので不要との判断でしょう。

  2. twitterのコメントに書いたDMAがおかしい件は、ST7789ドライバで使用している16bit転送が正常に動作しない問題があったのが原因で、既に修正済みです。

5
3
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
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?