From 20b30525b04152f7fffc7c9960736fa1478b3aa0 Mon Sep 17 00:00:00 2001 From: Adam Green Date: Fri, 16 Nov 2018 23:36:46 -0800 Subject: [PATCH 1/3] A few minor updates to Chapter 2 text --- src/start/hardware.md | 2 +- src/start/registers.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/start/hardware.md b/src/start/hardware.md index ff161cc..eb881b9 100644 --- a/src/start/hardware.md +++ b/src/start/hardware.md @@ -93,7 +93,7 @@ $ cargo build --example hello Debugging will look a bit different. In fact, the first steps can look different depending on the target device. In this section we'll show the steps required to debug a program running on the STM32F3DISCOVERY. This is meant to serve as a -reference; for device specific about debugging check out [the +reference; for device specific information about debugging check out [the Debugonomicon](https://github.com/rust-embedded/debugonomicon). As before we'll do remote debugging and the client will be a GDB process. This diff --git a/src/start/registers.md b/src/start/registers.md index ce0d871..f41c8f9 100644 --- a/src/start/registers.md +++ b/src/start/registers.md @@ -6,7 +6,7 @@ You may well find that the code you need to access the peripherals in your micro * Micro-architecture Crate - This sort of crate handles any useful routines common to the processor core your microcontroller is using, as well as any peripherals that are common to all micro-controllers that use that particular type of processor core. For example the [cortex-m] crate gives you functions to enable and disable interrupts, which are the same for all Cortex-M based micro-controllers. It also gives you access to the 'SysTick' peripheral included with all Cortex-M based micro-controllers. * Peripheral Access Crate (PAC) - This sort of crate is a thin wrapper over the various memory-wrapper registers defined for your particular part-number of micro-controller you are using. For example, [tm4c123x] for the Texas Instruments Tiva-C TM4C123 series, or [stm32f30x] for the ST-Micro STM32F30x series. Here, you'll be interacting with the registers directly, following each peripheral's operating instructions given in your micro-controller's Technical Reference Manual. -* HAL Crate - These crates offer a more user-friendly API for your particular processor, often by implementing some common traits defined in [embedded-hal]. For example, this crate might offer a `Serial` struct, with a constructor that takes an appropriate set of GPIO pins and a board rate, and offers some sort of `write_byte` function for sending data. See the chapter on [Portability] for more information on [embedded-hal]. +* HAL Crate - These crates offer a more user-friendly API for your particular processor, often by implementing some common traits defined in [embedded-hal]. For example, this crate might offer a `Serial` struct, with a constructor that takes an appropriate set of GPIO pins and a baud rate, and offers some sort of `write_byte` function for sending data. See the chapter on [Portability] for more information on [embedded-hal]. * Board Crate - These crates go one step further than a HAL Crate by pre-configuring various peripherals and GPIO pins to suit the specific developer kit or board you are using, such as [F3] for the STM32F3DISCOVERY board. [cortex-m]: https://crates.io/crates/cortex-m @@ -73,7 +73,7 @@ pub fn init() -> (Delay, Leds) { ``` -We've access the `PWM0` peripheral in exactly the same as as we access the `SYST` peripheral earlier, except we called `tm4c123x::Peripherals::take()`. As this crate was auto-generated using [svd2rust], the access functions for our register fields take a closure, rather than a numeric argument. While this looks like a lot of code, the Rust compiler can use it to perform a bunch of checks for us, but then generate machine-code which is pretty close to hand-written assembler! Where the auto-generated code isn't able to determine that all possible arguments to a particular accessor function are valid (for example, if the SVD defines the register as 32-bit but doesn't say if some of those 32-bit values have a special meaning), then the function is marked as `unsafe`. We can see this in the example above when setting the `load` and `compa` sub-fields using the `bits()` function. +We've accessed the `PWM0` peripheral in exactly the same way as we accessed the `SYST` peripheral earlier, except we called `tm4c123x::Peripherals::take()`. As this crate was auto-generated using [svd2rust], the access functions for our register fields take a closure, rather than a numeric argument. While this looks like a lot of code, the Rust compiler can use it to perform a bunch of checks for us, but then generate machine-code which is pretty close to hand-written assembler! Where the auto-generated code isn't able to determine that all possible arguments to a particular accessor function are valid (for example, if the SVD defines the register as 32-bit but doesn't say if some of those 32-bit values have a special meaning), then the function is marked as `unsafe`. We can see this in the example above when setting the `load` and `compa` sub-fields using the `bits()` function. ### Reading @@ -95,7 +95,7 @@ pwm.ctl.write(|w| w.globalsync0().clear_bit()); ### Modifying -If we wish to change only on particular sub-field in this register and leave the other sub-fields unchanged, we can use the `modify` function. This function takes a closure with two arguments - one for reading and one for writing. Typically we call these `r` and `w` respectively. The `r` argument can be used to inspect the current contents of the register, and the `w` argument can be used to modify the register contents. +If we wish to change only one particular sub-field in this register and leave the other sub-fields unchanged, we can use the `modify` function. This function takes a closure with two arguments - one for reading and one for writing. Typically we call these `r` and `w` respectively. The `r` argument can be used to inspect the current contents of the register, and the `w` argument can be used to modify the register contents. ```rust pwm.ctl.modify(|r, w| w.globalsync0().clear_bit()); From c5caa3b72d498b27f75e5f431566e24660f4bff3 Mon Sep 17 00:00:00 2001 From: Adam Green Date: Fri, 16 Nov 2018 23:44:23 -0800 Subject: [PATCH 2/3] Have mdBook not wrap code snippets in "fn main() {}" I noticed that when I tried to copy a code snippet into the clipboard that it had some extra code text that I didn't see on the webpage. It had wrapped the code snippet in a "fn main()" declaration. The code window on the page also contained arrows in the upper-right corner for expanding the code so that this hidden declaration could be seen. These snippets aren't meant to be working samples so treating them as code to be contained in main() often doesn't make sense. Changing the language from "rust" to "rust,ignore" on these snippets causes mdBook to not perform this wrapping. For example before the following would be copied to clipboard: ```rust fn main() { // Exception handler for the SysTick (System Timer) exception fn SysTick() { // .. } } ``` After this change, we get the following copied to the clipboard: ```rust // Exception handler for the SysTick (System Timer) exception fn SysTick() { // .. } ``` --- src/start/exceptions.md | 8 ++++---- src/start/panicking.md | 2 +- src/start/registers.md | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/start/exceptions.md b/src/start/exceptions.md index 6dc8114..ffdd966 100644 --- a/src/start/exceptions.md +++ b/src/start/exceptions.md @@ -10,7 +10,7 @@ handlers. [`exception`]: https://rust-embedded.github.io/cortex-m-rt/0.6.1/cortex_m_rt_macros/fn.exception.html -``` rust +``` rust,ignore // Exception handler for the SysTick (System Timer) exception #[exception] fn SysTick() { @@ -26,7 +26,7 @@ would result in a compilation error. This behavior is pretty much intended and it's required to provide a feature: `static mut` variables declared *inside* `exception` handlers are *safe* to use. -``` rust +``` rust,ignore #[exception] fn SysTick() { static mut COUNT: u32 = 0; @@ -141,7 +141,7 @@ handler for a specific exception. If you don't override the handler for a particular exception it will be handled by the `DefaultHandler` function, which defaults to: -``` rust +``` rust,ignore fn DefaultHandler() { loop {} } @@ -153,7 +153,7 @@ This function is provided by the `cortex-m-rt` crate and marked as It's possible to override this `DefaultHandler` using the `exception` attribute: -``` rust +``` rust,ignore #[exception] fn DefaultHandler(irqn: i16) { // custom default handler diff --git a/src/start/panicking.md b/src/start/panicking.md index 242ce44..139d09f 100644 --- a/src/start/panicking.md +++ b/src/start/panicking.md @@ -45,7 +45,7 @@ an application as a single line of code is not only useful as documentation but can also be used to change the panicking behavior according to the compilation profile. For example: -``` rust +``` rust,ignore #![no_main] #![no_std] diff --git a/src/start/registers.md b/src/start/registers.md index f41c8f9..c963154 100644 --- a/src/start/registers.md +++ b/src/start/registers.md @@ -46,7 +46,7 @@ The functions on the `SYST` struct map pretty closely to the functionality defin We won't get very far with our embedded software development if we restrict ourselves to only the basic peripherals included with every Cortex-M. At some point, we're going to need to write some code that's specific to the particular micro-controller we're using. In this example, let's assume we have an Texas Instruments TM4C123 - a middling 80MHz Cortex-M4 with 256 KiB of Flash. We're going to pull in the [tm4c123x] crate to make use of this chip. -```rust +```rust,ignore #![no_std] #![no_main] @@ -79,7 +79,7 @@ We've accessed the `PWM0` peripheral in exactly the same way as we accessed the The `read()` function returns an object which gives read-only access to the various sub-fields within this register, as defined by the manufacturer's SVD file for this chip. You can find all the functions available on special `R` return type for this particular register, in this particular peripheral, on this particular chip, in the [tm4c123x documentation][tm4c123x documentation R]. -```rust +```rust,ignore if pwm.ctl.read().globalsync0().is_set() { // Do a thing } @@ -89,7 +89,7 @@ if pwm.ctl.read().globalsync0().is_set() { The `write()` function takes a closure with a single argument. Typically we call this `w`. This argument then gives read-write access to the various sub-fields within this register, as defined by the manufacturer's SVD file for this chip. Again, you can find all the functions available on the 'w' for this particular register, in this particular peripheral, on this particular chip, in the [tm4c123x documentation][tm4c123x Documentation W]. Note that all of the sub-fields that we do not set will be set to a default value for us - any existing content in the register will be lost. -```rust +```rust,ignore pwm.ctl.write(|w| w.globalsync0().clear_bit()); ``` @@ -97,7 +97,7 @@ pwm.ctl.write(|w| w.globalsync0().clear_bit()); If we wish to change only one particular sub-field in this register and leave the other sub-fields unchanged, we can use the `modify` function. This function takes a closure with two arguments - one for reading and one for writing. Typically we call these `r` and `w` respectively. The `r` argument can be used to inspect the current contents of the register, and the `w` argument can be used to modify the register contents. -```rust +```rust,ignore pwm.ctl.modify(|r, w| w.globalsync0().clear_bit()); ``` From 98dbe9989bf8029ce06996d234cdb6eb2c6c0bb0 Mon Sep 17 00:00:00 2001 From: Adam Green Date: Sat, 17 Nov 2018 00:07:51 -0800 Subject: [PATCH 3/3] Chapter 2 code sample fixes These fixes get code samples to compile without warnings. Other changes include: * Fix the SysTick code snippet on the "Memory Mapped Registers" page so that it: * Compiles without errors/warnings. * Sets up the SysTick peripheral correctly for counting down 1000 ticks. * Added a reminder in the "Semihosting" section about how to enable semihosting in openOCD. --- src/start/panicking.md | 2 +- src/start/registers.md | 7 +++++-- src/start/semihosting.md | 8 ++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/start/panicking.md b/src/start/panicking.md index 139d09f..9e7626b 100644 --- a/src/start/panicking.md +++ b/src/start/panicking.md @@ -81,7 +81,7 @@ use cortex_m_rt::entry; fn main() -> ! { let xs = [0, 1, 2]; let i = xs.len() + 1; - let y = xs[i]; // out of bounds access + let _y = xs[i]; // out of bounds access loop {} } diff --git a/src/start/registers.md b/src/start/registers.md index c963154..b909b31 100644 --- a/src/start/registers.md +++ b/src/start/registers.md @@ -26,15 +26,18 @@ use cortex_m::peripheral::{syst, Peripherals}; use cortex_m_rt::entry; #[entry] -fn main() { +fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); let mut systick = peripherals.SYST; systick.set_clock_source(syst::SystClkSource::Core); + systick.set_reload(1_000); systick.clear_current(); systick.enable_counter(); - while systick.get_current() < 1_000 { + while !systick.has_wrapped() { // Loop } + + loop {} } ``` diff --git a/src/start/semihosting.md b/src/start/semihosting.md index 6ebf25e..3a7d6dd 100644 --- a/src/start/semihosting.md +++ b/src/start/semihosting.md @@ -18,8 +18,6 @@ world!": extern crate panic_halt; -use core::fmt::Write; - use cortex_m_rt::entry; use cortex_m_semihosting::hprintln; @@ -41,6 +39,12 @@ Hello, world! (..) ``` +You do need to enable semihosting in OpenOCD from GDB first: +``` console +(gdb) monitor arm semihosting enable +semihosting is enabled +``` + QEMU understands semihosting operations so the above program will also work with `qemu-system-arm` without having to start a debug session. Note that you'll need to pass the `-semihosting-config` flag to QEMU to enable semihosting