Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

状態機械としてのペリフェラル

マイクロコントローラのペリフェラルは、一連の状態機械の集合と考えることができます。たとえば、単純化した GPIOピン の構成は、次のような状態の木として表現できます:

  • 無効
  • 有効
    • 出力として設定
      • 出力: High
      • 出力: Low
    • 入力として設定
      • 入力: ハイインピーダンス
      • 入力: プルダウン
      • 入力: プルアップ

ペリフェラルが Disabled モードから開始する場合、Input: High Resistance モードへ移るには、次の手順を実行しなければなりません:

  1. 無効
  2. 有効
  3. 入力として設定
  4. 入力: ハイインピーダンス

Input: High Resistance から Input: Pulled Low に移りたい場合、次の手順を実行しなければなりません:

  1. 入力: ハイインピーダンス
  2. 入力: プルダウン

同様に、GPIOピンを Input: Pulled Low として構成された状態から Output: High へ移行したい場合、次の手順を実行しなければなりません:

  1. 入力: プルダウン
  2. 入力として設定
  3. 出力として設定
  4. 出力: High

ハードウェア表現

通常、上に挙げた状態は、GPIOペリフェラルにマップされた所定のレジスタに値を書き込むことで設定されます。これを説明するために、架空の GPIO 構成レジスタを定義してみましょう:

名前ビット番号意味注記
enable00無効GPIO を無効にする
1有効GPIO を有効にする
direction10入力方向を入力に設定する
1出力方向を出力に設定する
input_mode2..300hi-z入力をハイインピーダンスに設定する
01pull-low入力ピンは Low にプルされる
10pull-high入力ピンは High にプルされる
11該当なし無効な状態。設定しないこと
output_mode40Low に設定出力ピンを Low に駆動する
1High に設定出力ピンを High に駆動する
input_status5x入力値入力が < 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 に設定された入力のような状態に到達できてしまいます。ハードウェアによっては、これは問題にならないかもしれません。別のハードウェアでは、予期しない動作や未定義動作を引き起こす可能性があります!

このインターフェースは記述しやすいものの、ハードウェア実装で定められた設計上の契約を強制しません。