🐥
ZephyrRTOSでSTM32マイコン再入門~PWMでLED制御~
はじめに
これまでWindows上にZephyrRTOSの開発環境を構築し、NucleoF103RBボードを用いて学習を進めてきた。
今回は、PWM(パルス幅変調)を使ってNucleoF103RBのLEDを明るさ制御するサンプルを作成し、PWM動作の仕組みの理解に取り組みたい。
なおNucleoF103RBのオンボードLEDを直接PWM制御することはできないため、PA8に外付けLEDを接続して制御することにする。この場合、以下デバイスツリー定義に従い、TIM1のチャネル1を用いてPWM信号を生成することになる。

コード
今回はmain.cの実装に加えて、zephyr/prj.confの編集、そしてzephyr/boards/nucleo_f103rb.overlayのデバイスツリー定義が必要である。
main.cのコード全体
main.c
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/pwm.h>
#define PWM_LED_NODE DT_ALIAS(pwm_led0)
static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(PWM_LED_NODE);
#define PERIOD_USEC (20U * 1000U)
int main(void)
{
uint32_t step = 100; // デューティ比の刻み (usec)
uint32_t delay_ms = 10; // 1ステップごとの待ち時間
uint32_t pulse = 0; // デューティ比 (usec)
bool increasing = true; // フェード方向
printk("Debug start\n");
if (!pwm_is_ready_dt(&pwm_led0)) {
printk("Error: PWM device %s is not ready\n",
pwm_led0.dev->name);
return 0;
}
while (1) {
// PWM出力設定 (周期20ms, デューティ比 pulse)
pwm_set_dt(&pwm_led0, PWM_USEC(PERIOD_USEC), PWM_USEC(pulse));
// フェード方向に応じてデューティ比を増減
if (increasing) {
pulse += step;
if (pulse >= PERIOD_USEC) {
pulse = PERIOD_USEC;
increasing = false;
}
} else {
if (pulse <= step) {
pulse = 0;
increasing = true;
} else {
pulse -= step;
}
}
k_msleep(delay_ms);
}
return 0;
}
zephyr/prj.conf
CONFIG_PWM=y
CONFIG_PWM_STM32=y
zephyr/boards/nucleo_f103rb.overlay
/ {
pwmleds {
compatible = "pwm-leds";
red_pwm_led: red_pwm_led {
pwms = <&pwm1 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
};
};
aliases {
pwm-led0 = &red_pwm_led;
};
};
デバイスツリーでのPWM設定
#define PWM_LED_NODE DT_ALIAS(pwm_led0)
static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(PWM_LED_NODE);
nucleo_f103rb.overlayで定義したpwm-led0エイリアスを用いて、PWMデバイスのノードを取得している。
メイン関数の説明
#define PERIOD_USEC (20U * 1000U)
int main(void)
{
uint32_t step = 100; // デューティ比の刻み (usec)
uint32_t delay_ms = 10; // 1ステップごとの待ち時間
uint32_t pulse = 0; // デューティ比 (usec)
bool increasing = true; // フェード方向
printk("Debug start\n");
if (!pwm_is_ready_dt(&pwm_led0)) {
printk("Error: PWM device %s is not ready\n",
pwm_led0.dev->name);
return 0;
}
while (1) {
// PWM出力設定 (周期20ms, デューティ比 pulse)
pwm_set_dt(&pwm_led0, PWM_USEC(PERIOD_USEC), PWM_USEC(pulse));
// フェード方向に応じてデューティ比を増減
if (increasing) {
pulse += step;
if (pulse >= PERIOD_USEC) {
pulse = PERIOD_USEC;
increasing = false;
}
} else {
if (pulse <= step) {
pulse = 0;
increasing = true;
} else {
pulse -= step;
}
}
k_msleep(delay_ms);
}
return 0;
}
main関数では、PWMのデューティ比を徐々に増減させることでLEDの明るさを変化させている。
pwm_set_dt関数を用いて、周期20ms、デューティ比pulse(マイクロ秒単位)でPWM信号を出力している。
inclreasingフラグに基づいてデューティ比を増減させ、k_msleep関数で各ステップ間に10msの遅延を挟んでいる。
おわりに
以上でZephyrRTOSを用いたSTM32マイコンのPWMによるLED制御の解説を終わる。
今回はPWMでLEDを制御したがサーボモータ制御などにも応用できるため、今後試す予定である。
Discussion