The Led and Delay abstractions

    The auxiliary crate, aux5, exposes an initialization function called init. When called thisfunction returns two values packed in a tuple: a Delay value and a Leds value.

    Delay can be used to block your program for a specified amount of milliseconds.

    Leds is actually an array of eight Leds. Each Led represents one of the LEDs on the F3 board,and exposes two methods: on and off which can be used to turn the LED on or off, respectively.

    Let’s try out these two abstractions by modifying the starter code to look like this:

    Now build it:

    1. $ cargo build --target thumbv7em-none-eabihf

    Now, we’ll repeat the flashing procedure that we did in the previous section:

    1. $ # this starts a GDB session of the program; no need to specify the path to the binary
    2. $ arm-none-eabi-gdb -q target/thumbv7em-none-eabihf/debug/led-roulette
    3. Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette...done.
    4. (gdb) target remote :3333
    5. Remote debugging using :3333
    6. (..)
    7. (gdb) load
    8. Loading section .vector_table, size 0x188 lma 0x8000000
    9. Loading section .text, size 0x3fc6 lma 0x8000188
    10. Loading section .rodata, size 0xa0c lma 0x8004150
    11. Start address 0x8000188, load size 19290
    12. Transfer rate: 19 KB/sec, 4822 bytes/write.
    13. (gdb) break main
    14. Breakpoint 1 at 0x800018c: file src/05-led-roulette/src/main.rs, line 9.
    15. (gdb) continue
    16. Continuing.
    17. Note: automatically using hardware breakpoints for read-only addresses.
    1. (gdb) next
    2. 11 let half_period = 500_u16;
    3. (gdb) next
    4. 13 loop {
    5. (gdb) next
    6. 14 leds[0].on();
    7. (gdb) next
    8. 15 delay.delay_ms(half_period);

    After executing the leds[0].on() statement, you should see a red LED, the one pointing North,turn on.

    Let’s continue stepping over the program:

    The delay_ms call will block the program for half a second but you may not notice because thenext command also takes some time to execute. However, after stepping over the leds[0].off()statement you should see the red LED turn off.

    You can already guess what this program does. Let it run uninterrupted using the continue command.

    1. (gdb) continue
    2. Continuing.

    Now, let’s do something more interesting. We are going to modify the behavior of our program usingGDB.

    First, let’s stop the infinite loop by hitting Ctrl+C. You’ll probably end up somewhere insideLed::on, Led::off or delay_ms:

    1. Program received signal SIGINT, Interrupt.
    2. 0x080033f6 in core::ptr::read_volatile (src=0xe000e010) at /checkout/src/libcore/ptr.rs:472
    3. 472 /checkout/src/libcore/ptr.rs: No such file or directory.

    In my case, the program stopped its execution inside a read_volatile function. GDB output showssome interesting information about that: core::ptr::read_volatile (src=0xe000e010). This meansthat the function comes from the core crate and that it was called with argument src = 0xe000e010.

    1. (gdb) info args
    2. src = 0xe000e010

    Regardless of where your program may have stopped you can always look at the output of thebacktrace command (bt for short) to learn how it got there:

    will print a trace of function calls from the current function down to main.

    Back to our topic. To do what we are after, first, we have to return to the main function. We cando that using the finish command. This command resumes the program execution and stops it againright after the program returns from the current function. We’ll have to call it several times.

    1. (gdb) finish
    2. cortex_m::peripheral::syst::<impl cortex_m::peripheral::SYST>::has_wrapped (self=0x10001fbc)
    3. at $REGISTRY/cortex-m-0.5.7/src/peripheral/syst.rs:124
    4. 124 self.csr.read() & SYST_CSR_COUNTFLAG != 0
    5. Value returned is $1 = 5
    6. (gdb) finish
    7. Run till exit from #0 cortex_m::peripheral::syst::<impl cortex_m::peripheral::SYST>::has_wrapped (
    8. self=0x10001fbc)
    9. at $REGISTRY/cortex-m-0.5.7/src/peripheral/syst.rs:124
    10. 0x08002d9c in <stm32f30x_hal::delay::Delay as embedded_hal::blocking::delay::DelayUs<u32>>::delay_us (
    11. self=0x10001fbc, us=500000)
    12. at $REGISTRY/stm32f30x-hal-0.2.0/src/delay.rs:58
    13. 58 while !self.syst.has_wrapped() {}
    14. Value returned is $2 = false
    15. (..)
    16. (gdb) finish
    17. Run till exit from #0 0x08002d0e in <stm32f30x_hal::delay::Delay as embedded_hal::blocking::delay::DelayMs<u16>>::delay_ms (self=0x10001fbc, ms=500)
    18. at $REGISTRY/stm32f30x-hal-0.2.0/src/delay.rs:38
    19. 0x080001ee in main () at src/05-led-roulette/src/main.rs:18
    20. 18 delay.delay_ms(half_period);

    We are back in main. We have a local variable in here: half_period

    1. (gdb) info locals
    2. half_period = 500
    3. delay = (..)
    4. leds = (..)

    Now, we are going to modify this variable using the set command:

    1. (gdb) set half_period = 100
    2. $1 = 100

    If you let program run free again using the continue command, you should see that the LED willblink at a much faster rate now!

    Question! What happens if you keep lowering the value of half_period? At what value of you can no longer see the LED blink?