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

LedDelay の抽象化

これから、LEDルーレットアプリケーションを実装するために使用する、2つの高水準の抽象化を紹介します。

補助クレート aux5 は、init という初期化関数を公開しています。この関数を呼び出すと、タプルにまとめられた2つの値、Delay 値と LedArray 値が返されます。

Delay は、指定したミリ秒数の間プログラムをブロックするために使用できます。

LedArray は、8個の Led からなる配列です。各 Led は F3 ボード上の1つのLEDを表し、2つのメソッド onoff を公開しています。これらを使うと、それぞれLEDをオンまたはオフにできます。

では、スターターコードを次のように変更して、この2つの抽象化を試してみましょう。

#![deny(unsafe_code)]
#![no_main]
#![no_std]

use aux5::{entry, Delay, DelayMs, LedArray, OutputSwitch};

#[entry]
fn main() -> ! {
    let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

    let half_period = 500_u16;

    loop {
        leds[0].on().ok();
        delay.delay_ms(half_period);

        leds[0].off().ok();
        delay.delay_ms(half_period);
    }
}

ではビルドします:

cargo build

NOTE: GDB セッションを開始する 前に プログラムを再ビルドするのを忘れてしまうことがあります。この見落としは、非常に混乱しやすいデバッグセッションにつながる可能性があります。この問題を避けるために、cargo build の代わりに cargo run を実行するだけでかまいません。cargo run コマンドはビルドを行い、さらに デバッグセッションも開始するため、プログラムの再コンパイルを忘れずに済みます。

では、新しいプログラムで前の節と同じように実行し、フラッシュ手順を繰り返しましょう。cargo run は自分で入力してみてください。これもすぐに楽になります。:)

NOTE: 別のターミナルで openocd(デバッガー)を起動するのを忘れないでください。
そうしないと target remote :3333 は動作しません!

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `arm-none-eabi-gdb -q ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette...

(gdb) target remote :3333
Remote debugging using :3333
led_roulette::__cortex_m_rt_main_trampoline () at ~/embedded-discovery/src/05-led-roulette/src/main.rs:7
7       #[entry]

(gdb) load
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x52c0 lma 0x8000194
Loading section .rodata, size 0xb50 lma 0x8005454
Start address 0x08000194, load size 24484
Transfer rate: 21 KB/sec, 6121 bytes/write.

(gdb) break main
Breakpoint 1 at 0x8000202: file ~/embedded-discovery/src/05-led-roulette/src/main.rs, line 7.
Note: automatically using hardware breakpoints for read-only addresses.

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main_trampoline ()
    at ~/embedded-discovery/src/05-led-roulette/src/main.rs:7
7       #[entry]

(gdb) step
led_roulette::__cortex_m_rt_main () at ~/embedded-discovery/src/05-led-roulette/src/main.rs:9
9           let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

(gdb)

OK。コードをステップ実行していきましょう。今回は step ではなく next コマンドを使います。違いは、next コマンドは関数呼び出しの中に入るのではなく、それを 飛び越えて ステップ実行することです。

(gdb) next
11          let half_period = 500_u16;

(gdb) next
13          loop {

(gdb) next
14              leds[0].on().ok();

(gdb) next
15              delay.delay_ms(half_period);

leds[0].on().ok() 文を実行した後、北を向いた赤色LEDが点灯するはずです。

そのままプログラムをステップオーバーしていきましょう。

(gdb) next
17              leds[0].off().ok();

(gdb) next
18              delay.delay_ms(half_period);

delay_ms の呼び出しはプログラムを0.5秒間ブロックしますが、next コマンド自体の実行にも少し時間がかかるため、気づかないかもしれません。ただし、leds[0].off() 文をステップオーバーした後には、赤色LEDが消灯するはずです。

このプログラムが何をするかは、もう想像できるでしょう。continue コマンドを使って、中断せずに実行させてみましょう。

(gdb) continue
Continuing.

では、もっと面白いことをしてみましょう。GDB を使って、プログラムの挙動を変更します。

まず、Ctrl+C を押して無限ループを止めましょう。おそらく Led::onLed::offdelay_ms のどこかで停止します。

^C
Program received signal SIGINT, Interrupt.
0x08003434 in core::ptr::read_volatile<u32> (src=0xe000e010)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1053

私の場合、プログラムは read_volatile 関数の中で実行を停止しました。GDB の出力には、そのことに関する興味深い情報が表示されています: core::ptr::read_volatile (src=0xe000e010)。これは、その関数が core クレート由来であり、引数 src = 0xe000e010 を伴って呼び出されたことを意味します。

補足すると、関数の引数をより明示的に表示するには info args コマンドを使います。

(gdb) info args
src = 0xe000e010

プログラムがどこで停止していても、backtrace コマンド(短縮形は bt)の出力を見れば、そこに至るまでの経路をいつでも確認できます。

(gdb) backtrace
#0  0x08003434 in core::ptr::read_volatile<u32> (src=0xe000e010)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1053
#1  0x08002d66 in vcell::VolatileCell<u32>::get<u32> (self=0xe000e010) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/vcell-0.1.3/src/lib.rs:33
#2  volatile_register::RW<u32>::read<u32> (self=0xe000e010) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/volatile-register-0.2.0/src/lib.rs:75
#3  cortex_m::peripheral::SYST::has_wrapped (self=0x20009fa4)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/peripheral/syst.rs:136
#4  0x08003004 in stm32f3xx_hal::delay::{{impl}}::delay_us (self=0x20009fa4, us=500000)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:58
#5  0x08002f3e in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:32
#6  0x08002f80 in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:38
#7  0x0800024c in led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:15
#8  0x08000206 in led_roulette::__cortex_m_rt_main_trampoline () at src/05-led-roulette/src/main.rs:7

backtrace は、現在の関数から main までの関数呼び出しのトレースを表示します。

本題に戻りましょう。やりたいことを行うには、まず main 関数に戻る必要があります。それには finish コマンドを使えます。このコマンドはプログラムの実行を再開し、現在の関数からプログラムが戻った直後に再び停止します。これを数回呼び出す必要があります。

(gdb) finish Run till exit from #0 0x08003434 in core::ptr::read_volatile (src=0xe000e010) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1053 cortex_m::peripheral::SYST::has_wrapped (self=0x20009fa4) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/peripheral/syst.rs:136 136 self.csr.read() & SYST_CSR_COUNTFLAG != 0 Value returned is $1 = 5

(..)

(gdb) finish Run till exit from #0 0x08002f3e in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:32 0x08002f80 in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:38 38 self.delay_ms(u32(ms));

(gdb) finish Run till exit from #0 0x08002f80 in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:38 0x0800024c in led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:15 15 delay.delay_ms(half_period);


`main` に戻ってきました。ここにはローカル変数 `half_period` があります。

(gdb) print half_period $3 = 500


では、`set` コマンドを使ってこの変数を変更してみましょう。

(gdb) set half_period = 100

(gdb) print half_period $5 = 100


`continue` コマンドを使ってプログラムを再びそのまま実行させると、LED が今度はずっと速く
点滅するのが **見えるかもしれません** が、おそらく点滅速度は変わっていません。**何が起きたのでしょうか?**

`Ctrl+C` でプログラムを停止し、その後 `main:14` にブレークポイントを設定しましょう。
``` console
(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
core::cell::UnsafeCell<u32>::get<u32> (self=0x20009fa4)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:1711
1711        pub const fn get(&self) -> *mut T {

次に、main.rs:14 にブレークポイントを設定して、continue を実行します。

(gdb) break main.rs:14
Breakpoint 2 at 0x8000236: file src/05-led-roulette/src/main.rs, line 14.
(gdb) continue
Continuing.

Breakpoint 2, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:14
14              leds[0].on().ok();

次に、可能であれば端末ウィンドウを縦約 80 行、横約 170 文字になるように開いてください。

: そこまで大きく端末を開けなくても問題ありません。その場合は --Type <RET> for more, q to quit, c to continue without paging-- と表示されるので、 (gdb) プロンプトが見えるまで return を入力してください。その後、端末ウィンドウを スクロールして結果を確認してください。

(gdb) disassemble /m
Dump of assembler code for function _ZN12led_roulette18__cortex_m_rt_main17h51e7c3daad2af251E:
8       fn main() -> ! {
   0x08000208 <+0>:     push    {r7, lr}
   0x0800020a <+2>:     mov     r7, sp
   0x0800020c <+4>:     sub     sp, #64 ; 0x40
   0x0800020e <+6>:     add     r0, sp, #32

9           let (mut delay, mut leds): (Delay, LedArray) = aux5::init();
   0x08000210 <+8>:     bl      0x8000302 <aux5::init>
   0x08000214 <+12>:    b.n     0x8000216 <led_roulette::__cortex_m_rt_main+14>
   0x08000216 <+14>:    add     r0, sp, #32
   0x08000218 <+16>:    add     r1, sp, #4
   0x0800021a <+18>:    ldmia.w r0, {r2, r3, r4, r12, lr}
   0x0800021e <+22>:    stmia.w r1, {r2, r3, r4, r12, lr}
   0x08000222 <+26>:    ldr     r0, [sp, #52]   ; 0x34
   0x08000224 <+28>:    ldr     r1, [sp, #56]   ; 0x38
   0x08000226 <+30>:    str     r1, [sp, #28]
   0x08000228 <+32>:    str     r0, [sp, #24]
   0x0800022a <+34>:    mov.w   r0, #500        ; 0x1f4

10
11          let half_period = 500_u16;
   0x0800022e <+38>:    strh.w  r0, [r7, #-2]

12
13          loop {
   0x08000232 <+42>:    b.n     0x8000234 <led_roulette::__cortex_m_rt_main+44>
   0x08000234 <+44>:    add     r0, sp, #24
   0x08000268 <+96>:    b.n     0x8000234 <led_roulette::__cortex_m_rt_main+44>

14              leds[0].on().ok();
=> 0x08000236 <+46>:    bl      0x80001ec <switch_hal::output::{{impl}}::on<stm32f3xx_hal::gpio::gpioe::PEx<stm32f3xx_hal::gpio::Output<stm32f3xx_hal::gpio::PushPull>>>>
   0x0800023a <+50>:    b.n     0x800023c <led_roulette::__cortex_m_rt_main+52>
   0x0800023c <+52>:    bl      0x8000594 <core::result::Result<(), core::convert::Infallible>::ok<(),core::convert::Infallible>>
   0x08000240 <+56>:    b.n     0x8000242 <led_roulette::__cortex_m_rt_main+58>
   0x08000242 <+58>:    add     r0, sp, #4
   0x08000244 <+60>:    mov.w   r1, #500        ; 0x1f4

15              delay.delay_ms(half_period);
   0x08000248 <+64>:    bl      0x8002f5c <stm32f3xx_hal::delay::{{impl}}::delay_ms>
   0x0800024c <+68>:    b.n     0x800024e <led_roulette::__cortex_m_rt_main+70>
   0x0800024e <+70>:    add     r0, sp, #24

16
17              leds[0].off().ok();
   0x08000250 <+72>:    bl      0x800081a <switch_hal::output::{{impl}}::off<stm32f3xx_hal::gpio::gpioe::PEx<stm32f3xx_hal::gpio::Output<stm32f3xx_hal::gpio::PushPull>>>>
   0x08000254 <+76>:    b.n     0x8000256 <led_roulette::__cortex_m_rt_main+78>
   0x08000256 <+78>:    bl      0x8000594 <core::result::Result<(), core::convert::Infallible>::ok<(),core::convert::Infallible>>
   0x0800025a <+82>:    b.n     0x800025c <led_roulette::__cortex_m_rt_main+84>
   0x0800025c <+84>:    add     r0, sp, #4
   0x0800025e <+86>:    mov.w   r1, #500        ; 0x1f4

18              delay.delay_ms(half_period);
   0x08000262 <+90>:    bl      0x8002f5c <stm32f3xx_hal::delay::{{impl}}::delay_ms>
   0x08000266 <+94>:    b.n     0x8000268 <led_roulette::__cortex_m_rt_main+96>

End of assembler dump.

上のダンプで遅延が変わらなかった理由は、コンパイラが half_period は変化しないと 認識し、その結果 delay.delay_ms(half_period); が呼ばれている 2 か所で mov.w r1, #500 が見えているためです。つまり、half_period の値を変更しても 何も起こりません。

   0x08000244 <+60>:    mov.w   r1, #500        ; 0x1f4

15              delay.delay_ms(half_period);
   0x08000248 <+64>:    bl      0x8002f5c <stm32f3xx_hal::delay::{{impl}}::delay_ms>

(..)

   0x0800025e <+86>:    mov.w   r1, #500        ; 0x1f4

18              delay.delay_ms(half_period);
   0x08000262 <+90>:    bl      0x8002f5c <stm32f3xx_hal::delay::{{impl}}::delay_ms>

この問題に対する 1 つの解決策は、以下に示すように half_periodVolatile でラップすることです。

#![deny(unsafe_code)]
#![no_main]
#![no_std]

use volatile::Volatile;
use aux5::{Delay, DelayMs, LedArray, OutputSwitch, entry};

#[entry]
fn main() -> ! {
    let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

    let mut half_period = 500_u16;
    let v_half_period = Volatile::new(&mut half_period);

    loop {
        leds[0].on().ok();
        delay.delay_ms(v_half_period.read());

        leds[0].off().ok();
        delay.delay_ms(v_half_period.read());
    }
}

Cargo.toml[dependencies] セクションに volatile = "0.4.3" を追加してください。

[dependencies]
aux5 = { path = "auxiliary" }
volatile = "0.4.3"

上記のコードで Volatile を使うと、half_period を変更できるようになり、 さまざまな値を試せるようになります。以下にコマンドの一覧を示し、その後で 説明します。# xxxx は説明のためのものです。

$ cargo run --target thumbv7em-none-eabihf   # プログラムをコンパイルして gdb に読み込む
(gdb) target remote :3333           # PC から STM32F3DISCOVERY ボードに接続する
(gdb) load                          # プログラムを書き込む
(gdb) break main.rs:16              # ループの先頭にブレークポイント 1 を設定する
(gdb) continue                      # 続行。main.rs:16 で停止する
(gdb) disable 1                     # ブレークポイント 1 を無効にする
(gdb) set print asm-demangle on     # asm-demangle を有効にする
(gdb) disassemble /m                # main 関数を逆アセンブルする
(gdb) continue                      # LED が 1/2 秒点灯し、その後 1/2 秒消灯する
^C                                  # Ctrl+C で停止する
(gdb) enable 1                      # ブレークポイント 1 を有効にする
(gdb) continue                      # 続行。main.rs:16 で停止する
(gdb) print half_period             # half_period を表示する。結果は 500
(gdb) set half_period = 2000        # half_period を 2000ms に設定する
(gdb) print half_period             # half_period を表示する。結果は 2000
(gdb) disable 1                     # ブレークポイント 1 を無効にする
(gdb) continue                      # LED が 2 秒点灯し、その後 2 秒消灯する
^C                                  # Ctrl+C で停止する
(gdb) quit                          # gdb を終了する

重要な変更点はソースコードの 13、17、20 行目にあり、これは 逆アセンブル結果で確認できます。13 行目では v_half_period を作成し、その後 17 行目と 20 行目でその値を read() しています。これは、set half_period = 2000 を実行すると、LED が 2 秒間点灯し、その後 2 秒間消灯するようになることを意味します。

$ cargo run --target thumbv7em-none-eabihf
   Compiling led-roulette v0.2.0 (~/embedded-discovery/src/05-led-roulette)
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s
     Running `arm-none-eabi-gdb -q ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette...

(gdb) target remote :3333
Remote debugging using :3333
led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) load
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x5258 lma 0x8000194
Loading section .rodata, size 0xbd8 lma 0x80053ec
Start address 0x08000194, load size 24516
Transfer rate: 21 KB/sec, 6129 bytes/write.

(gdb) break main.rs:16
Breakpoint 1 at 0x8000246: file src/05-led-roulette/src/main.rs, line 16.
Note: automatically using hardware breakpoints for read-only addresses.

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) disable 1

(gdb) set print asm-demangle on

(gdb) disassemble /m
Dump of assembler code for function _ZN12led_roulette18__cortex_m_rt_main17he1f2bc7990b13731E:
9       fn main() -> ! {
   0x0800020e <+0>:     push    {r7, lr}
   0x08000210 <+2>:     mov     r7, sp
   0x08000212 <+4>:     sub     sp, #72 ; 0x48
   0x08000214 <+6>:     add     r0, sp, #36     ; 0x24

10          let (mut delay, mut leds): (Delay, LedArray) = aux5::init();
   0x08000216 <+8>:     bl      0x800036a <aux5::init>
   0x0800021a <+12>:    b.n     0x800021c <led_roulette::__cortex_m_rt_main+14>
   0x0800021c <+14>:    add     r0, sp, #36     ; 0x24
   0x0800021e <+16>:    add     r1, sp, #8
   0x08000220 <+18>:    ldmia.w r0, {r2, r3, r4, r12, lr}
   0x08000224 <+22>:    stmia.w r1, {r2, r3, r4, r12, lr}
   0x08000228 <+26>:    ldr     r0, [sp, #56]   ; 0x38
   0x0800022a <+28>:    ldr     r1, [sp, #60]   ; 0x3c
   0x0800022c <+30>:    str     r1, [sp, #32]
   0x0800022e <+32>:    str     r0, [sp, #28]
   0x08000230 <+34>:    mov.w   r0, #500        ; 0x1f4

11
12          let mut half_period = 500_u16;
   0x08000234 <+38>:    strh.w  r0, [r7, #-6]
   0x08000238 <+42>:    subs    r0, r7, #6

13          let v_half_period = Volatile::new(&mut half_period);
   0x0800023a <+44>:    bl      0x800033e <volatile::Volatile<&mut u16, volatile::access::ReadWrite>::new<&mut u16>>
   0x0800023e <+48>:    str     r0, [sp, #68]   ; 0x44
   0x08000240 <+50>:    b.n     0x8000242 <led_roulette::__cortex_m_rt_main+52>

14
15          loop {
   0x08000242 <+52>:    b.n     0x8000244 <led_roulette::__cortex_m_rt_main+54>
   0x08000244 <+54>:    add     r0, sp, #28
   0x08000288 <+122>:   b.n     0x8000244 <led_roulette::__cortex_m_rt_main+54>

16              leds[0].on().ok();
=> 0x08000246 <+56>:    bl      0x800032c <switch_hal::output::{{impl}}::on<stm32f3xx_hal::gpio::gpioe::PEx<stm32f3xx_hal::gpio::Output<stm32f3xx_hal::gpio::PushPull>>>>
   0x0800024a <+60>:    b.n     0x800024c <led_roulette::__cortex_m_rt_main+62>
   0x0800024c <+62>:    bl      0x80005fc <core::result::Result<(), core::convert::Infallible>::ok<(),core::convert::Infallible>>
   0x08000250 <+66>:    b.n     0x8000252 <led_roulette::__cortex_m_rt_main+68>
   0x08000252 <+68>:    add     r0, sp, #68     ; 0x44

17              delay.delay_ms(v_half_period.read());
   0x08000254 <+70>:    bl      0x800034a <volatile::Volatile<&mut u16, volatile::access::ReadWrite>::read<&mut u16,u16,volatile::access::ReadWrite>>
   0x08000258 <+74>:    str     r0, [sp, #4]
   0x0800025a <+76>:    b.n     0x800025c <led_roulette::__cortex_m_rt_main+78>
   0x0800025c <+78>:    add     r0, sp, #8
   0x0800025e <+80>:    ldr     r1, [sp, #4]
   0x08000260 <+82>:    bl      0x8002fc4 <stm32f3xx_hal::delay::{{impl}}::delay_ms>
   0x08000264 <+86>:    b.n     0x8000266 <led_roulette::__cortex_m_rt_main+88>
   0x08000266 <+88>:    add     r0, sp, #28

18
19              leds[0].off().ok();
   0x08000268 <+90>:    bl      0x8000882 <switch_hal::output::{{impl}}::off<stm32f3xx_hal::gpio::gpioe::PEx<stm32f3xx_hal::gpio::Output<stm32f3xx_hal::gpio::PushPull>>>>
   0x0800026c <+94>:    b.n     0x800026e <led_roulette::__cortex_m_rt_main+96>
   0x0800026e <+96>:    bl      0x80005fc <core::result::Result<(), core::convert::Infallible>::ok<(),core::convert::Infallible>>
   0x08000272 <+100>:   b.n     0x8000274 <led_roulette::__cortex_m_rt_main+102>
   0x08000274 <+102>:   add     r0, sp, #68     ; 0x44

20              delay.delay_ms(v_half_period.read());
   0x08000276 <+104>:   bl      0x800034a <volatile::Volatile<&mut u16, volatile::access::ReadWrite>::read<&mut u16,u16,volatile::access::ReadWrite>>
   0x0800027a <+108>:   str     r0, [sp, #0]
   0x0800027c <+110>:   b.n     0x800027e <led_roulette::__cortex_m_rt_main+112>
   0x0800027e <+112>:   add     r0, sp, #8
   0x08000280 <+114>:   ldr     r1, [sp, #0]
   0x08000282 <+116>:   bl      0x8002fc4 <stm32f3xx_hal::delay::{{impl}}::delay_ms>
   0x08000286 <+120>:   b.n     0x8000288 <led_roulette::__cortex_m_rt_main+122>

End of assembler dump.

(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x080037b2 in core::cell::UnsafeCell<u32>::get<u32> (self=0x20009fa0) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:1716
1716        }

(gdb) enable 1

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) print half_period
$2 = 500

(gdb) disable 1

(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x08003498 in core::ptr::read_volatile<u32> (src=0xe000e010) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1052
1052        unsafe { intrinsics::volatile_load(src) }

(gdb) enable 1

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) print half_period
$3 = 500

(gdb) set half_period = 2000

(gdb) print half_period
$4 = 2000

(gdb) disable 1

(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x0800348e in core::ptr::read_volatile<u32> (src=0xe000e010) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1046
1046    pub unsafe fn read_volatile<T>(src: *const T) -> T {

(gdb) q
Detaching from program: ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette, Remote target
Ending remote debugging.
[Inferior 1 (Remote target) detached]

質問です!half_period の値を下げ始めると何が起こりますか?half_period が いくつになると、LED の点滅が見えなくなりますか?

では、今度はあなたがプログラムを書く番です。