状態機械としてのペリフェラル
マイクロコントローラのペリフェラルは、一連の状態機械の集合と考えることができます。たとえば、単純化した GPIOピン の構成は、次のような状態の木として表現できます:
- 無効
- 有効
- 出力として設定
- 出力: High
- 出力: Low
- 入力として設定
- 入力: ハイインピーダンス
- 入力: プルダウン
- 入力: プルアップ
- 出力として設定
ペリフェラルが Disabled モードから開始する場合、Input: High Resistance モードへ移るには、次の手順を実行しなければなりません:
- 無効
- 有効
- 入力として設定
- 入力: ハイインピーダンス
Input: High Resistance から Input: Pulled Low に移りたい場合、次の手順を実行しなければなりません:
- 入力: ハイインピーダンス
- 入力: プルダウン
同様に、GPIOピンを Input: Pulled Low として構成された状態から Output: High へ移行したい場合、次の手順を実行しなければなりません:
- 入力: プルダウン
- 入力として設定
- 出力として設定
- 出力: High
ハードウェア表現
通常、上に挙げた状態は、GPIOペリフェラルにマップされた所定のレジスタに値を書き込むことで設定されます。これを説明するために、架空の GPIO 構成レジスタを定義してみましょう:
| 名前 | ビット番号 | 値 | 意味 | 注記 |
|---|---|---|---|---|
| enable | 0 | 0 | 無効 | GPIO を無効にする |
| 1 | 有効 | GPIO を有効にする | ||
| direction | 1 | 0 | 入力 | 方向を入力に設定する |
| 1 | 出力 | 方向を出力に設定する | ||
| input_mode | 2..3 | 00 | hi-z | 入力をハイインピーダンスに設定する |
| 01 | pull-low | 入力ピンは Low にプルされる | ||
| 10 | pull-high | 入力ピンは High にプルされる | ||
| 11 | 該当なし | 無効な状態。設定しないこと | ||
| output_mode | 4 | 0 | Low に設定 | 出力ピンを Low に駆動する |
| 1 | High に設定 | 出力ピンを High に駆動する | ||
| input_status | 5 | x | 入力値 | 入力が < 1.5v の場合は 0、入力が >= 1.5v の場合は 1 |
この GPIO を制御するために、Rust では次のような構造体を公開すること もできます:
/// GPIO インターフェース
struct GpioConfig {
/// svd2rust によって生成された GPIO 構成構造体
periph: GPIO_CONFIG,
}
impl GpioConfig {
pub fn set_enable(&mut self, is_enabled: bool) {
self.periph.modify(|_r, w| {
w.enable().set_bit(is_enabled)
});
}
pub fn set_direction(&mut self, is_output: bool) {
self.periph.modify(|_r, w| {
w.direction().set_bit(is_output)
});
}
pub fn set_input_mode(&mut self, variant: InputMode) {
self.periph.modify(|_r, w| {
w.input_mode().variant(variant)
});
}
pub fn set_output_mode(&mut self, is_high: bool) {
self.periph.modify(|_r, w| {
w.output_mode.set_bit(is_high)
});
}
pub fn get_input_status(&self) -> bool {
self.periph.read().input_status().bit_is_set()
}
}
しかし、これでは意味をなさない特定のレジスタを変更できてしまいます。たとえば、GPIO が入力として構成されているときに output_mode フィールドを設定すると、どうなるでしょうか?
一般に、この構造体を使うと、上の状態機械で定義されていない状態、たとえばプルダウンされた出力や High に設定された入力のような状態に到達できてしまいます。ハードウェアによっては、これは問題にならないかもしれません。別のハードウェアでは、予期しない動作や未定義動作を引き起こす可能性があります!
このインターフェースは記述しやすいものの、ハードウェア実装で定められた設計上の契約を強制しません。