【チュートリアル】mruby/cをSTM32マイコンで動かす Chapter04: halの仕上げ

[しまねソフト研究開発センター](https://www.s-itoc.jp)（略称 ITOC）にいます、東です。

[mruby/cをSTマイクロエレクトロニクス社製の32bitマイコンSTM32で動かす記事](https://qiita.com/HirohitoHigashi/items/7ef01d074baa27a3b2e7)、
今回はその第4回、mruby/c のhalを仕上げます。


# 目標

mruby/c のプログラムで、puts や、printf を使えるようにする。


# 作業手順

## デバイスの確認

プロジェクトを作成する段階で、ペリフェラルをデフォルト値で初期化を選んでいますので、UART2 を使う設定で初期化コードも自動生成されています。確認してみましょう。

左ペイン Project Explorer から、`（プロジェクト名）.ioc` （ここでは、`tuto01.ioc`） をダブルクリックし、コンフィグレーション画面を開きます。

Categories > Connectivity > USART2 [^1] にチェックが入っていることを確認し、そこをクリックします。
![STM32Tuto04-スクリーンショット 2024-05-30 12.02.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504019/0c120398-0616-05e7-b756-c12650e16e32.png)

画面表示より、以下の設定になっていることを確認します。

* Mode Asynchronous
* Hardware Flow Control : Disable
* Baud Rate : 115200
* Word Length : 8 Bits
* Parity : None
* Stop Bits : 1
* Data Direction : Receive And Transmit
* ICチップ表示の左下、USART_TX = PA2 と USART_RX = PA3 がアサインされている

実際に PA2とPA3がどこにつながっているか、ユーザーマニュアル(UM1724) で確認すると、デフォルトでST-LINK 基板を通じて USB の Virtual COM port として使えると記述があります。

[^1]: 画面上は USART と表示がされていますが、ここでは UART と同じものです。記事では、UARTで統一します。


## コンソール出力先を準備

Windowsでは TeraTerm を使うのが定番になっていますので、ここでもそれを使う前提で説明します。

TeraTerm を起動し、接続先でシリアルを選んだのち、ポートを、「STMicroelectronics STLink ...」　を選びます。
![STM32Tuto04-スクリーンショット 2024-05-29 16.35.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504019/003ccf7d-17ee-3df9-130b-f4672ba1ffe9.png)

メニューから、設定 > シリアルポート　を選ぶと以下のダイアログが表示されますので、先ほど CubeIDEで確認したパラメータに合わせて設定します。
![STM32Tuto04-スクリーンショット 2024-05-29 16.36.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504019/2e866eed-dcda-dec7-4605-47cbb5722b0b.png)

メニューから、設定 > 端末 を選ぶと以下のダイアログが表示されますので、以下の通りに設定します。
![STM32Tuto04-スクリーンショット 2024-05-29 16.37.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504019/5058a7e3-5011-56f8-2a3b-c1889394448a.png)

## hal関数へ、UART2を使うよう追記

空の関数で作っておいた、hal_write で、UART2 を使うように追記します。

左ペイン Project Explorer から、Core > mrubyc とたどり、start_mrubyc.c をダブルクリックして開きます。

空だった hal_write 関数を、以下の通り書き換えます。

```c:Core/mrubyc/start_mrubyc.c
/*! HAL
*/
int hal_write(int fd, const void *buf, int nbytes)
{
  extern UART_HandleTypeDef huart2;
  HAL_UART_Transmit( &huart2, buf, nbytes, HAL_MAX_DELAY );

  return nbytes;
}
```

また、libc の標準出力が使えると便利な場合があるかもしれないので、hal_write 関数の下に、以下の _write 関数も定義しておくと良いです。

```c:Core/mrubyc/start_mrubyc.c
int _write(int file, char *ptr, int len)
{
  return hal_write(file, ptr, len);
}
```

---
**（参考）**
残りのhal関数、hal_flush() と　hal_abort() は、今後のバージョンで使う予定にしており、現段階では積極的に使っていませんので、空のままで大丈夫です。


## mruby/c プログラムの書き換え

では、puts が使えるようになったか確認するために、mruby/c プログラム側も puts を使うよう書き換えます。

左ペイン Project Explorer から、Core > mrubyc とたどり、task1.rb をダブルクリックして開きます。

以下のように、書き換えます。

```ruby:Core/mrubyc/task1.rb
10.times {|i|
  puts "Hello, mruby/c #{i}"
  sleep 1
}
```

## 実行

メニューから、Run > Run を選んでターゲットへ書き込みます。

![STM32Tuto04-Demo1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504019/b4877057-fd5e-801d-50be-468aa66461e7.gif)

正常に、文字列 "Hello, mruby/c" とカウントアップする数字とが10行ほど表示されたでしょうか。

mruby/c の標準出力だけではなく、例外発生時の出力も表示されるようになるので、例えば以下の通り存在しない関数をコールした場合、

```ruby:Core/mrubyc/task1.rb
not_exist_func()
```

TeraTerm には、その旨が表示されるようになります。

```
Exception(vm_id=1): undefined local variable or method 'not_exist_func' for Object (NoMethodError)
```


# 浮動小数点値の表示

task1.rb を、次のように書き換えて実行してみます。

```ruby:Core/mrubyc/task1.rb
printf "ABC %d %d\n", 12, 34
printf "PI=%.2f\n", 3.141592
```

すると、以下の通り整数は表示されますが、浮動小数点は表示されません。

```
ABC 12 34
PI=
```

STM32の開発環境は、デフォルトで浮動小数点の表示サポートをOFFにしてあるためですので変更します。

メニューから、Project > Properties を選び、ダイアログを開きます。

ダイアログ左ペインの C/C++ Build > Settings をクリックします。

右ペインの　Tool Settings タブをクリックし、MCU Settings をクリックします。

Use float with printf from newlib-nano 欄のチェックをつけます。

![STM32Tuto04-スクリーンショット 2024-05-29 16.56.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504019/001debfd-a08a-249f-8422-b6e888dfcbb0.png)

再度ビルド、書き込みをすると、今度は表示されるようになります。

```
ABC 12 34
PI=3.14
```


# おまけ - IDE内にシリアル出力を表示

いつの間にか Eclipse （だと思う） が、シリアル出力のウインドウ内表示をサポートしていました。ただし、改行コードの指定など全くできないようなので、今回の mruby/c での実験では使いづらく、ここではやり方の紹介にとどめます。

## 方法

Console ペイン右端にあるアイコンから、以下の画像を参考に、Open Console アイコンをクリックし、開いたメニューから Command Shell Console を選びます。
![STM32Tuto04-スクリーンショット 2024-05-29 16.17.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504019/1dddce2e-521d-8dc4-ccd7-639fe912de79.png)

Select Remote Connection ダイアログが開くので、Connection Type 欄で Serial Port を選んでから、[New] ボタンをクリックします。
![STM32Tuto04-スクリーンショット 2024-05-29 16.18.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504019/2c235b9a-143b-c02f-4294-9e00c1e01a60.png)

New Serial Port Connection ダイアログが開くので、以下の図を参考にパラメータを設定します。
![STM32Tuto04-スクリーンショット 2024-05-29 16.19.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504019/89166217-eb82-db14-a1d4-94301474223f.png)

これで、IDE画面内に、シリアル出力の表示ペインができます。


# おわりに

ファイル全体は、github リポジトリにありますので、そちらをご覧ください。

https://github.com/HirohitoHigashi/mrubyc-tuto-stm32/tree/chapter04

今回は、hal のコンソール出力をサポートしました。
これで、mruby/c 側で何か意図しないことが発生したときに手がかりを表示させることができるようになったので、開発段階では非常に有用かと思います。
次回は、GPIOの拡張と、複数プログラムの動作を行います。