皆さん こんにちは。
今回は前回構築した構成を全体的に見ていきます。
前回の環境構築 により以下のディレクトリにパッケージ(プロジェクト)が構築されています。(xxxxは皆さんのユーザー名)
C:\Users\xxxx\pprp\rp2040
(pprpは Pi Pico Rust Projectの略です)
config.toml
C:\Users\xxxx\pprp\rp2040 の下に .cargo というディレクトリがあり、そこに config.toml というファイルがあります。
このファイルについて、わかる部分だけ簡単に説明します。
[build]
target = “thumbv6m-none-eabi”
これはラズピコのマイコンである RP2040 のARM cortex-M0+ アーキテクチャをビルド対象に指定しています。
確認するには ここ と ここ を照らし合わせてみてください。
rustflags = [] の中(コンパイルオプションの指定)
“-C”, “link-arg=-Tlink.x”,
ここではリンカスクリプトに link.x というファイルを指定しています。
link.x はこちらで用意する必要はなく cortex-m-rt クレートによって自動的につくられます。
それからもうひとつ
“-C”, “linker=flip-link”,
これはスタックのプロテクションツールだそうです。
一般的に静的メモリやヒープはアドレスの低い方から高い方に伸びていき、スタックはアドレスの高い方から低い方に伸びていきます。
これが衝突するとスタックオーバーフローが発生します。
何か警告が出るのかパニックするのか、後に勉強してトライしてみようと思います。
.vscode下のファイル
rp2040.svd
svdファイルはデバイスのレジスタを定義したものです。
組込みRustでは svd2rust により PAC のソースコードを自動生成してくれます。
PACは Peripheral Access Crate (ペリフェラル アクセス クレート) の略です。
このファイルは私がネットで探して来てパッケージ内に配置しました。
すでにビルドシステム内で用意されているかも知れませんが、念のために配置しました。
launch.json
VSCodeのデバッグ時の構成や設定を記述したファイルです。
Wio Terminal を使っている分には、ひな形のものをそのまま使って頂ければ良いと思います。
ただし複製をつくって、実行ファイル名が変わる場合には “executable” の部分を編集する必要があります。
sesttings.json
上の2行は皆さまの構成に合わせてパスを設定する必要があります。
openocd.exe と arm-none-eabi-gdb.exe それぞれについて設定します。
下の2行は、Windows環境で VSCode上の表示に警告が出ることがあったので付加してみました。
特に編集する必要はありません。
tasks.json
ビルド時などのタスクを記述しています。
特に変更する必要はありません。
それでは、main.rs について見ていきます。
main.rs
Rustのソースは拡張子が rs です。
パッケージの src フォルダ下に main.rs が置かれています。
no_stdなRust
no_stdなRustでコードを書くことになるので、以下のひな形部分はいつでも共通で、ここにコードをつけ足していくことになります。
ただし、(3)のuseは必要なクレート等を都度、記述する必要があります。
#![no_std] // (1)
#![no_main] // (2)
use bsp::entry; // (3)
use embedded_hal::digital::v2::OutputPin; // (3)
use panic_halt as _; // (3)
use rp_pico as bsp; // (3)
use bsp::hal::{ // (3)
clocks::{init_clocks_and_plls, Clock},
pac,
sio::Sio,
watchdog::Watchdog,
};
#[entry] // (4)
fn main() -> ! { // (5)
loop { // (6)
}
}
#![…] と #[…] について
これらはアトリビュート(属性)と言います。
…の部分がアトリビュートの名前です。
#![…]
こちらは内部属性と言いスコープ(範囲)を持ちます。
クレート(ファイル)単位で全体的に影響を受けます。
#[…]
対してこちらは外部属性と言い、そのすぐ下の要素だけが影響を受けます。
例えば
#[entry]
fn main()
の部分では、main()関数だけが entry だと言っています。
(1)#![no_std]
これは内部属性なので main.rs 全体が no_std であると言っています。
no_std は std (スタンダード) ではない の意味です。
Rustの標準ライブラリは core , alloc , std の3レベル構造になっています。
no_stdアトリビュートを指定するとRustコンパイラは stdクレートではなく coreクレートを使ってプログラムをビルドします。
OSが存在しないベアメタルな開発では no_std を使うようです。
stdクレートを使わない代わりにcoreクレートを使うことになります。
allocクレートはヒープメモリを利用する型を提供します。ヒープメモリを利用する Box や Vec 等の構造体が含まれています。
allocクレートを利用するにはメモリアロケータの実装が必要で alloc-cortex-mクレート等が利用できます。
(2)#![no_main]
こちらも内部属性なので main.rs 全体が no_main であると言っています。
stdクレートに実装したコードがmain()関数を呼び出すための前処理を行っています。
この前処理はOSの機能が必要ですが組込みRustでは同様の前処理を行わなえないため、このアトリビュートで処理不要であることを指示します。
(3)use
use で必要なクレートから構造体やクレート等を見えるようにします。
(4)#[entry]
これは外部属性ですぐ下の main()関数が entry であると言っています。
no_mainアトリビュートにより main()関数が呼ばれなくなります。
そこで cortex-m-rtクレートの entryアトリビュートを使います。
cortex-m-rtクレートはマイコンをリセットし、スタックポインタの初期化や必要最小限のハードウェアの初期化を行った後に entryアトリビュートのついた関数を呼び出します。
(5)main()
main()関数の戻り値は ! となっています。
これは発散する関数と呼ばれ、この関数から戻らないことを意味しています。
(6)loop {}
とは言え loop によりプログラムが繰り返し動作するようにします。
今回は全体の構成を眺めてみました。
次回はLチカのソースコードを見ていきます。
お疲れさまでした。