外设状态机
MCU 的外设可以被看作是一种状态机. 例如, 简化的 GPIO Pin (GPIO 引脚) 的配置可以表示为如下状态树:
- Disabled (禁用)
- Enabled (启用)
- Configured as Output (输出)
- Output: High (高电平输出)
- Output: Low (低电平输出)
- Configured as Input (输入)
- Input: High Resistance (高阻)
- Input: Pulled Low (拉低)
- Input: Pulled High (拉高)
- Configured as Output (输出)
如果外设开始是 Disabled
状态, 为了把它转换到 Input: High Resistance
模式, 我们要这么做:
- Disabled
- Enabled
- Configured as Input
- Input: High Resistance
如果我们想从 Input: High Resistance
状态到 Input: Pulled Low
状态, 我们需要:
- Input: High Resistance
- Input: Pulled Low
同样的, 如果我们想把一个 GPIO 从 Input: Pulled Low
设置到 Output: High
, 我们需要:
- Input: Pulled Low
- Configured as Input
- Configured as Output
- Output: High
硬件表示
通常, 上面列出来的状态是将给定的值写入到 GPIO 外设的寄存器上来实现的. 让我们来定义一个虚构的 GPIO 寄存器来说明一下:
Name | Bit Number(s) | Value | Meaning | Notes |
---|---|---|---|---|
enable | 0 | 0 | disabled | Disables the GPIO |
1 | enabled | Enables the GPIO | ||
direction | 1 | 0 | input | Sets the direction to Input |
1 | output | Sets the direction to Output | ||
input_mode | 2..3 | 00 | hi-z | Sets the input as high resistance |
01 | pull-low | Input pin is pulled low | ||
10 | pull-high | Input pin is pulled high | ||
11 | n/a | Invalid state. Do not set | ||
output_mode | 4 | 0 | set-low | Output pin is driven low |
1 | set-high | Output pin is driven high | ||
input_status | 5 | x | in-val | 0 if input is < 1.5v, 1 if input >= 1.5v |
我们可以在 Rust 中公开这个结构体来展示这个寄存器结构:
#![allow(unused)] fn main() { /// GPIO interface struct GpioConfig { /// GPIO Configuration structure generated by svd2rust 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 实际处于输入状态时, 我们将模式设置为输出会发生什么?
通常来说, 使用此结构体可以让我们达到状态机没有定义的状态: 例如, 被拉低的输出, 或者一个被设置为高电平的输入. 对于某些硬件, 这些可能不会起作用. 在其他硬件上, 这可能会导致 exception 或未定义行为.
尽管这个接口很方便, 但并不满足我们的设计.