STM32F4を弄る(6) xprintfを使用したPCとのUSB VCP UART通信

STM32
スポンサーリンク

こん○○は、よふかしわーくすの、よふかしさんです
6回目はBlack Pillと呼ばれるWeAct製かそれ系のSTM32F411を使って
Cube環境でPCとのシリアル通信をxprintfを使用してやってみます

特に今回はSTM32F411に搭載されているUSB機能と、
Black Pillに搭載されているUSB Type-Cポートを使用、それ以外のデバイスを使用しないで
VCP(Virtual COM Port)で通信してみたいと思います

今回使用している開発環境は、
CubeMX:Version 6.13.0
CubeIDE:Version 1.17.0
で解説していきます

スポンサーリンク

xprintfとは?

xprintfとは何ぞや?は、製作者であるChanさんの公式ページに記載があります

xprintfは組み込み用に特化したコンパクトなprintfとサポート関数群です。標準入出力関数のサポートされない組み込みシステムにおいて、既存の入出力デバイス(UARTやLCD)に結合することにより、それらに対してprintfで簡単に整形文字列を出力することができます。このため、LCDやUARTなどに手軽に整形出力したいときや、デバッグ・メンテナンス・コンソールなどに有効です。

xprintfは構成オプション(xprintf.h内に定義)で必要な機能のみ組み込むことでモジュールサイズを削減することができます。例としてCortex-M3でのコンパイル結果を次の表に示します。(gcc -Os) なお、long longと浮動小数点は、C99を必要とします。

要は、

  • PCだとprintfでコンソール画面に表示させられる
  • 組み込みの場合は接続ディスプレイへの表示や、デバッグ用途でPC等の何らか表示させられる機器に通信で出したいよね?
  • じゃあそれを実現しましょ

的な感じ

xprintfをDownloadする

Chanさんのトップページにアクセス

おまけのソフトウェア、をクリック
(全然おまけじゃない…)

組み込み用printfモジュール、をクリック

下までスクロールすると、ダウンロードの項目があるので
組み込み用printfモジュールをクリックしてダウンロード

そうすると、xprintf.zipがダウンロードされます

xprintfを組み込む

xprintf.zipを解凍すると、srcフォルダ内に

  • xprintf.c
  • xprintf.h

があります
STM32 Projectフォルダ→Core→Src、にxprintf.cを
STM32 Projectフォルダ→Core→Inc、にxprintf.hを
配置します
こんな感じ

main.cにインクルード宣言を追加

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "usbd_cdc_if.h"
#include "xprintf.h"

/* USER CODE END Includes */

main.cに下記のオリジナル関数を追加

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

void usb_putc(char c)
{
    while(CDC_Transmit_FS((uint8_t*)&c, 1) != USBD_OK)  // USB VCPを使って1文字送信
    {
    	// 何もしない
    }
}

/* USER CODE END 0 */

main.cのループ処理にxprintfでの送信処理を追加

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	xprintf("USB VCP Tx\n");
	HAL_Delay(500);
  }
  /* USER CODE END 3 */

解説

公式ページでは下記の記述があります

入出力デバイスとの結合

UARTやLCDなどの出力デバイスに結合するには、デフォルト出力デバイスとしてモジュールのグローバル変数xfunc_outputに、そのデバイスの1文字出力関数へのポインタを代入するだけでOKです。これにより、xputc/xputs/xprintf/put_dump関数の出力は指定された関数に渡されます。xfputc/xfputs/xfprintf/xsprintf関数の出力先は、それぞれの引数で直接指定されます。この設定のためマクロも用意されているので、例えば、void uart1_putc (uint8_t chr);に結合する場合、xdev_out(uart1_putc);とすればOKです。出力関数が複数の引数をとる場合や単純な1文字出力が無い場合は、グルー関数を間にかませる必要があるかも知れません。

UARTなどの入力デバイスに結合するには、デフォルト入力デバイスとしてモジュールのグローバル変数xfunc_inputに、そのデバイスの1文字読み出し関数へのポインタを代入するだけでOKです。(設定マクロを使用した例:xdev_in(uart1_getc);) xgets関数はデフォルト入力デバイスからライン入力を行います。xfgets関数は入力関数を引数で直接指定します。読みだされた文字は、順にバッファにストアされます。’\r’、’\b’以外の制御文字は無視されます。’\r’が読み出されると読み出しを終了してxgets関数は1を返します。’\r’はバッファにはストアされず、文字列は’\0’で終端されます。通常、入力があるまで読み出し関数は制御を返しませんが、入力デバイスはコンソールに限られるわけではない(ファイルに結合した例もあります)ので、入力ストリームの終端が明確なときは-1を返すべきです。これにより、xgets関数は中断して0を返すので、アプリケーションがストリーム終端を知ることが可能になります。

ということで、USB VCPでの1文字送信関数、usb_putcをオリジナルで作成し、
xdev_out関数に渡しています

TeraTermを起動して、受信の改行コードをLFに変更
下記の様に受信できていれば成功です

終わりに

PCへのUSB VCPでのシリアル送信をxprintfで実装した事例を紹介しました
次回は実装系ではなく、Config等のTipsを書いておきたいと思います

公開日時:2024/12/26 4:44:59

コメント

タイトルとURLをコピーしました