みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

NuttXでRAMLOG(dmesg)を使用する

はじめに

NuttXではデバッグログをRAMに出力することができる。 RAMに出力されたログデータはLinuxなどでおなじみのdmesgコマンドで表示することができる。

BluePillのようなRAMの少ない環境では活用は難しそうだが、STM32F4Discoveryくらい余裕のある環境であれば非常に便利。

ここではSTM32F4Discoveryの環境でRAMLOGを有効にする。

RAMLOG

usbnshとnshで有効にすべきコンフィグレーションが異なる。

usbnshでの設定

次の設定が必要となる。

CONFIG_RAMLOG=y
CONFIG_RAMLOG_CONSOLE_BUFSIZE=1024
CONFIG_RAMLOG_NONBLOCKING=y
CONFIG_RAMLOG_SYSLOG=y
#CONFIG_SYSLOG_CHAR undefined, else duplicate output with syslog_putc()

メニューコンフィグ

make menuconfigで設定する項目を示す。

CONFIG_RAMLOG

Device Drivers
  -> System Logging
    -> RAM log device support

CONFIG_RAMLOG_NONBLOCKING

Device Drivers
  -> System Logging
    -> RAM log device support
      -> RAMLOG non-block reads

CONFIG_RAMLOG_SYSLOG

Device Drivers
  -> System Logging
    -> System log device
      -> Use RAMLOG for SYSLOG

nshでの設定

次の設定が必要となる。

CONFIG_RAMLOG=y
CONFIG_RAMLOG_CONSOLE_BUFSIZE=1024
CONFIG_RAMLOG_CONSOLE=y
CONFIG_RAMLOG_SYSLOG=y
#CONFIG_SYSLOG_CHAR undefined, else duplicate output with syslog_putc()

メニューコンフィグ

make menuconfigで設定する項目を示す。

CONFIG_RAMLOG

Device Drivers
  -> System Logging
    -> RAM log device support

CONFIG_RAMLOG_CONSOLE

Device Drivers
  -> System Logging
    -> RAM log device support
      -> Use RAMLOG for /dev/console

CONFIG_RAMLOG_SYSLOG

Device Drivers
  -> System Logging
    -> System log device
      -> Use RAMLOG for SYSLOG

バッファサイズについて

RAMLOGのバッファはリングバッファで実装1されており、 バッファを使い切ると古いログは新しいログに上書きされる。

CONFIG_RAMLOG_CONSOLE_BUFSIZEのデフォルトは1024となっているが、 この程度のサイズだと、デバッグ時に見たいログがすぐに上書きされてしまう。

なのでCONFIG_RAMLOG_CONSOLE_BUFSIZEを8192くらいに増やしておく。

Device Drivers
  -> System Logging
    -> RAMLOG buffer size

デバッグログ有効化

必要に応じでデバッグログの機能を有効化する。

コンフィグレーション

例としてSchedulerのデバッグログを有効化する。

CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_ERROR=y
CONFIG_DEBUG_WARN=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_SCHED=y
CONFIG_DEBUG_SCHED_ERROR=y
CONFIG_DEBUG_SCHED_WARN=y
CONFIG_DEBUG_SCHED_INFO=y

メニューコンフィグ

CONFIG_DEBUG_FEATURES

Build Setup
  -> Debug Options
    -> Enable Debug Features

CONFIG_DEBUG_ERROR

Build Setup
  -> Debug Options
    -> Enable Debug Features
      -> Enable Error Output

CONFIG_DEBUG_WARN

Build Setup
  -> Debug Options
    -> Enable Debug Features
      -> Enable Error Output
        -> Enable Warnings Output

CONFIG_DEBUG_INFO

Build Setup
  -> Debug Options
    -> Enable Debug Features
      -> Enable Error Output
        -> Enable Warnings Output
          -> Enable Informational Debug Output

CONFIG_DEBUG_SCHED

Build Setup
  -> Debug Options
    -> Enable Debug Features
      -> Scheduler Debug Features

CONFIG_DEBUG_SCHED_ERROR

Build Setup
  -> Debug Options
    -> Enable Debug Features
      -> Scheduler Debug Features
        -> Scheduler Error Output

CONFIG_DEBUG_SHED_WARN

Build Setup
  -> Debug Options
    -> Enable Debug Features
      -> Scheduler Debug Features
        -> Scheduler Warnings Output

CONFIG_DEBUG_SCHED_INFO

Build Setup
  -> Debug Options
    -> Enable Debug Features
      -> Scheduler Debug Features
        -> Scheduler Informational Output

動作確認

helpコマンドを実行してdmesgが有効化されていればOK。

NuttShell (NSH)
nsh> help
help usage:  help [-v] [<cmd>]

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

Builtin Apps:
nsh>

dmesgを実行してログが表示される事を確認。

nsh> dmesg
os_start: Entry
uart_register: Registering /dev/console
uart_register: Registering /dev/ttyS0
os_do_appstart: Starting init thread
os_start: CPU0: Beginning Idle Loop

Linuxとは異なり、一度実行されたログは再度コマンドを実行しても表示されなくなる。

NuttXをSTM32F4Discoveryで動かす(NSH編)

STM32F4Discovery + NuttXの続き。

はじめに

STM32F4DiscoveryでのNSHの使用方法を紹介する。

コンフィグレーション

次のようにコンフィグレーションを実行する。

$ cd nuttx
$ tools/configure.sh -l stm32f4discovery/nsh

接続方法

STM32F4DiscoveryとUSB-TTL変換ケーブルの接続は次のようになる。

ケーブル側 BluePill
5V(赤) 5V
GND(黒) GND
TXD(緑) PA10(RX1)
RXD(白) PA9(TX1)

Ubuntuでは/dev/ttyUSB0として見えるのでminicomなどで接続する。

NuttXをSTM32F4Discoveryで動かす

はじめに

これまでBluePillで遊んできたNuttXをSTM32F4Discoveryで動かす。

STM32F4DiscoveryはSTM32F407VGT6が載っている。

メモリ サイズ
フラッシュ 1MiB
RAM 192KiB

BluePillと比較するとかなりリッチなリソースを持っている。

NuttXの作成

基本的なところはBluePillの時と同じ

ソースの取得

$ git clone https://bitbucket.org/nuttx/nuttx.git
$ git clone https://bitbucket.org/nuttx/apps.git

コンフィグレーション

USB経由でシェルを使用する場合は次のようにする。

$ cd nuttx
$ tools/configure.sh -l stm32f4discovery/usbnsh

ビルド

次のコマンドでビルドする。

$ make -j4

ボードへの書き込み

STM32F4DiscoveryにはST-LINK/V2がオンボードで搭載されているため、USB miniBのポートからnuttx.binを書き込むことができる。

ボードのUSB miniBポートとPCを接続し、次のコマンドを実行する。

$ st-flash write nuttx.bin 0x8000000

st-flashstlink toolsに含まれている。作り方はここを参照。

sigrok PulseViewのビルド

はじめに

アマゾンで買ったロジアナを使用するためにPulseViewインストールする。

このロジアナはSaleae社の製品のコピー品らしい。ソフトウェアはSaleae社のものが使用できるらしいが、それはそれで問題があるし。

環境はUbuntu 18.04。

apt

Ubuntuではaptでインストールできる。

$ sudo apt install pulseview

ビルド

最新版を使用したい場合はソースからビルドする。

libsigrok

$ git clone git://sigrok.org/libsigrok
$ cd libsigrok
$ ./autogen.sh
$ ./configure
$ make -j4
$ sudo make install
$ sudo ldconfig

libsigrokdecode

$ git clone git://sigrok.org/libsigrokdecode
$ cd libsigrokdecode
$ ./autogen.sh
$ ./configure
$ make -j4
$ sudo make install
$ sudo ldconfig

sigrok-cli

$ git clone git://sigrok.org/sigrok-cli
$ cd sigrok-cli
$ ./autogen.sh
$ ./configure
$ make -j4
$ sudo make install
$ sudo ldconfig

pulseview

$ git clone git://sigrok.org/pulseview.git
$ cd pulseview
$ mkdir build
$ cd build
$ cmake ..
$ make -j4
$ sudo make install

udevルールの追加

$ wget https://raw.githubusercontent.com/keesj/saleae-logic-libusb/master/contrib/udevd/99-saleae-logic-libusb.rules
$ sudo mv 99-saleae-logic-libusb.rules /etc/udev/rules.d/
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger

PCにロジアナを接続してdmesgで次のように表示されれば無事に認識。

[81262.978175] usb 1-7: USB disconnect, device number 73
[81264.587230] usb 1-7: new high-speed USB device number 78 using xhci_hcd
[81264.755819] usb 1-7: New USB device found, idVendor=0925, idProduct=3881
[81264.755823] usb 1-7: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[81264.755826] usb 1-7: Product: fx2lafw
[81264.755828] usb 1-7: Manufacturer: sigrok
[81264.755830] usb 1-7: SerialNumber: Saleae Logic

PulseView起動

$ pulseview

f:id:mickey_happygolucky:20190201092531p:plain
PulseViewの実行画面

入れてる波形は適当。

STM32F103 minimum(BluePill)上のNuttXをOpenOCD(とブラウザ)でデバッグ

BluePill + NuttXの続き。

OpenOCDでデバッグ

フラッシュを128K使うために、OpenOCDを使用してイメージを書き込んだ。 せっかくOpenOCDを使用しているのでデバッグもできるはず。

デバッグ用のイメージを作成するとnuttx.binのサイズが最低でも70K程度になってしまうので、128Kの環境をベースに作業する。

コンフィギュレーション

ベースの環境はNSHで作業する。

$ cd nuttx
$ tools/configure.sh -l configs/stm32f103-minimum/nsh

メニューコンフィグ

make menuconfigで次の項目を有効化する。

CONFIG_DEBUG_NOOPT

Build Setup
  -> Optimization Level
    -> Suppress Optimization

CONFIG_DEBUG_SYMBOLS

Build Setup
  -> Debug Options
    -> Generate Debug Symbols

GDBでイメージを書き込む

前にOpenOCDでイメージを書き込んだ時は、telnetでOpenOCDに接続したが、 実はGDBでもイメージの書き込みを行なうことができる。

$ openocd -f /usr/local/share/openocd/scripts/interface/stlink-v2.cfg -f /usr/local/share/openocd/scripts/target/stm32f103c8t6.cfg

別のシェルを開き、nuttx.binがあるディレクトリで次のコマンドを実行する。

$ arm-none-eabi-gdb nuttx

これで次のようにgdbのプロンプトが出てくる。

...(snip)...

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from nuttx...
(gdb)

この状態で次のコマンドを実行する。

(gdb) target remote localhost:3333

これでGDBがOpenOCDと接続されターゲットを操作できるようになる。つまりターゲットと接続される。

(gdb) mon reset halt
(gdb) mon flash write_image erase /home/mickey/work/nuttx/nuttx/nuttx.bin 0x08000000
(gdb) mon reset run
(gdb) quit

やっていることはtelnetでしたことと全く同じ。 localhostの3333ポートに接続して、イメージを書き込むだけ。

gdbではmon(monitor)コマンドを使う必要があるが、それ以降の構文は全く同じ。

mon reset runのあとで、シリアルコンソールでnshが問題なく動作すればOK

ここの例では書き込み後、一度GDBを終了しているが継続して作業することもできる。

デバッグ開始

GDBが実行されていない状態からの手順を示す。

書き込みの時と同様に、OpenOCDが実行中のものとは違うシェルでGDBを起動する。

$ arm-none-eabi-gdb nuttx

ターゲットと接続後、実行中のプログラムを停止し、プログラムをロードする。

(gdb) target remote localhost:3333
(gdb) mon reset halt
(gdb) load

この状態からステップやブレークなどのデバッグが可能となる。

初期化ファイル

GDB起動からloadまでのコマンドは毎回同じなので手動で実行するのは手間となる。

初期化ファイルを作成し自動的に実行されるようにする。

nuttx.gdbinitを次の内容で作成する。

target remote localhost:3333
mon reset halt
load

GDBを起動するときに指定する。

$ arm-none-eabi-gdb  nuttx -x nuttx.gdbinit

gdbgui

gdbguiというプログラムを使用すると、ブラウザ上のGUIデバッグすることができる。

インストール

pipコマンドでインストールする。

$ sudo pip install gdbgui --upgrade

gdbguiの起動

次のコマンドでgdbguiをarm-none-eabi-gdbのフロントエンドとして起動する。

$ gdbgui -g arm-none-eabi-gdb 

ブラウザ上にデバッグ画面が表示され、デバッグ可能となる。

初期化ファイルの指定

gdbguiで初期化ファイルを指定する場合は次のようにする。

$ gdbgui -g arm-none-eabi-gdb --gdb-args "-x nuttx.gdbinit" nuttx

GUIで直感的にデバッグができるのですごく便利。

f:id:mickey_happygolucky:20190130221244p:plain
gdbguiの実行画面

NuttXをSTM32F103 minimum(BluePill)で動かす(NSH編)

NuttX + BluePillの続き。

UARTでシェル

前回まではBluePillとPCをUSBケーブルで接続しUSB経由でシェルを使用していたが、 今回はUSB-TTL変換ケーブルで接続しUART経由でシェルを使用してみる。

コンフィギュレーション

基本的なNuttXのビルド方法は変わらないが、コンフィギュレーションを次のようにする。

$ cd nuttx
$ tools/configure.sh -l configs/stm32f103-minimum/nsh

接続方法

ビルド方法と書き込み方法は省略する。

PCと接続するUSB-TTL変換ケーブルはこんな感じのものを使用する。

基本的には5VGNDTXDRXDを接続する。

変換ケーブルとBluePillの接続は次のようになる。

ケーブル側 BluePill
5V(赤) 5V
GND(黒) GND
TXD(緑) PA10(RX1)
RXD(白) PA9(TX1)

USB-TTL変換ケーブルの色は手元のケーブルのもので書いたが、実際のところすべての変換ケーブルがこのアサインなのかどうかはわからない。 ざっと調べたところ、これと同じ確率は高いとおもう。

Ubuntuでは/dev/ttyUSB0として見えるのでminicomなどで接続する。

比較

バイナリサイズ

configure.sh実行後、make menuconfigの変更をしない状態でのnuttx.binのサイズを比較した。

USBNSH NSH
50K 40K

UART接続のNSHの方が10K小さくできる。

RAM消費量

デフォルトのままではprocfsが無効のためmeminfoが見れないので、 CONFIG_FS_PROCFSだけ有効にして比較してみる。

まず、この状態のバイナリサイズ

USBNSH NSH
58K 49K

次にfreeコマンドの結果

total used free largest
USBNSH 16640 10208 6432 6416
NSH 17104 11536 5568 5552

freeコマンドの各項目の意味は次の通り。

項目 概要
total This is the total size of memory allocated for use by malloc in bytes.
used This is the total size of memory occupied by chunks handed out by malloc.
free This is the total size of memory occupied by free (not in use) chunks.
largest Size of the largest free (not in use) chunk.

largestってピークのことではないのね。

意外なことにRAMの消費量はUARTのNSHの方が大きいという結果になった。

NuttXのSTM32F103 minimum(BluePill)で128Kのフラッシュを使う

はじめに

前回STM32F103C8T6のフラッシュは64KiBだと書いた。

しかし、NuttXのconfigs/stm32f103-minimum/scripts/ld.scriptを参照すると、次のように書いてある。

 *
 * NOTE: While the STM32F103C8T6 states that the part has 64Kb of FLASH,
 * all parts that I have seen do, in fact, have 128Kb of FLASH.  That
 * additional 64Kb of FLASH can be utilized by simply change the LENGTH
 * of the flash region from 64K to 128K.

...(snip)...

MEMORY
{
    flash (rx) : ORIGIN = 0x08000000, LENGTH = 64K
    sram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}

つまり、公開しているスペックとしては64Kだが実際には128Kのフラッシュが載っている。 このリンカスクリプトのLENGTHの部分を128Kに書き換えるだけで、フラッシュを128Kまで使用できるということらしい。

実際の作業はここを参考にさせてもらった。

BluePillのフラッシュを128Kにしてみる

まずは、ld.scriptを次のように修正してみる。

diff --git a/configs/stm32f103-minimum/scripts/ld.script b/configs/stm32f103-minimum/scripts/ld.script
index ec15a978f8..32649c8c9a 100644
--- a/configs/stm32f103-minimum/scripts/ld.script
+++ b/configs/stm32f103-minimum/scripts/ld.script
@@ -48,7 +48,7 @@
 
 MEMORY
 {
-    flash (rx) : ORIGIN = 0x08000000, LENGTH = 64K
+    flash (rx) : ORIGIN = 0x08000000, LENGTH = 128K
     sram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
 }
 
-- 
2.17.1

なにか機能を増やしてバイナリサイズを増やしてみる。

make menuconfigでいろいろ機能を増やしてみて、64Kよりも大きいnuttx.binを作ってみる。

-rwxr-xr-x   1 mickey mickey   67K  1月 28 10:27 nuttx.bin

67Kのnuttx.binができた。

st-flashで書き込みを試してみる。

st-flashコマンドで書き込みを試してみる。ただ、このコマンドはSTM32F103C8T6のフラッシュを64Kと認識しているので、うまく行く可能性は低そう。。。

$ st-flash write nuttx.bin 0x8000000
st-flash 1.5.1
2019-01-28T08:43:33 INFO usb.c: -- exit_dfu_mode
2019-01-28T08:43:33 INFO common.c: Loading device parameters....
2019-01-28T08:43:33 INFO common.c: Device connected is: F1 Medium-density device, id 0x20036410
2019-01-28T08:43:33 INFO common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x10000 bytes (64 KiB) in pages of 1024 bytes
2019-01-28T08:43:33 INFO common.c: Attempting to write 67076 (0x10604) bytes to stm32 address: 134217728 (0x8000000)
2019-01-28T08:43:33 ERROR common.c: addr too high
stlink_fwrite_flash() == -1

予想通り失敗した。

OpenOCDで書き込み

ネットの情報を探してみると、OpenOCDでちょっとした細工をすると64Kを超えるイメージを書き込めるようになるらしい。

OpenOCDのインストール

OpenOCDをソースからビルドしインストールする。

$ git clone http://repo.or.cz/openocd.git
$ cd openocd
$ ./bootstrap
$ ./configure --enable-stlink
$ make -j4
$ sudo make install

コンフィグファイルの作成

stm32f1x.cfgをベースにstm32f103c8t6.cfgを作成する。

$ cd /usr/local/share/openocd/scripts/target
$ sudo cp stm32f1x.cfg stm32f103c8t6.cfg

FLASH_SIZEに0x20000(128K)を設定する。

--- stm32f1x.cfg 2019-01-27 17:36:28.525946159 +0900
+++ stm32f103c8t6.cfg 2019-01-28 09:11:50.681348394 +0900
@@ -1,5 +1,7 @@
 # script for stm32f1x family
 
+set FLASH_SIZE 0x20000
+
 #
 # stm32 devices support both JTAG and SWD transports.
 #

イメージの書き込み

OpenOCDの起動

次のコマンドでOpenOCDを起動する。

$ openocd -f /usr/local/share/openocd/scripts/interface/stlink-v2.cfg -f /usr/local/share/openocd/scripts/target/stm32f103c8t6.cfg

telnetによる接続

シェルを新たに開いて次のコマンドを実行しOpenOCDに接続する。

$ telnet localhost 4444
> reset halt
> flash write_image erase /home/mickey/work/nuttx/nuttx/nuttx.bin 0x08000000
> reset run
> exit

書き込み結果

> flash write_image erase /home/mickey/work/nuttx/nuttx/nuttx.bin 0x08000000
auto erase enabled
device id = 0x20036410
ignoring flash probed value, using configured bank size
flash size = 128kbytes
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20000f18
wrote 68608 bytes from file /home/mickey/work/nuttx/nuttx/nuttx.bin in 3.809221s (17.589 KiB/s)

68608 bytes書き込めてることがわかる。

確実にリセットさせるために、電源となるUSBケーブルを抜いて挿し直す。

NuttShell (NSH)
nsh>
nsh>
nsh>
nsh> help
help usage:  help [-v] [<cmd>]

  [        dd       free     mb       mv       rmdir    true
  ?        echo     help     mkdir    mw       set      umount
  cat      exec     hexdump  mkrd     ps       sh       unset
  cd       exit     kill     mh       pwd      sleep    usleep
  cp       false    ls       mount    rm       test     xd

Builtin Apps:
  tee      ramtest  hello
nsh>

問題なく動作している。