Open2

組み込み Rust 入門を読んで実装していく

noshishinoshishi

Wio Terminal で UART 通信を実装する

とりあえず本書通りに実装していくのだが、mutable グローバル変数をいい感じに設定できないかクレートを探してみた。
以下のようなクレートがあった。
https://crates.io/crates/static_cell

確かに定義としては使えるんだけども、設定した変数を別のモジュールなどで呼び出せるようにはなっていないようだったので、試してみたが断念した。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 をして書き込むのが面倒なので、いい感じに抽象化したかった。

そこで、著者のドキュメントで以下のように出会い、これを使わせてもらった。
https://tomoyuki-nakabayashi.github.io/embedded-rust-techniques/03-bare-metal/print.html

最後に困ったことは、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