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

Peripheriegeräte als Zustandsautomaten

Die Peripherie eines Mikrocontrollers lässt sich als eine Menge von Zustandsautomaten auffassen. So ließe sich beispielsweise die Konfiguration eines vereinfachten GPIO-Pins als der folgende Zustandsbaum darstellen:

  • Deaktiviert
  • Aktiviert

    • Als Ausgang konfiguriert

      • Ausgang: High
      • Ausgang: Low
    • Als Eingang konfiguriert

      • Eingang: Hoher Widerstand
      • Eingang: Auf Low-Pegel gezogen
      • Eingang: Auf High-Pegel gezogen

Wenn die Peripherieeinheit im Modus Deaktiviert startet, müssen wir die folgenden Schritte ausführen, um in den Modus Eingang: Hoher Widerstand zu ​​wechseln:

  1. Deaktiviert
  2. Aktiviert
  3. Als Eingang konfiguriert
  4. Eingang: Hoher Widerstand

Wenn wir von „Eingang: Hoher Widerstand“ zu „Eingang: Auf Low-Pegel gezogen” wechseln möchten, müssen wir die folgenden Schritte ausführen:

  1. Eingang: Hoher Widerstand 2. Eingang: Auf Low-Pegel gezogen

Wenn wir einen GPIO-Pin von der Konfiguration „Eingang: Auf Low-Pegel gezogen“ auf „Ausgang: High” umstellen wollen, müssen wir ebenfalls die folgenden Schritte ausführen:

  1. Eingang: Auf Low-Pegel gezogen
  2. Als Eingang konfiguriert
  3. Als Ausgang konfiguriert
  4. Ausgang: High

Hardware-Darstellung

Typischerweise werden die oben aufgeführten Zustände eingestellt, indem Werte in bestimmte Register geschrieben werden, die einer GPIO-Peripherieeinheit zugeordnet sind. Definieren wir zur Veranschaulichung ein fiktives GPIO-Konfigurationsregister:

NameBit-NummerWertBedeutungHinweise
enable00disabledDeaktiviert den GPIO
1enabledAktiviert den GPIO
direction10inputLegt die Richtung auf „Eingang“ fest.
1outputLegt die Richtung auf „Ausgang” fest.
input_mode2..300hi-zSetzt den Eingang auf hochohmig.
01pull-lowDer Eingangspin wird auf Low-Pegel gezogen.
10pull-highDer Eingangspin wird auf High-Pegel gezogen
11n/aUngültiger Zustand. Nicht setzen.
output_mode40set-lowDer Ausgangspin wird auf Low-Pegel gesteuert.
1set-highDer Ausgangspin wird auf High-Pegel gesteuert.
input_status5xin-val0, wenn der Eingang < 1,5 V ist; 1, wenn der Eingang ≥ 1,5 V ist.

Wir könnten die folgende Struktur in Rust bereitstellen, um diesen GPIO zu steuern:

/// GPIO interface
struct GpioConfig {
    /// Von svd2rust generierte GPIO-Konfigurationsstruktur
    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()
    }
}

Dies würde uns jedoch erlauben, bestimmte Register zu verändern, was keinen Sinn ergibt. Was passiert beispielsweise, wenn wir das Feld output_mode setzen, während unser GPIO als Eingang konfiguriert ist?

Im Allgemeinen würde die Verwendung dieser Struktur es uns ermöglichen, Zustände zu erreichen, die nicht durch unsere obige Zustandsmaschine definiert sind: z. B. einen Ausgang, der auf LOW gesetzt wird, oder einen Eingang, der auf HIGH gesetzt wird. Bei mancher Hardware mag dies keine Rolle spielen. Bei anderer Hardware könnte es jedoch zu unerwartetem oder undefiniertem Verhalten führen!

Obwohl diese Schnittstelle bequem zu implementieren ist, erzwingt sie nicht die in unserer Hardware-Implementierung festgelegten Designvorgaben.