0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【チュートリアル】mruby/c ver4 をSTM32マイコンで動かす Chapter3: ハードウェアタイマーの使用

0
Last updated at Posted at 2026-09-01

島根県産業技術センター の東です。

mruby/c ver4 をSTM32マイコンで動かす記事 、今回はその第3回、ハードウェアタイマーを使うよう設定を追加します。

目標

ハードウェアタイマーを使って sleep の時間を正確にするとともに、sleep 中は CPUを止めて消費電力の削減をはかる。

ビルドシステムの調整

まず、前回 mruby/c のプログラムを書き換えるたびに、コマンドプロンプト画面で mrbc.exe を動かす必要があった作業を自動化します。

CubeIDE 内部では、gnu make が動いているので、これを利用して .rb ファイルが更新された時だけ .c ファイルも更新するという動作をさせます。

手順

左ペイン Project Explorer 上、mrubyc の上で右クリックし、New > File を選びます。

20260901190401.png

Create New File ダイアログで、File name 欄へ、makefile と入力し、[Finish] をクリックし、ファイルを作ります。

20260901185847.png

Makefile ができますので、以下の内容を入力し保存します。
最終行の前空白(インデント)は、スペースではなく TABですので気をつけて入力します。

Core/mrubyc/makefile
MRBC = cmd /C mrbc.exe
RBSRCS = $(wildcard *.rb)
CSRCS = $(RBSRCS:.rb=.c)

.PHONY : all
all: $(CSRCS)

%.c : %.rb
	$(MRBC) -B$(@:.c=) $^

次にこのファイルを使う設定をします。

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

20260901191525.png

  • ダイアログ左ペインの C/C++ Build > Settings をクリックし、右ペインの Build Steps タブをクリックします
  • Pre-build steps の Command: 欄へ、以下の通り入力します
cd ..\\Core\\mrubyc; make

これで、ビルド時に mruby/c ファイルの自動コンパイルも行ってくれるようになりました。

ハードウェアタイマーを使う

前回は、sleep の時間が指定した時間よりもかなり長くスリープしていました。これは、スケジューラが正確に計時する方法が無いからです。これをハードウェアタイマーを使って解決します。

以下の手順で行います。

  1. 前回行った タイマー未使用の宣言を取り下げる
  2. SysTick タイマーで、mrbc_tick() をコールする
  3. hal.h へ割り込み許可/禁止を定義

今回ターゲットにしているマイコン STM32F401 は、ARM Cortex-M4 CPUコアを搭載しており、CPUコア自体にSysTickという簡単なハードウェアタイマーを内蔵しています。
ST製 HAL ライブラリの仕様を調査すると、SysTickタイマーを使って 1ms サイクルで割り込みをかける用途に使っており、割り込みハンドラはユーザにも開放されています。別途ペリファラルのタイマーを使用する方法もありますが、有限のリソースをスケジューラが使用してしまうのはもったいないので、ここでは HALライブラリの SysTick タイマーに同居する方法を採用しました。

1. 前回行った タイマー未使用の宣言を取り下げる

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

20260817094527.png

  • ダイアログ左ペインの C/C++ General > Paths and Symbols をクリックします
  • 右ペインの Symbols タブをクリックします
  • Languages 欄で GNU C が選ばれていることを確認します
  • 前回追加したシンボル MRBC_NO_TIMER をクリックして選択状態にしてから、[Delete] ボタンをクリックして消去します
  • [Apply and Close] ボタンでダイアログをクローズします

2. SysTick タイマーで、mrbc_tick() をコールする

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

20260817095348.png

右ペインに表示された C言語ソースコードから、
/* USER CODE BEGIN SysTick_IRQn 0 */
の箇所を探し、その下に以下のコードを追記します。

Core/Src/stm32f4xx_it.c
  /* USER CODE BEGIN SysTick_IRQn 0 */
  void mrbc_tick(void);
  mrbc_tick();
  /* USER CODE END SysTick_IRQn 0 */

この箇所は、SysTick_Handler関数の中で、1msごとに割り込み処理によってコールされます。
mruby/c スケジューラがタイマー割り込みによって必要としている処理は、mrbc_tick() をコールすることだけです。

3. hal.h へ割り込み許可/禁止を定義

前回は、割り込みを使用しない前提でしたので、ほとんどのマクロを無効化していました。今回は必要な箇所をきちんと記述します。

左ペイン Project Explorer の画面から、Core > mrubyc_src とたどり、hal.h をダブルクリックして開きます。

ファイルの内容を、以下の通り書き換えます。

Core/mrubyc_src/hal.h
#ifndef MRBC_SRC_HAL_H_
#define MRBC_SRC_HAL_H_

#include "main.h"

#define MRBC_TICK_UNIT 1
#define MRBC_TIMESLICE_TICK_COUNT 10

#define mrbc_hal_init()        ((void)0)
#define mrbc_hal_enable_irq()  __enable_irq()
#define mrbc_hal_disable_irq() __disable_irq()
#define mrbc_hal_idle_cpu()    ((void)0)

int mrbc_hal_write(int fd, const void *buf, int nbytes);
int mrbc_hal_flush(int fd);
void mrbc_hal_abort(const char *s);

#endif

変更点は、mrbc_hal_enable_irq, mrbc_hal_disable_irq の実体を記述した事と、NO_TIMER用に仮に設定していた mrbc_hal_idle_cpu を無効化した点です。
割り込みの enable/disable は、TickTimer の割り込みだけを有効化/無効化でも良いですが、より汎用的に(簡易に)使う事ができる方法を選定しています。

一通り終わりましたら、ビルドしてターゲットへ書き込みます。

ほぼ正確な秒数で、sleep するようになります。
(以下のデモは、Rubyのプログラムを、1秒ごとの sleep に戻しています)

Core/mrubyc/task1.rb
while true
  led_write( 1 )
  sleep 1
  led_write( 0 )
  sleep 1
end

20260817_movie_1.png

プログラムの sleep 時には CPU も sleep させる

この Ruby プログラムでは、ほとんど sleep の待ち時間が占めており、その間 CPU は何もしていないことになります。このような場合、使用電力の削減を狙って、マイコンを低消費電力モードにするのが良案です。
Cortex-M4 にも低消費電力モードがあります。マニュアルによると、いくつかのモードが用意されていますが、

  • SysTick タイマーでウェイクアップが必要
  • 周辺デバイスの動作維持
  • メモリ(RAM)内容の維持

といった条件を満たす必要があり、それを満たすモードに入るには、以下のようにすれば良いことが分かります。

HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI)

この関数を、hal.h の mrbc_hal_idle_cpu() マクロに設定します。

Core/mrubyc_src/hal.h
#ifndef MRBC_SRC_HAL_H_
#define MRBC_SRC_HAL_H_

#include "main.h"

#define MRBC_TICK_UNIT 1
#define MRBC_TIMESLICE_TICK_COUNT 10

#define mrbc_hal_init()        ((void)0)
#define mrbc_hal_enable_irq()  __enable_irq()
#define mrbc_hal_disable_irq() __disable_irq()
#define mrbc_hal_idle_cpu()    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI)

int mrbc_hal_write(int fd, const void *buf, int nbytes);
int mrbc_hal_flush(int fd);
void mrbc_hal_abort(const char *s);

#endif

これで、ビルドしてターゲットへ書き込みます。
書き込みが終わったタイミング(= 実行が始まったタイミング)で、CubeIDE がターゲットに接続できないエラーを表示しますが、これは CPUがきちんとスリープモードに入っている証拠ですので問題ありません。

このボードは、CPUに流れる電流を、JP6に電流計を接続することによって測定することができますので、シャント抵抗とオシロスコープを使って観測してみます。

スリープモードにしない場合 スリープモードにする場合
20260817_scope_1.png 20260817_scope_2.png
約15mA 約6mA

測定結果の値が高い部分はLEDの電流を含んでいるので、低い部分を比較すると、約15mAから6mAと、半分以下の電流に低減できていることがわかります。

おまけ - オシレータを内蔵から外部へ変更

ここからはおまけですので、実施しなくても続けられます。

CubeIDE で自動生成したコードは、デフォルトのクロックソースに内蔵RCオシレータを使うよう設定されます。メーカーによると内蔵RCオシレータは、工場出荷時に25℃の条件下にて±1%の誤差内に調整されています。しかしながら、AN5067 で述べられるとおり、実装条件や周囲温度によって影響をうけ、正確さはそれほど期待できません。

Nucleo-F401RE ボードの回路図を見ると、ST-Link プログラマ側にあるマイコンチップは、8MHz の水晶がクロックソースになっており、さらにその出力は、メイン側の STM32F401RE に接続されているようです。こういった使い方は、恐らく保証対象外だとは思いますが、メーカー製のボードですし、試しに使用する設定にしてみると確かに動きます。

方法

  • CubeIDEを一旦終了します
  • エクスプローラでプロジェクトのフォルダを開き、mrubyc_v4.ioc をダブルクリックして CubeMX を開きます

20260825105148.png

参考
CubeIDEとCubeMXは連携するように作られているので、CubeIDEの左ペインにある mrubyc_v4.ioc をダブルクリックして CubeMX を起動する方法もあります。
しかし私がこのバージョンの組合せで試す限り、意図通り動作しない事が多く発生したので、全く別々のツールとして操作するほうが安全のようです。

CubeMXが起動したら、以下の設定を行います。

20260817114238.png

  • Clock Configuration をクリックし、クロック設定画面を開きます
  • 左、中程の Input frequency 欄が、8 (MHz) になっていることを確認します
  • PLL Source Mux セレクタを HSI から HSE に変更します
  • HCLK (MHz) 欄に、84 を入力します
  • 画像の通り、各プリスケーラやPLLの逓倍率が変更されたことを確認します
  • 右上の GENERATE CODE ボタンをクリックします

ちなみに、初期値(内蔵RC使用時)は以下の通り。
20260817114018.png

効果

効果はてきめんです。

SysTick実測値(kHz) 誤差 (%)
内蔵 RC 1.0176 1.76
外部 クリスタル 1.0000 0.00

測定は、いま手元に周波数カウンタが無いので、オシロスコープ (キーサイト DSOX2002A)で簡易的に測定しました。ですが、時間(およびその逆数の周波数)は、身近な物理量のなかで最も有効桁数を確保しやすい物理量なので、十分信頼できる値と言えます。

ダウンロード

ファイル全体は、以下のリンクからダウンロード出来ます。

おわりに

今回は、ハードウェアタイマーを使うことを目標に、mruby/c の hal を整備しました。
次回は halの残り(コンソール関係)の整備をしていきます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?