1. はじめに
これまでの記事では、Zephyr の入門的な記事を投稿してきました。
一方で直近の記事は、DeviceTree の記述方法について部分的に解説をしたものの、視野の狭い解説になっており理解しにくい内容だったと反省しております。
そこで、今回はいったん理屈を抜きにしてとりあえず動かして、答えを見てから理解しようという方針で記事を書いていこうと思います。
過去の Zephyr の記事は以下にまとめていますのでご参考にしていただけると幸いです。
2. ターゲット
最近触ったマイコンボードの中でちょっとお気に入りの Nucleo G431KB をベースに話を進めていきます。
せっかくなので Raspberry Pi Pico / Pico2 と比較してみました。
| Nucleo G431KB | RPi pico | RPi pico2 | |
|---|---|---|---|
| アーキテクチャ | Cortex M4F | Cortex M0+ | Cortex M33 |
| CPU clock | 170 MHz | 133 MHz x 2 | 150 MHz x 2 |
| FPU | あり | なし | あり |
| RAM | 32 KB | 264 KB | 520 KB |
| ROM | 128 KB | 2 MB | 4 MB |
| Size (mm) | 18.542 x 50.292 | 21.0 x 51.3 | 21.0 x 51.3 |
| 形状 | Arduino nano 互換 | 独自(RPi pico系) | 独自(RPi pico系) |
| デバッガ | ST-Link 内蔵 | 別売り(約 2,000 円) | 別売り(約 2,000 円) |
| 値段 (2026年1月) | 約 2,000 円 | 約 800 円 | 約 900 円 |
こうやって見ると、pico / pico2 の ROM / RAM が異次元ですね・・・
ですが、nucleo_g431kb には pico 系にはない以下の魅力があります。
- Cortex M4 170MHz + FPU 搭載で演算能力としてなかなか
- ST-Link が内蔵されているためこれ単体でデバッグ/書き込み可能
- Arduino nano フォームファクター互換なので拡張ボードも利用可能
本記事の終盤にフォームファクター互換を活かすおまけも記載していますのであわせてご覧ください。
3. ディレクトリ構成と overlay の配置
まずは overlay の置き場所について触れておきます。明示的に指定しなければ、ビルド時に2箇所のみ自動的に検索して適用されます。
- boards ディレクトリ直下
- CMakeLists.txt と同じ場所
自作ソフトを apps として作成した場合、以下のような配置になります。
.
├── .venv/
├── .west/
├── apps/ # 自作ソフトのディレクトリ(名前は何でもOK)
│ ├── boards/
│ │ └── nucleo_g431kb.overlay # 1. ディレクトリを分けて管理する場合はこちら
│ ├── CMakeLists.txt # west build で参照されるビルドの設定集
│ ├── nucleo_g431kb.overlay # 2. CMakeLists.txt と同じ階層でも良い
│ └── prj.conf
├── bootloader/
├── modules/
└── zephyr/
一方で、以下のようにビルド時に明示的に指定することも可能です。
west build -b nucleo_g431kb -- -DDTC_OVERLAY_FILE=path/to/foo.overlay
なお、CMakeLists.txt をゼロから作るのがめんどくさい場合は、以下のように zephyr/samples/hello_world をコピペして編集するのがおすすめです。
cp -rf zephyr/samples/hello_world apps
4. nucleo_g431kb 向けの雛形
まずは、nucleo_g431kb で適用できる UART / I2C / SPI の選択肢をすべて挙げたものを出しておきます(Timer(PWM)は数が多いので割愛)。
設定内容は以下の通りです。
以下の内容をそのまま overlay として先述の配置に保存すれば利用できます。
nucleo_g431kb 向け overlay
/*
* Copyright (c) 2026 Takayuki Goto <tkg.develop@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
chosen {
zephyr,console = &usart1;
zephyr,shell-uart = &usart1;
};
};
&lpuart1 {
status = "disabled";
current-speed = <115200>;
// lpuart1_tx_pa2
// lpuart1_rx_pa3
pinctrl-0 = <&lpuart1_tx_pa2 &lpuart1_rx_pa3>;
pinctrl-names = "default";
// LL_DMAMUX_REQ_LPUART1_TX, LL_DMAMUX_REQ_LPUART1_RX
// dmas = <&dmamux1 0 35 STM32_DMA_PERIPH_TX>,
// <&dmamux1 1 34 STM32_DMA_PERIPH_RX>;
// dma-names = "tx", "rx";
// fifo-enable;
};
&usart1 {
status = "okay";
current-speed = <115200>;
// usart1_tx_pa9, usart1_tx_pb6
// usart1_rx_pa10, usart1_rx_pb7
pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>;
pinctrl-names = "default";
// LL_DMAMUX_REQ_USART1_TX, LL_DMAMUX_REQ_USART1_RX
dmas = <&dmamux1 2 25 STM32_DMA_PERIPH_TX>,
<&dmamux1 3 24 STM32_DMA_PERIPH_RX>;
dma-names = "tx", "rx";
fifo-enable;
};
&usart2 {
status = "disabled";
current-speed = <115200>;
// usart2_tx_pa2, usart2_tx_pa14, usart2_tx_pb3
// usart2_rx_pa3, usart2_rx_pa15, usart2_rx_pb4
pinctrl-0 = < &usart2_tx_pa2 &usart2_rx_pa3 >;
pinctrl-names = "default";
// LL_DMAMUX_REQ_USART2_TX, LL_DMAMUX_REQ_USART2_RX
// dmas = <&dmamux1 4 27 STM32_DMA_PERIPH_TX>,
// <&dmamux1 5 26 STM32_DMA_PERIPH_RX>;
// dma-names = "tx", "rx";
};
&dma1 {
status = "okay";
};
&dmamux1 {
status = "okay";
};
&i2c1 {
status = "okay";
clock-frequency = <I2C_BITRATE_STANDARD>;
// i2c1_scl_pa13, i2c1_scl_pa15, i2c1_scl_pb8
// i2c1_sda_pa14, i2c1_sda_pb7
pinctrl-0 = < &i2c1_scl_pa15 &i2c1_sda_pb7 >;
pinctrl-names = "default";
};
&i2c2 {
status = "disabled";
clock-frequency = <I2C_BITRATE_STANDARD>;
// i2c2_scl_pa9
// i2c2_sda_pa8, i2c2_sda_pf0
pinctrl-0 = < &i2c2_scl_pa9 &i2c2_sda_pa8 >;
pinctrl-names = "default";
};
&i2c3 {
status = "disabled";
clock-frequency = <I2C_BITRATE_STANDARD>;
// i2c3_scl_pa8
// i2c3_sda_pb5
pinctrl-0 = < &i2c3_scl_pa8 &i2c3_sda_pb5 >;
pinctrl-names = "default";
};
&spi1 {
status = "disabled";
clock-frequency = <8000000>;
// spi1_sck_pa5, spi1_sck_pb3
// spi1_miso_pa6, spi1_miso_pb4
// spi1_mosi_pa7, spi1_mosi_pb5
pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>;
pinctrl-names = "default";
// cs-gpios = <&gpiob 7 GPIO_ACTIVE_LOW>;
};
&spi2 {
status = "disabled";
clock-frequency = <8000000>;
// spi2_sck_pf1
// spi2_miso_pa10
// spi2_mosi_pa11
pinctrl-0 = <&spi2_sck_pf1 &spi2_miso_pa10 &spi2_mosi_pa11>;
pinctrl-names = "default";
// cs-gpios = <&gpioa 1 GPIO_ACTIVE_LOW>;
};
&spi3 {
status = "okay";
clock-frequency = <8000000>;
// spi3_sck_pb3
// spi3_miso_pb4
// spi3_mosi_pb5
pinctrl-0 = <&spi3_sck_pb3 &spi3_miso_pb4 &spi3_mosi_pb5>;
pinctrl-names = "default";
cs-gpios = <&gpiob 0 GPIO_ACTIVE_LOW>;
sdhc0: sdhc@0 {
compatible = "zephyr,sdhc-spi-slot";
reg = <0>;
status = "okay";
mmc {
compatible = "zephyr,sdmmc-disk";
disk-name = "SD";
status = "okay";
};
spi-max-frequency = <8000000>;
};
};
&timers1 {
status = "disabled";
pwm1: pwm {
status = "disabled";
// tim1_ch1_pa8, tim1_ch1n_pa7, tim1_ch1n_pa11
// tim1_ch2_pa9, tim1_ch2n_pa12, tim1_ch2n_pb0
// tim1_ch3_pa10, tim1_ch3n_pf0
// tim1_ch4_pa11,
pinctrl-0 = <&tim1_ch1_pa8 &tim1_ch4_pa11>;
pinctrl-names = "default";
};
};
&timers2 {
status = "disabled";
pwm2: pwm {
status = "disabled";
// tim2_ch1_pa0, tim2_ch2_pa1, tim2_ch3_pa2, tim2_ch4_pa3
// tim2_ch1_pa5, tim2_ch3_pa9, tim2_ch4_pa10, tim2_ch1_pa15
// tim2_ch2_pb3
pinctrl-0 = <&tim2_ch1_pa0>;
pinctrl-names = "default";
};
};
&timers3 {
status = "disabled";
pwm3: pwm {
status = "disabled";
// tim3_ch2_pa4, tim3_ch1_pa6, tim3_ch2_pa7, tim3_ch3_pb0
// tim3_ch1_pb4, tim3_ch2_pb5, tim3_ch4_pb7
pinctrl-0 = <&tim3_ch2_pa4>;
pinctrl-names = "default";
};
};
&timers4 {
status = "disabled";
pwm4: pwm {
status = "disabled";
// tim4_ch1_pa11, tim4_ch2_pa12, tim4_ch3_pa13, tim4_ch1_pb6
// tim4_ch2_pb7, tim4_ch3_pb8
pinctrl-0 = <&tim4_ch2_pa12>;
pinctrl-names = "default";
};
};
&timers8 {
status = "disabled";
pwm8: pwm {
status = "disabled";
// tim8_ch1n_pa7, tim8_ch2_pa14, tim8_ch1_pa15, tim8_ch2n_pb0
// tim8_ch1n_pb3, tim8_ch2n_pb4, tim8_ch3n_pb5, tim8_ch1_pb6
// tim8_ch2_pb8
pinctrl-0 = <&tim8_ch2_pa14>;
pinctrl-names = "default";
};
};
&timers15 {
status = "disabled";
pwm15: pwm {
status = "disabled";
// tim15_ch1n_pa1, tim15_ch1_pa2, tim15_ch2_pa3
pinctrl-0 = <&tim15_ch1n_pa1>;
pinctrl-names = "default";
};
};
&timers16 {
status = "disabled";
pwm16: pwm {
status = "disabled";
// tim16_ch1_pa6, tim16_ch1_pa12, tim16_ch1n_pa13, tim16_ch1_pb4
// tim16_ch1n_pb6, tim16_ch1_pb8
pinctrl-0 = <&tim16_ch1_pb8>;
pinctrl-names = "default";
};
};
&timers17 {
status = "disabled";
pwm17: pwm {
status = "disabled";
// tim17_ch1_pa7, tim17_ch1_pb5, tim17_ch1n_pb7
pinctrl-0 = <&tim17_ch1_pa7>;
pinctrl-names = "default";
};
};
/*
&adc1 {
status = "disabled";
// adc1_in1_pa0, adc1_in2_pa1, adc1_in3_pa2
// adc1_in4_pa3, adc1_in15_pb0, adc1_in10_pf0
pinctrl-0 = <&adc1_in1_pa0>;
#address-cells = <1>;
#size-cells = <0>;
st,adc-clock-source = "SYNC";
st,adc-prescaler = <4>;
};
&adc2 {
status = "disabled";
// adc2_in1_pa0, adc2_in2_pa1, adc2_in17_pa4
// adc2_in13_pa5, adc2_in3_pa6, adc2_in4_pa7
// adc2_in10_pf1
// pinctrl-0 = <&>;
};
&dac1 {
status = "disabled";
// dac1_out1_pa4, dac1_out2_pa5
// pinctrl-0 = <&>;
};
*/
5. 使い方例
5.1. USART2 の有効化と出力先の変更
先述の内容は図の通り usart1 を有効にしており、USB経由(ST-Link)に繋がっている usart2 は無効にしています。
USB 経由でシリアル通信を行いたい場合は以下の2点を変更してください。
/ {
chosen {
zephyr,console = &usart2;
zephyr,shell-uart = &usart2;
};
};
&usart2 {
status = "okay";
current-speed = <115200>;
// usart2_tx_pa2, usart2_tx_pa14, usart2_tx_pb3
// usart2_rx_pa3, usart2_rx_pa15, usart2_rx_pb4
pinctrl-0 = < &usart2_tx_pa2 &usart2_rx_pa3 >;
pinctrl-names = "default";
5.2. Timer(PWM) を有効にする
timers1 と pwm の status = "okay" にすると PA8 と PA11 で PWM 出力することができます。
&timers1 {
status = "okay";
pwm1: pwm {
status = "okay";
// tim1_ch1_pa8, tim1_ch1n_pa7, tim1_ch1n_pa11
// tim1_ch2_pa9, tim1_ch2n_pa12, tim1_ch2n_pb0
// tim1_ch3_pa10, tim1_ch3n_pf0
// tim1_ch4_pa11,
pinctrl-0 = <&tim1_ch1_pa8 &tim1_ch4_pa11>;
pinctrl-names = "default";
};
};
対象のピンを変えたい場合は、pinctrl-0 = <&tim1_ch1_pa8 &tim1_ch4_pa11>; の右辺を変更します。変更可能なピンは、直前のコメントアウト内に羅列していますので、これらをコピペして設定してください。
例えば、PA11 のみを PWM 用に設定する場合は以下のようになります。
pinctrl-0 = <&tim1_ch4_pa11>;
※ 他の機能で同じピンを使っていないか確認の上設定してください。
例えば tim1_ch2_pa9 の pa9 は usart1_tx_pa9 にも使われており、同時利用はできません。
※ 同様に、この pwm1 内の同一 ch の重複も回避してください。
例えば tim1_ch1n_pa7 と tim1_ch1n_pa11 は tim1 の中の同一 ch1 なので、これも同時利用はできません。
5.3. I2C3 を有効にする
同じ要領で I2C3 を有効にしたい場合は status を okay にするだけです。
※ 先述の PWM で PA8 を設定している場合は重複するので注意。
(nucleo_g431kb だと、i2c3 に割り当てられるピンはそれぞれ1種類しかなく変更不可)
&i2c3 {
status = "okay";
clock-frequency = <I2C_BITRATE_STANDARD>;
// i2c3_scl_pa8
// i2c3_sda_pb5
pinctrl-0 = < &i2c3_scl_pa8 &i2c3_sda_pb5 >;
pinctrl-names = "default";
};
5.4. DMA の有効化
ついでに DMA の設定を有効にしやすいようにこちらも記載しています。
デフォルトで usart1 に適用していますが、usart2 にも適用したい場合は dmas, dma-names, fifo-enable のコメントアウトを解除するだけです。
必須機能ではないですが、性能・機能を無駄なく活かせてコーディングも楽になるためオススメです。
活かし方は zephyr/samples/boards/st/uart/circular_dma を参考にしてください。
&usart2 {
status = "okay";
current-speed = <115200>;
// usart2_tx_pa2, usart2_tx_pa14, usart2_tx_pb3
// usart2_rx_pa3, usart2_rx_pa15, usart2_rx_pb4
pinctrl-0 = < &usart2_tx_pa2 &usart2_rx_pa3 >;
pinctrl-names = "default";
// LL_DMAMUX_REQ_USART2_TX, LL_DMAMUX_REQ_USART2_RX
dmas = <&dmamux1 4 27 STM32_DMA_PERIPH_TX>,
<&dmamux1 5 26 STM32_DMA_PERIPH_RX>;
dma-names = "tx", "rx";
fifo-enable;
};
6. Arduino nano 互換を活かした応用
今回例示した overlay は usart1 を有効にしているなど、少々変な設定だとは思いますが、これは今回使用している nucleo_g431kb が Arduino Nano のフォームファクター準拠なことに由来しています。
つまり、Arduino nano のピンアサインに近づけた設定というわけです。
その結果 Arduino nano 互換として様々な拡張ボードが利用できるようになり、私は下記のコネクタキャリアをセットで愛用しています。
これを使うと以下のメリットがあります。
- メスのピンヘッダで簡易ブレッドボード化
-
USART1は Grove コネクタから利用可能 -
I2C1は Qwiic と Grove コネクタからアクセス可能 - SD カードシールドも付属(動くけど要検証)
-
ADC1とADC2も Grove コネクタからアクセス可能(ただし未所持で未確認)
いろんなセンサードライバの実装を行ったり、性能を確認・検証する場合に於いて、はんだ不要で付け替えたりできるため非常に重宝しています。
6.1. 利用できるコネクターの紹介
6.1.1. Grove コネクタ
Grove コネクタは Seeed Studio 提唱のコネクタで、幅広く採用されています。
6.1.2. Qwiic コネクタ
Qwiic コネクタは Sparkfun が提唱しているコネクタで、用途もほぼ Grove と同じですが更に小型化されています。
6.1.3. 相互変換ハブ
どちらか一方しか使えないわけではなく、以下のようなハブを使うと相互に変換でき、ポートも増やせるためこれも手元にあるとさらに便利です。
6.2. dts の設定や配線のチェック
これらを使って色々繋げた様子はこちら。
ドライバを書く前に、結線や overlay が正しいかチェックする際に i2c scan が便利です。
その機能を有効にするには、prj.conf で下記3つを有効にするだけです。
CONFIG_I2C=y
CONFIG_SHELL=y
CONFIG_I2C_SHELL=y
実際に確認する方法は以下の流れです。DTS や 配線が正しければ以下のように該当するアドレスが表示されます。
uart:~$ *** Booting Zephyr OS build v4.3.0-3523-g588d22464d13 ***
Hello World! nucleo_g431kb/stm32g431xx
uart:~$ i2c scan <- 一旦 i2c scan と打つ
scan: wrong parameter count
scan - Scan I2C devices
Usage: scan <device>
Subcommands:
i2c@40005400 <- バスのアドレス一覧が出てくる(有効なバスだけが表示)
uart:~$ i2c scan i2c@40005400 <- バスを指定して改めて実行
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- --
10: 10 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- 28 29 -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 -- -- -- -- -- -- --
6.3. SDカードシールドを有効にする方法
一応、SDカードシールドが使えることは確認しています。ただし下記注意点があります。
-
SD_SS(CS)はデフォルトではD4(PB7)に割り当てられていますが、PB7はI2C1 SCLになるため、Solder Jumper を短絡してD3(PB0)に変更が必要 - SDカードへアクセスする際の初期化時に、
SPIのクロックが規定外で先に進めません。雑にコメントアウトで回避はできますが要検証 -
ピン が重複する以外の理由があるのかデフォルトで有効になっているI2C1(Grove/Qwiic) と併用できていません。代わりにI2C2,I2C3は利用可能ですが、その場合はUSART1との干渉に注意。D4(PB7)の Solder Jumper が繋がったままが原因でした。D4(PB7)の Jumper をしっかり切断し、D3(PB0)を繋げることで SD カードへのアクセスと I2C1 の併用ができることを確認しています。
6.3.1. Solder Jumper の設定方法
コネクタキャリア側のジャンパーを切り替えることで、SDカード用の CS を D4(PB7)、D3(PB0)、D2(PA12) のどれかに割り当てることができます。デフォルトでは D4(PB7) になっていますが、これは i2c1_sda_pb7 と重複しているため、以下のジャンパーを結線して D3(PB0) に切り替えています(写真オレンジ枠が該当のジャンパー)。
なお、nucleo_g431kb の USBコネクタの向き(写真左上)は、コネクタキャリア側に USB という印字がされている方(写真右下部)と逆の位置になる点には注意。
双方のピンアサインの画像も以下に貼り付けておきます。
6.3.2. SDカードを機能させるための SPI の初期化を通すための対応
ジャンパーの結線と overlay の有効化を行っただけでは以下のエラーで動作しません。
[00:00:00.001,000] <err> spi_stm32: Unsupported frequency 400000Hz, max 85000000Hz, min 664062Hz
[00:00:00.001,000] <err> sdhc_spi: Card SCLK init sequence failed
これは以下の初期化関数内で低速過ぎて弾かれるのですが、コメントアウトで回避はできています(要検証)。
922 static int spi_stm32_configure(const struct device *dev,
923 const struct spi_config *config,
924 bool write)
925 {
926 const struct spi_stm32_config *cfg = dev->config;
927 struct spi_stm32_data *data = dev->data;
:
:
999 for (br = 0; br < ARRAY_SIZE(scaler); ++br) {
1000 uint32_t clk = clock >> (br + shift);
1001
1002 if (clk <= config->frequency) {
1003 break;
1004 }
1005 }
1006 /*
1007 if (br >= ARRAY_SIZE(scaler)) {
1008 LOG_ERR("Unsupported frequency %uHz, max %uHz, min %uHz",
1009 config->frequency, clock >> shift,
1010 clock >> (ARRAY_SIZE(scaler) - 1 + shift));
1011 return -EINVAL;
1012 }
1013 */
1014 LL_SPI_Disable(spi);
1015 LL_SPI_SetBaudRatePrescaler(spi, scaler[br]);
1016
1017 #if defined(SPI_CFG2_IOSWP)
1018 if (cfg->ioswp) {
1019 LL_SPI_EnableIOSwap(cfg->spi);
1020 }
1021 #endif
6.3.3. SD カードのフォーマット
下記手順でブートセクタ、パーティション等を構築することでアクセスできることを確認しています。
※ SD カードは /dev/sda として検出している前提です。作業環境に依存するため自分のPCやカードリーダーの作りを把握した上で進めてください。
$ sudo fdisk /dev/sda
Welcome to fdisk (util-linux 2.39.3).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): o
Created a new DOS (MBR) disklabel with disk identifier 0xb488ee27.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):
First sector (2048-7744511, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-7744511, default 7744511):
Created a new partition 1 of type 'Linux' and of size 3.7 GiB.
Partition #1 contains a vfat signature.
Do you want to remove the signature? [Y]es/[N]o: Y
The signature will be removed by a write command.
Command (m for help): t
Selected partition 1
Hex code or alias (type L to list all): b
Changed type of partition 'Linux' to 'W95 FAT32'.
Command (m for help): p
Disk /dev/sda: 3.69 GiB, 3965190144 bytes, 7744512 sectors
Disk model: SD/MMC
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xb488ee27
Device Boot Start End Sectors Size Id Type
/dev/sda1 2048 7744511 7742464 3.7G b W95 FAT32
Filesystem/RAID signature on partition 1 will be wiped.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
パーティション構成を作成したあと、パーティション自体を vfat でフォーマットします。
$ sudo mkfs.vfat -v /dev/sda1
mkfs.fat 4.2 (2021-01-31)
Auto-selecting FAT32 for large filesystem
/dev/sda1 has 122 heads and 62 sectors per track,
hidden sectors 0x0800;
logical sector size is 512,
using 0xf8 media descriptor, with 7742436 sectors;
drive number 0x80;
filesystem has 2 32-bit FATs and 8 sectors per cluster.
FAT size is 7552 sectors, and provides 965912 clusters.
There are 32 reserved sectors.
Volume ID is 9eae7be7, no volume label.
6.3.4. 実際にSDカードを読み書きしてみる
SDカードへのアクセスに関しては、samples/subsys/fs/fs_sample/ としてサンプルがありますので、これに nucleo_g431kb.overlay を適用してビルド・ファーム書き込みを行います。
$ tree zephyr/samples/subsys/fs/fs_sample/
zephyr/samples/subsys/fs/fs_sample/
├── CMakeLists.txt
├── Kconfig
├── README.rst
├── boards
│ ├── apollo4p_evb.conf
│ :
│ ├── nucleo_g431kb.overlay <- ここに nucleo_g431kb.overlay を配置
│ :
│ └── stm32h747i_disco_stm32h747xx_m7.conf
├── prj.conf
├── prj_ext.conf
├── sample.yaml
└── src
└── main.c
west build -p -b nucleo_g431kb zephyr/samples/subsys/fs/fs_sample/
west flash --runner openocd
$ cu -s 115200 -l /dev/ttyUSB1
Connected.
*** Booting Zephyr OS build v4.3.0-3523-g588d22464d13 ***
[00:00:00.034,000] <inf> sd: Maximum SD clock is under 25MHz, using clock of 8000000Hz
[00:00:00.034,000] <inf> main: Block count 7744512
Sector size 512
Memory Size(MB) 3781
[00:00:00.068,000] <inf> sd: Maximum SD clock is under 25MHz, using clock of 8000000Hz
Disk mounted.
[00:00:00.108,000] <inf> sd: Maximum SD clock is under 25MHz, using clock of 8000000Hz
Listing dir /SD: ...
[FILE] SOME.DAT (size = 0)
[DIR ] SOME
PC で SDカードの中身を確認すると書き込まれていることが確認できます。
7. まとめ
今回、記事を書いている間に、あれもこれもとネタが出てきてカロリー高くなってしまったので、一旦ここで記事を分割しておきます。
少なくともこの記事に沿って手を動かすことで、Nucleo G431KB / STM32G431KBT6 向けの設定はある程度自由に変更できるようになるかと思います。
次回は、この overlay を踏み込んで解説することで、他のボード向けの overlay も自分で書ける応用編を考えています。





