ZephyrRTOSでSTM32マイコン再入門~Blinkyで学ぶGPIO出力~
はじめに
前回の記事ではWindowsのVSCode+PlatformIOにZephyr RTOSの環境を構築し、NucleoF103RBボードでサンプルのBlinkyをビルドして動作するところまで確認した。
今回は「とりあえず点滅した」から一歩進んで、ZephyrがどのようにGPIOを扱っているのかを掘り下げていく。
Blinkyのコード
Zephyrのサンプルに含まれるmain.cは以下の通り。
main.cのコード全体
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
/* 1000 msec = 1 sec */
#define SLEEP_TIME_MS 1000
/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)
/*
* A build error on this line means your board is unsupported.
* See the sample documentation for information on how to fix this.
*/
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
int main(void)
{
int ret;
bool led_state = true;
if (!gpio_is_ready_dt(&led)) {
return 0;
}
ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return 0;
}
while (1) {
ret = gpio_pin_toggle_dt(&led);
if (ret < 0) {
return 0;
}
led_state = !led_state;
printf("LED state: %s\n", led_state ? "ON" : "OFF");
k_msleep(SLEEP_TIME_MS);
}
return 0;
}
Zephyr特有の箇所について調べたことをまとめる。
デバイスツリーとエイリアス
/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)
Zephyrではハードウェアのピンや周辺機能をデバイスツリー (DTS)で定義している。
Blinkyサンプルではled0というエイリアスが用意されており、基板上のLEDにマッピングされている。
DT_ALIASでled0という名称のエイリアスから基板上のLEDのGPIO設定のノードを取得している。
これにより、アプリコード側は「どのポートの何番ピンか」を意識せずに 抽象化された名前 (led0) を使えるようになっている。
GPIO設定の取得
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
ここでデバイスツリーから実際のGPIO設定を取得している。
GPIO_DT_SPEC_GETにはノードID, そのノードのプロパティ名を渡す。
< &gpioa 0x5 0x0 >はGPIOAポートの5番ピンをプルなしのハイアクティブで使う設定を意味する。
gpio_dt_specは<zephyr/drivers/gpio.h>で以下のように定義されている。
GPIOの初期化確認
if (!gpio_is_ready_dt(&led)) {
return 0;
}
GPIOが使える状態になっているかを判定している。
- デバイスツリーで有効化されているか(status = "okay";)
- デバイスドライバが初期化済みか(DEVICE_DT_GET() で ready になっているか)
STM32ドライバの場合は起動時に以下処理が自動で実行されている。
- RCCで該当ポートへのクロックを有効化
- レジスタベースアドレスをセット
- "ready"状態に遷移
ピンの設定
ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return 0;
}
アプリケーション側で「このピンをどう使うか」を指定している。
第2引数で初期状態を定義する。
GPIO出力のトグル制御
ret = gpio_pin_toggle_dt(&led);
if (ret < 0) {
return 0;
}
この関数でGPIOの状態を反転させている。
内部の処理を見ていくと以下のようにZephyrのGPIO APIを使っていることがわかる。
GPIOのAPIは他に以下の処理が関数ポインタとして定義されている。
STM32向けのドライバの中でAPIの関数ポインタと実処理とを対応付けしている。
おわりに
今回はZephyrでのGPIO出力の仕組みについてBlinkyサンプルを通じて学んだ。
- デバイスツリーでGPIO端子の設定を定義。
- アプリのコードではGPIO端子の設定を取得し、APIを使って出力制御を行う。
引き続きサンプルコードを読み進めながらZephyrの仕組みを学び、ペリフェラルの使用方法をまとめていきたい。
Discussion