組み込み Rust 入門を読んで実装していく
基礎から学ぶ組み込み Rust を読んで実装していく過程のスクラップ
Wio Terminal で UART 通信を実装する
とりあえず本書通りに実装していくのだが、mutable グローバル変数をいい感じに設定できないかクレートを探してみた。
以下のようなクレートがあった。
確かに定義としては使えるんだけども、設定した変数を別のモジュールなどで呼び出せるようにはなっていないようだったので、試してみたが断念した。MaybeUninit
というメモリの初期化がされているかどうかをいい感じにラップしてくれる core
にある構造体を使って初期化しているらしい。
本書通りに cortex_m
クレートの interrupt を使って、処理を書いてみる。interrupt::free
が実際何をしているかはまだ理解できないけど、static のような共有リソースを安全にアクセスできるようにしてくれるらしい。
// UART の初期化処理
pub fn init_uart(
uart: wio::Uart,
clocks: &mut GenericClockController,
selcom: wio::pac::SERCOM2,
mclk: &mut MCLK,
) {
let serials = uart.init(clocks, 115200.Hz(), selcom, mclk);
interrupt::free(|cs| {
let mut serial = SERIAL.borrow(cs).borrow_mut();
*serial = Some(serials);
});
}
あと、クレートバージョンを現時点で最新に近いものにしていることで、シグネチャというか実際のパラメータあたりがごっそり変わって、構築するのに時間がかかった。
[workspace.dependencies]
panic-halt = "1.0.0"
wio_terminal = "0.7.2"
embedded-hal = "1.0.0"
cortex-m = "0.7.7"
最終的にこうなった。
type UartConfig = Config<Pads<Sercom2, IoSet2, Pin<PB27, Alternate<C>>, Pin<PB26, Alternate<C>>>>;
static SERIAL: Mutex<RefCell<Option<Uart<UartConfig, Duplex>>>> = Mutex::new(RefCell::new(None));
type
で一旦エイリアスを使ったので、以下みたく長くて複雑だからという clippy の指摘に従った結果です。(こんなパラメーター書くことないから初めて出会った。)
warning: very complex type used. Consider factoring parts into `type` definitions
--> crates/driver/src/uart.rs:16:16
|
16 | static SERIAL: Mutex<
| ________________^
17 | | RefCell<
18 | | Option<
19 | | Uart<
... |
24 | | >,
25 | | > = Mutex::new(RefCell::new(None));
| |_^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
= note: `#[warn(clippy::type_complexity)]` on by default
グローバルで定義したものの、毎回グローバル変数から interrupt::free
をして書き込むのが面倒なので、いい感じに抽象化したかった。
そこで、著者のドキュメントで以下のように出会い、これを使わせてもらった。
最後に困ったことは、writeln!
が使えなかったこと。Uart
構造体に core::fmt::Write
trait が impl されてないらしく、write_fmt
がないらしい。以前はされてたのかな?とりあえず、write
で Byte ごとに書き込むようにした。
error[E0599]: the method `write_fmt` exists for mutable reference `&mut Uart<Config<Pads<SERCOM2, IoSet2, ..., ...>>, ...>`, but its trait bounds were not satisfied
--> crates/driver/src/uart.rs:49:22
|
49 | writeln!(s, "{}", c).unwrap();
| ^
|
::: /Users/noshishi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/atsamd-hal-0.16.0/src/sercom/uart.rs:602:1
|
602 | pub struct Uart<C, D>
| --------------------- doesn't satisfy `_: Write`
|
note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method
--> crates/driver/src/uart.rs:49:22
|
49 | writeln!(s, "{}", c).unwrap();
| ^
= note: the following trait bounds were not satisfied:
`wio_terminal::atsamd_hal::sercom::uart::Uart<wio_terminal::atsamd_hal::sercom::uart::Config<wio_terminal::atsamd_hal::sercom::uart::Pads<SERCOM2, IoSet2, wio_terminal::atsamd_hal::gpio::Pin<PB27, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>, wio_terminal::atsamd_hal::gpio::Pin<PB26, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>>>, wio_terminal::atsamd_hal::sercom::uart::Duplex>: core::fmt::Write`
which is required by `&mut wio_terminal::atsamd_hal::sercom::uart::Uart<wio_terminal::atsamd_hal::sercom::uart::Config<wio_terminal::atsamd_hal::sercom::uart::Pads<SERCOM2, IoSet2, wio_terminal::atsamd_hal::gpio::Pin<PB27, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>, wio_terminal::atsamd_hal::gpio::Pin<PB26, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>>>, wio_terminal::atsamd_hal::sercom::uart::Duplex>: core::fmt::Write`
= note: the full name for the type has been written to '/Users/noshishi/study/wio-demo/target/thumbv7em-none-eabihf/debug/deps/driver-c023946f5e4ae250.long-type-2331274042589001354.txt'
= note: consider using `--verbose` to print the full type name to the console