Pro Micro上のLEDをRustでLチカ

RustでPro Microのキーボードのファームウェアをつくりたい（車輪の再発明したい）と思ったため、前準備としてLチカさせました。

# 環境構築

avr-halを使用しますので、こちらを見ながら、環境構築しました。


https://github.com/Rahix/avr-hal

# テンプレート

```
cargo generate --git https://github.com/Rahix/avr-hal-template.git
```

こちらでテンプレートのプロジェクトを作成。

ボードは`SparkFun ProMicro`を選択してあります。

# 動かし方

`cargo run`でビルド、書き込みを行うのですが、環境によるかもしれませんが、わたしのケースではポートを指定する必要がありました。

ravedudeへポートを情報を渡す必要があるため、`cargo run -- -P COM5`という形式で実行しました。

今回はPro Micro本体のみで試しているため、ドライバーでGNDとRSTピンをショートさせて、書き込み待機状態にさせます。

```
PS E:\github\temp> cargo run -- -P COM5
    Finished `dev` profile [optimized + debuginfo] target(s) in 0.22s
     Running `ravedude promicro target\avr-atmega32u4\debug\temp.elf -P COM5`
       Board SparkFun Pro Micro
Warning: this board cannot reset itself.

    Reset the board by quickly pressing the reset button **twice**.

Once reset, press ENTER here:
 Programming target\avr-atmega32u4\debug\temp.elf => COM5
Reading 328 bytes for flash from input file temp.elf
Writing 328 bytes to flash
Writing | ################################################## | 100% 0.03 s 
Reading | ################################################## | 100% 0.00 s 
328 bytes of flash verified

Avrdude done.  Thank you.
  Programmed target\avr-atmega32u4\debug\temp.elf
```

ポートを指定しなかった場合は以下のエラーになりました。

<details><summary>ポートを指定しなかった場合のログ</summary>

```
    Finished `dev` profile [optimized + debuginfo] target(s) in 0.27s
     Running `ravedude promicro target\avr-atmega32u4\debug\temp.elf`
       Board SparkFun Pro Micro
Warning: this board cannot reset itself.

    Reset the board by quickly pressing the reset button **twice**.

Once reset, press ENTER here:
Error: no matching serial port found, use -P or set RAVEDUDE_PORT in your environment

Caused by: Serial port not found.
error: process didn't exit successfully: `ravedude promicro target\avr-atmega32u4\debug\temp.elf` (exit code: 1)
```
</details>

ポート番号は環境依存な気がするので、お試しする方はご自分の環境のものを調べてください。

Windows11環境であれば、デバイスマネージャーの「ポート（COMとLPT）」を見ながら、ボードをリセットして、出現するポートを指定するといいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821654/61ed8321-ca14-c58c-a02e-cb59cbbf04e1.png)

これで、サンプルコードでのLチカに成功しました。

# Arduinoを使用しないようにする

テンプレートでは`arduino_hal`を使用しているため、次に`atmega_hal`を使用するケースを試して見ます。

Cargo.tomlを以下のようにモジュールを追加したり、書き換えたりします。

```diff:Cargo.toml
[dependencies]
panic-halt = "0.2.0"
ufmt = "0.2.0"
nb = "1.1.0"
embedded-hal = "1.0"
+ avr-device-macros = "0.7.0"

- [dependencies.arduino-hal]
+ [dependencies.atmega-hal]
git = "https://github.com/rahix/avr-hal"
rev = "3c089795cadbbc7fa83f45958128689fee7ba1e4"
- features = ["arduino-leonardo"]
+ features = ["atmega32u4"]
```

ソースコード本体は、試行錯誤した結果、以下のようになりました。

```rust:main.rs
#![no_std]
#![no_main]

use atmega_hal::delay::Delay;
use embedded_hal::delay::DelayNs;
type Clock = atmega_hal::clock::MHz16;
use panic_halt as _;

fn delay(ms: u32) {
    let mut delay = Delay::<Clock>::new();
    delay.delay_ms(ms);
}

#[avr_device_macros::entry]
fn main() -> ! {
    let dp = atmega_hal::Peripherals::take().unwrap();
    let pins = atmega_hal::pins!(dp);

    let mut led = pins.pb0.into_output();

    loop {
        led.toggle();
        delay(500);
    }
}
```

これで同様に書きこんで実行すると、無事Lチカに成功しました。



# 他のLEDも光らせる

https://www.switch-science.com/products/1623?srsltid=AfmBOoq7romLeV5sBrI6dmbzEGI3W5UaDDFYXgtljEUWykPNsghzxWXX

スイッチサイエンスさんで確認できる回路図を確認すると、LED二つはPB0とPD5につながっていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821654/6a83e32f-082a-b626-fd37-4915b5e4ecc1.png)

この情報を元にして、以下のようにすると二つのLEDが交互に光りました。

```
fn main() -> ! {
    let dp = atmega_hal::Peripherals::take().unwrap();
    let pins = atmega_hal::pins!(dp);

    let mut led1 = pins.pb0.into_output();
    let mut led2 = pins.pd5.into_output();

    led1.toggle();

    loop {
        led1.toggle();
        led2.toggle();
        delay(500);
    }
}
```

# 終わりに

以上で簡単ですがLチカ作業完了です。

ネットでググっていると、arduino_halベースで書いているケースは多く見られましたが、atmega_halベースのものは少なかったため、今回書いてみました。

続いて、USBデバイス作成に取りかかりたいと思います。