概要
IoT機器関連のデモ開発を進めるにあたり、開発用ボードには、CPUやメモリーのリソースがある程度あり、EthernetやmicroSDなどの周辺機器が最初から搭載されているSTM32H757I-EVALを、RTOS (Real Time OS)には、開発の容易さとミドルウェアの充実度からZephyrを選定しました。
Zephyrについては、選定の過程でZephyrのボード サポートページでmicroSD対応状況を確認したところ、SDMMCと記載があるので特に問題なくmicroSDが使用できると思っていました。
ところが、SDMMCの記載はあるものの、これを調査した段階(2026年1月頃のコード)では、microSDは使用できる状態ではないことが判明しました。このため、ボードの仕様やコードの調査、修正を行うなどmicroSDを使用可能な状態にするために試行錯誤し、最終的になんとか動作を確認することができました。
注意:著者自身はRTOSやハードに近いドライバーなどのポーティングには疎いので、間違っていたり、最良の方法ではなかったりする可能性があります。
Zephyrとは
Zephyrは、OSSとして開発されている、主にIoT機器などをターゲットにしたマイコンや省リソースデバイスで動作するRTOSです。
STM32H757I-EVALとは
STM32H757I-EVALボードは、ST Microelectronicsが開発するSTM32のH7シリーズの開発用の評価ボードです。
比較的リッチなスペックのボードで、Ethernet、USB OTG、microSD、LCDなどを搭載しています。
ドキュメント
ボードのドキュメントは、ここにまとまっています。
(STへ登録とログインの必要があります)
- 開発ボードについてはUM2525を参照してください
- 開発ボードの接続図についてはMB1246-H757-E03 Board Schematicを参照してください
- 搭載されているSTM32H757についてRM0399を参照してください (本記事では必要ありません)
Zephyr on STM32H757I-EVAL
ZephyrはSTM32H757I-EVALボードをサポートしており、公式サイトにも専用ページが用意されています。
概要にも記しましたが、その専用ページの「Supported Features」にZephyrの対応機能としてSDMMCの記載があるのでmicroSDが直ぐに使用できると思ったのですが、調査を行った2026年1月時点ではそのような状態にありませんでした。
ビルド環境
セットアップ
公式のドキュメントのGetting Started Guideの通りに進め、セットアップを完了してください。
ビルドは上記のZephyr環境で導入されるwestコマンドで行い、デバッグにはST公式のSTM32CubeIDEをデバッグのみで使用するように設定しました。
対象サンプル
今回はsamples\subsys\fs\fs_sampleを使用してmicroSDの動作を確認しました。
ビルドコマンド
west build -p always -b stm32h757i_eval/stm32h757xx/m7 samples\subsys\fs\fs_sample
-
-p always
毎回付ける必要はないのですが、dtsファイルやconfファイルなどを編集した際に必要となりますので、ここではつけた例を表示しています -
-b stm32h757i_eval/stm32h757xx/m7
対象ボード名と細かいCPUの指定をします。このチップにはARMのm7とm4を積んでるのでその指定をしています。詳細はZephyrのボードのページで確認できます -
samples\subsys\fs\fs_sample
ビルドディレクトリからの相対パスです。
今回はWindows環境だったのでサンプルへのパスが\となっていますが、Linux等の場合は/とします
修正
カード検出ピンの変更
そのままfs_sampleをビルドしてflashすると、下記のような、正常にファイルシステムがマウントできていないことを表すログが出力されます。
*** Booting Zephyr OS build v4.3.0-3552-g76dd50833fab ***
[00:00:00.000,000] <err> main: Storage init ERROR!
[00:00:00.000,000] <err> fs: fs mount error (-5)
Error mounting disk.
[00:00:00.000,000] <err> fs: fs not mounted (mp == 0x24000000)
これをデバッグしてみるとdrivers\disk\sdmmc_stm32.cの下記のstm32_sdmmc_card_present関数から0以外の値が返るため、エラーとなりmicroSDが正常に使用できない状態となります。
これはmicroSDが検出できなかったということです。
if (!stm32_sdmmc_card_present(priv)) {
priv->status = DISK_STATUS_NOMEDIA;
err = -ENODEV;
goto error;
}
ここで、STM32H757I-EVALのDTSファイルのSDMMCの内容を確認してみましょう。
zephyr\boards\st\stm32h757i_eval\stm32h757i_eval_stm32h757xx_m7.dtsの内容を抜粋します。
&sdmmc1 {
status = "okay";
clocks = <&rcc STM32_CLOCK(AHB3, 16)>,
<&rcc STM32_SRC_PLL2_R SDMMC_SEL(1)>;
pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9
&sdmmc1_d2_pc10 &sdmmc1_d3_pc11
&sdmmc1_d4_pb8 &sdmmc1_d5_pb9
&sdmmc1_d6_pc6 &sdmmc1_d7_pc7
&sdmmc1_ck_pc12 &sdmmc1_cmd_pd2>;
pinctrl-names = "default";
cd-gpios = <&gpioi 8 GPIO_ACTIVE_LOW>;
disk-name = "SD";
};
さらに、 UM2525の6.12 microSD™ cardを確認すると、カード検出用のピンはMFX GPIO15となっています。
MFXは、今回のSTM32H757I-EVALボードに使用されいてる、I2Cバスで接続されているI/Oエキスパンダーです。6.20 MFX (multifunction eXpander)にもう少し詳しい他のピン情報などが記述されていますが、詳細な情報は
MB1246-H757-E03 Board Schematicの接続図を参照してください。
MB1246-H757-E03 Board Schematicによると、MFXにはSTM32L152を使用していることがわかります。
ZephyrでこのSTM32L152をI/Oエキスパンダーとして使用している例を探すと、STM32L4R9I Discoveryがありました。このボードのDTSファイルを参考にします。
今回は、fs_sampleをビルドする時に使用する、ボードごとのDTSファイルの一部分を上書き可能なoverlayファイルを使用します。
ファイルは、各サンプル内のboards内にボード名[+バリアント名].overlayというファイルを作成します。
今回の場合は、下記のパスでファイルを作成します。
zephyr\samples\subsys\fs\fs_sample\boards\stm32h757i_eval_stm32h757xx_m7.overlay
下記の内容をDTSのoverlayファイルに記述します。
- MFXの設定を追加
-
cd-gpiosをMFX15ピンに変更 -
sdmmc1のpinctrl-0のピン設定を接続図を元に変更
st_mfx_i2c: &i2c1 {
status = "okay";
pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb7>;
pinctrl-names = "default";
clock-frequency = <I2C_BITRATE_STANDARD>;
mfx: gpio@42 {
compatible = "st,mfxstm32l152";
reg = <0x42>;
ngpios = <24>;
int-gpios = <&gpioi 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>;
gpio-controller;
#gpio-cells = <2>;
};
};
&sdmmc1 {
status = "okay";
pinctrl-0 = <
&sdmmc1_d0_pc8 &sdmmc1_d1_pc9
&sdmmc1_d2_pc10 &sdmmc1_d3_pc11
&sdmmc1_ck_pc12 &sdmmc1_cmd_pd2
&sdmmc1_ckin_pb8 &sdmmc1_cdir_pb9
&sdmmc1_d0dir_pc6 &sdmmc1_d123dir_pc7
>;
pinctrl-names = "default";
cd-gpios = <&mfx 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
};
これでリビルドして実行すると、今度は下記のようなログとなりました。
[00:00:00.000,000] <err> mfxstm32l152: gpio@42: error reading register 0x0 (-5)
[00:00:00.000,000] <err> mfxstm32l152: gpio@42: Unable to read Chip ID
*** Booting Zephyr OS build v4.3.0-3552-g76dd50833fab ***
[00:00:00.000,000] <err> main: Storage init ERROR!
[00:00:00.000,000] <err> fs: fs mount error (-5)
Error mounting disk.
[00:00:00.000,000] <err> fs: fs not mounted (mp == 0x24000000)
起動時のI2Cコントローラーの初期化
上記のエラーは、ボードの起動(コールドスタート)時に、MFXとの接続に使用しているI2Cコントローラーの初期化が正しく行われないためにエラーとなっているようです。
今回は定義済みのsupply-gpiosを使用し、 DTSのoverlayファイルにsupply-gpiosを追加し、対応するGPIOドライバのgpio_mfxstm32l152.cにsupply-gpiosの処理を追加します。
stm32h757i_eval_stm32h757xx_m7.overlay
zephyr\samples\subsys\fs\fs_sample\boards\stm32h757i_eval_stm32h757xx_m7.overlay
のmfx: gpio@42にsupply-gpiosを追加します。
st_mfx_i2c: &i2c1 {
status = "okay";
pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb7>;
pinctrl-names = "default";
clock-frequency = <I2C_BITRATE_STANDARD>;
mfx: gpio@42 {
compatible = "st,mfxstm32l152";
reg = <0x42>;
ngpios = <24>;
int-gpios = <&gpioi 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>;
supply-gpios = <&gpioa 4 GPIO_ACTIVE_HIGH>;
gpio-controller;
#gpio-cells = <2>;
};
};
gpio_mfxstm32l152.c
drivers/gpio/gpio_mfxstm32l152.cを下記のように修正
diff a/drivers/gpio/gpio_mfxstm32l152.c b/drivers/gpio/gpio_mfxstm32l152.c
--- a/drivers/gpio/gpio_mfxstm32l152.c
+++ b/drivers/gpio/gpio_mfxstm32l152.c
@@ -54,6 +54,7 @@ struct mfxstm32l152_drv_cfg {
/** Master I2C DT specification */
struct i2c_dt_spec i2c_spec;
struct gpio_dt_spec int_gpio;
+ struct gpio_dt_spec supply_gpio;
};
/** Cache of the pins configuration */
@@ -525,6 +526,27 @@ static int mfxstm32l152_init(const struct device *dev)
uint8_t chip_id, int_pin = 0;
int ret;
+ if (drv_cfg->supply_gpio.port) {
+ if (!gpio_is_ready_dt(&drv_cfg->supply_gpio)) {
+ LOG_ERR("Supply GPIO device not ready");
+ return -ENODEV;
+ }
+
+ ret = gpio_pin_configure_dt(&drv_cfg->supply_gpio, GPIO_OUTPUT_ACTIVE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* High -> Low -> High */
+ gpio_pin_set_dt(&drv_cfg->supply_gpio, 1);
+ k_busy_wait(1000);
+ gpio_pin_set_dt(&drv_cfg->supply_gpio, 0);
+ k_busy_wait(1000);
+ gpio_pin_set_dt(&drv_cfg->supply_gpio, 1);
+ k_busy_wait(500);
+
+ }
+
if (!device_is_ready(drv_cfg->i2c_spec.bus)) {
LOG_ERR("I2C device not found");
return -ENODEV;
@@ -628,6 +650,7 @@ static DEVICE_API(gpio, mfxstm32l152_drv_api) = {
.common = {.port_pin_mask = 0x0fff}, \
.i2c_spec = I2C_DT_SPEC_INST_GET(inst), \
.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \
+ .supply_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, supply_gpios, {0}), \
}; \
\
static struct mfxstm32l152_drv_data mfxstm32l152_##inst##_drv_data; \
Tranciverの有効化
さらに、Tranciver(Transciver)を有効にする必要があるようでした。
modules/hal/stm32/stm32cube/stm32h7xx/drivers/include/stm32h7xx_hal_conf.hのUSE_SD_TRANSCEIVERを1にして、sdmmc_stm32.c内にST公式のHALからコールバックされる関数を追加し、Tranciver(Transciver)を有効にフラグを立てます。
この辺りは、ST公式のSTM32CubeIDEからSTM32H747I-EVAL用のFatFs_Dual_Instanceサンプルを参考にしました。
stm32h7xx_hal_conf.h
diff --git a/stm32cube/stm32h7xx/drivers/include/stm32h7xx_hal_conf.h b/stm32cube/stm32h7xx/drivers/include/stm32h7xx_hal_conf.h
index 54fcc2d9..d4c0c0d7 100644
--- a/stm32cube/stm32h7xx/drivers/include/stm32h7xx_hal_conf.h
+++ b/stm32cube/stm32h7xx/drivers/include/stm32h7xx_hal_conf.h
@@ -166,7 +166,7 @@
#define VDD_VALUE (3300UL) /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY (0x0FUL) /*!< tick interrupt priority */
#define USE_RTOS 0
-#define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */
+#define USE_SD_TRANSCEIVER 1U /*!< use uSD Transceiver */
#define USE_SPI_CRC 1U /*!< use CRC in SPI */
#define USE_FLASH_ECC 0U /*!< use ECC error management in FLASH */
#define USE_SDIO_TRANSCEIVER 0U /*!< use SDIO Transceiver */
sdmmc_stm32.c
diff --git a/drivers/disk/sdmmc_stm32.c b/drivers/disk/sdmmc_stm32.c
index bde5a8fa555..904a33ffb48 100644
--- a/drivers/disk/sdmmc_stm32.c
+++ b/drivers/disk/sdmmc_stm32.c
@@ -930,6 +951,8 @@ static int disk_stm32_sdmmc_init(const struct device *dev)
struct stm32_sdmmc_priv *priv = dev->data;
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+ g_sdmmc_priv = priv;
+
if (!device_is_ready(clk)) {
LOG_ERR("clock control device not ready");
return -ENODEV;
@@ -128,6 +128,22 @@ struct stm32_sdmmc_priv {
#endif /* STM32_SDMMC_USE_DMA */
};
+static struct stm32_sdmmc_priv *g_sdmmc_priv = NULL;
+
+void HAL_SD_DriveTransceiver_1_8V_Callback(FlagStatus status)
+{
+ if (g_sdmmc_priv && g_sdmmc_priv->pe.port) {
+ if (status == SET) {
+ /* 1.8V mode: Physical High (Logical Inactive for ACTIVE_LOW) */
+ gpio_pin_configure_dt(&g_sdmmc_priv->pe, GPIO_OUTPUT_INACTIVE);
+ } else {
+ /* 3.3V mode: Physical Low (Logical Active for ACTIVE_LOW) */
+ gpio_pin_configure_dt(&g_sdmmc_priv->pe, GPIO_OUTPUT_ACTIVE);
+ }
+ k_busy_wait(10);
+ }
+}
+
#ifdef CONFIG_SDMMC_STM32_HWFC
static void stm32_sdmmc_fc_enable(struct stm32_sdmmc_priv *priv)
{
@@ -373,6 +389,8 @@ static int stm32_sdmmc_access_init(struct disk_info *disk)
HAL_StatusTypeDef hal_ret;
int err;
+ g_sdmmc_priv = priv;
+
err = stm32_sdmmc_pwr_on(priv);
if (err) {
return -EIO;
@@ -424,6 +442,7 @@ static int stm32_sdmmc_access_init(struct disk_info *disk)
#ifdef CONFIG_SDMMC_STM32_EMMC
hal_ret = HAL_MMC_Init(&priv->hsd);
#else
+ priv->hsd.Init.TranceiverPresent = SDMMC_TRANSCEIVER_PRESENT;
hal_ret = HAL_SD_Init(&priv->hsd);
#endif
if (hal_ret != HAL_OK) {
@@ -930,6 +951,8 @@ static int disk_stm32_sdmmc_init(const struct device *dev)
struct stm32_sdmmc_priv *priv = dev->data;
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+ g_sdmmc_priv = priv;
+
if (!device_is_ready(clk)) {
LOG_ERR("clock control device not ready");
return -ENODEV;
その他
不要なログが出力されるので、下記のようにコメントアウトします。
sdmmc_stm32.c
diff --git a/drivers/disk/sdmmc_stm32.c b/drivers/disk/sdmmc_stm32.c
index bde5a8fa555..904a33ffb48 100644
@@ -917,11 +936,13 @@ static void stm32_sdmmc_pwr_off(struct stm32_sdmmc_priv *priv)
return;
}
+#if 0
/* PINCTRL sleep mode when powered down */
ret = pinctrl_apply_state(priv->pcfg, PINCTRL_STATE_SLEEP);
if (ret != 0 && ret != ENOTSUP) {
LOG_WRN("Failed to configure pins for sleep (%d)", ret);
}
+#endif
gpio_pin_configure_dt(&priv->pe, GPIO_OUTPUT_INACTIVE);
}
動作確認
以上で、再度fs_sampleを実行すると、正常にmicroSDへアクセスでき、FATでフォーマットされたカードの中身が表示されました。
*** Booting Zephyr OS build v4.3.0-3552-g76dd50833fab ***
[00:00:00.086,000] <inf> main: Block count 120881152
Sector size 512
Memory Size(MB) 59024
Disk mounted.
Listing dir /SD: ...
[FILE] STM32.TXT (size = 65)
[FILE] TMP.BIN (size = 52428800)
最後に
最初の状態では正常に使用できなかったmicroSDカードを、ボードの仕様書を確認してZephyrのコードを確認したり、ST公式のサンプルを参考にしたりしながら、DTSファイルやコードを修正して動作確認できるまでになりました。
今回は、ひとまずmicroSDを使用できるところまでとなりましたが、次の課題としてはパフォーマンスの問題などがあると思います。こちらに関しては、私もいろいろと試している最中です。
ぜひ、みなさんも挑戦して解決してみてください。