何だかんだこのシリーズも6個目ですねw
前回まででUARTの基本的な使い方はマスターしたと思います。
今回はCubeMXでの出力は詳しくは解説しないので
まだの方は1から読んでみてください
gsmcustomeffects.hatenablog.com
gsmcustomeffects.hatenablog.com
gsmcustomeffects.hatenablog.com
gsmcustomeffects.hatenablog.com
gsmcustomeffects.hatenablog.com
さっそくやってく
今回の環境は以下に示す通り
- AC6 SystemWorkbenchForSTM32
- STM32F303K Nucleo
- Teraterm
とりあえずCubeでUART2を有効にしてボーレートを各自設定しファイルを出力する。
ココまでは今までと同じです。
Syscall.cを持ってくる
syscall.cがCにおけるスタンダードライブラリを読んでいるのでそれをどっかからもってこないとリンクできないわけです。
とりあえずSTが提供するサンプルには入っているのですがCubeMXが出力するsrcフォルダには入っていません。
なのでAc6で適当な空プロジェクトを作る必要があります。
めんどかったらSTが提供するサンプルから引っ張ってくるという方法もあります。
で今回使うボードを選択
CubeHALを選択
そうするとsyscall.cができるのでそれをCubeMXが出力したSrcにコピーしてくる
んで一度コンパイルします。
Main.cでputcharを再定義。
syscall.c内では
__io_putchar(int ch) __attribute__((weak))
のようにWEAK定義されているのでMain内で再定義してこっちを使うよということをコンパイラに教えてあげる作業をします
こういうふうにします。
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
void __io_putchar(uint8_t ch) {
HAL_UART_Transmit(&huart2, &ch, 1, 1);
}
printfというのは内部で書式を整えてputcharを呼び出しているのでそのputcharの内部をHALの一文字送信APIに置き換えるということです。
コンパイルマクロがGNUとかついてるのはARMの純正コンパイラではfputcと定義されてるのでコンパイラごとに読み替えが効くようにしているためです。
次にprintfを呼ぶ前にどこか最初以下の行を挿入します
setbuf(stdout, NULL);
これはprintfの仕様みたいで1024byte入れた後に呼ばれるのでコレがないと変なハンドラに飛びます。
とりあえずバッファをフラッシュするといいみたいです。
ここまででとりあえずint型のprintfは動きます。
だいたい15KBぐらいになります。
Linkerフラグの編集
リンカーオプションにfloatを追加して再ビルドする必要があります。
やることとしてはlinkerのフラグ部分に-u _printf_floatというのを追加するだけです。
それであとはApplyして再ビルドします。
結構サイズがでかくなります。
いうてGCCならKEILと違って32KB以上もビルドできるしFloat扱うようなマイコンはフラッシュ自体大きい物がのってるので特に悩まないかと思います。