printfでデバッグ(Semihosting, UART, ITM console)

MCUXpresso でデバッグするときにprintfを使うにも種類が色々あるっていう話です。

PRINTFとprintf

SDKプロジェクトを作成すると、大文字と小文字のprintfが存在します。PRINTFは元々のCライブラリのprintfをSDKのライブラリがオーバーライドしたもので、プロジェクト作成時の設定によって、下のように色々動作がかわります。

SemihostingでPRINTF

MCUXpressoでSDKプロジェクトを作成すると、初期の設定で、semihosting printfというモードをオンにできます。こうすると、PRINTFがUARTではなく、デバッガ経由で信号が送られることになります。

下のように、MCUXpresso上のConsole画面で簡単に信号チェックできるので、便利さでいうと、一番です。下は、Hello worldをPRINTFした時の例です。

PRINTF(“Hello World\n”);

ただ、この方法は、PRINTFの実行のたびに、マイコンの処理が中断されるので、プログラムの実行速度がかなり悪化します。リアルタイム性が重要なアプリなどをデバッグするのは難しいかと。

あと、いったんsemihostingでprintfするとデバッガーなしでは、処理が止まってしまうので、スタンドアロンで動かせなくなってしまいます。

Semihostingの設定

プロジェクト作成ウィザードで設定することができ、Debug ConsoleをSemihostにチェックをいれます。

Redirect SDK “PRINTF” to C library “printf”にチェックをいれます。

設定はこれだけです。

UARTでPRINTF

次は、文字通り、UART経由でPRINTFを使う方法です。下のようにTera termなどのターミナルソフトを使って、信号を確認できます。あくまで中身はUARTですので、semihostingと違い、特にデバッガがなくても、プログラムは止まりません。一番よくつかわれますかね。

UARTの設定は、下のようにします。

Redirect printf/scanf to UARTにチェックいれときます。

下が実際に出力した結果です。

PRINTF(“Hello World\n”);

デバッグ用のUARTはデフォルトでUART0になっています。多くのkinetisマイコンの場合、UART0は評価ボードに実装されているUSBコントローラで、USBシリアル変換されているため、USBケーブルを接続したまま、特に何もせずにteratermなどのターミナルソフトで信号を確認することができます。

PRINTFで使うUARTを指定する

ただ、オリジナル基板やシリアルUSB変換ICが実装されていないUARTを使って、printfデバッグを使用したいよっていう場合もあります。

その場合は、プログラムのboard.h内にある下のBOARD_DEBUG_UART_BASEADDRとBOARD_DEBUG_UART_INSTANCEを変更します。そのほか、ボーレートなどもここで変えられます。

/* The board name */
#define BOARD_NAME "FRDM-K64F"

/* The UART to use for debug messages. */
#define BOARD_DEBUG_UART_TYPE     kSerialPort_Uart
#define BOARD_DEBUG_UART_BASEADDR (uint32_t) UART1 //UART0から変更! 
#define BOARD_DEBUG_UART_INSTANCE 1U //0から変更 
#define BOARD_DEBUG_UART_CLKSRC   SYS_CLK
#define BOARD_DEBUG_UART_CLK_FREQ CLOCK_GetCoreSysClkFreq()
#define BOARD_UART_IRQ            UART0_RX_TX_IRQn
#define BOARD_UART_IRQ_HANDLER    UART0_RX_TX_IRQHandler

#ifndef BOARD_DEBUG_UART_BAUDRATE
#define BOARD_DEBUG_UART_BAUDRATE 115200
#endif /* BOARD_DEBUG_UART_BAUDRATE */

当然、モニタには、レベル変換用のICを内蔵したケーブルが必要です。

DTech製のUSBシリアル変換コネクタとつなげる(クロスするのを忘れずに!RXとTXだけでOK)

Tera Termで同じようにハロハロした結果が下です。

PRINTF(“Hello World\n”);

ITM-CONSOLE

これは、ARMのデバッグインターフェースSWO( serial wire output )を利用して、PRINTFをするパターンです。ITM-CONSOLEは、このSWOを使い、ターゲットの処理への影響を減らし、PRINTFデバッグを実現することができます。

下はFRDM-K64FとPEmicroのデバッガをSWOを介して、接続したときの写真です。今回はこの構成でテストしてみました。

ITMコンソールを使用するには、プロジェクト作成時のウィザードで以下のようにします。Debug ConsoleでUARTを選択します。

次にRedirect printf/scanf to ITMにチェックをいれます。

ITM ConsoleはMCUXpressoのメニューバーからAnalysis -> SWO ITM Consoleから表示できます。

ITM Consoleを有効化するには、一旦プログラムをデバッグモードで中断した状態で、ITM Console画面から下のアイコンをクリックします。

Clock speedの横にあるChangeボタンをクリックします。

テキストボックスにシステムクロックを設定します。サンプルコードは、120MHzなのでそのとおり、値を入力します。

ちなみに、PEMicroのマルチリンクではクロックスピードは自動検出されると書かれていましたが、動作が不安定だったので、上のように直接値を設定しておいたほうが無難です。

クロックを設定後は、以下の再生ボタンをクリックして、コンソールを開始できます。

Semihost vs ITM console

実際にPRINTFがターゲットの実行速度にどの程度影響をあたえるかみてみました。下は、テスト用のメインループのコードです。1msec間隔で”Hello World”を出力します。

    while(1) {
        PRINTF("Hello World\n"); //PRINTF
        GPIO_PortToggle(GPIOC, 1U<<16); //デジタル出力High/Low切り替え
        Delay(1);//1ms待機
    }

オシロでデジタル信号を測定して、SemihostとITMで、どの程度信号が遅れるかを確認しました。

Semihostの結果が下。

1ms間隔が20ms間隔になりました。PRINTFで、かなり実行速度を落としていることがわかります。

ITM Consoleの場合が下。

信号周期はほぼ1msで、遅れはほとんど発生していないことが分かります。

両者の差は明らかでした。PRINTFを使いたいなら、可能な限り、ITMconsoleを利用していったほうがいいんですね。なるほど。

今回は短いですが、以上です。

PRINTFにもいろいろありましたがITMコンソール🙌ってことですね。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です