From ed973e7497408e1a6dc0c9e8786f3a3cd57c5a3e Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Mon, 13 Mar 2023 18:28:18 +0100 Subject: [PATCH] split exercise into several pages --- embedded-workshop-book/src/SUMMARY.md | 5 +- embedded-workshop-book/src/enabling-uarte.md | 89 +++++++++++ embedded-workshop-book/src/generating-pac.md | 67 +++++++++ embedded-workshop-book/src/pac-docs.md | 41 +++++ embedded-workshop-book/src/pac-exercise.md | 149 +------------------ 5 files changed, 203 insertions(+), 148 deletions(-) create mode 100644 embedded-workshop-book/src/enabling-uarte.md create mode 100644 embedded-workshop-book/src/generating-pac.md create mode 100644 embedded-workshop-book/src/pac-docs.md diff --git a/embedded-workshop-book/src/SUMMARY.md b/embedded-workshop-book/src/SUMMARY.md index d5d8dce..6f34aa0 100644 --- a/embedded-workshop-book/src/SUMMARY.md +++ b/embedded-workshop-book/src/SUMMARY.md @@ -28,7 +28,10 @@ - [BSC Exercise](./bsc-exercise.md) - [Button Implementation](./button-implementation.md) - [UARTE Implementation](./uarte-implementation.md) - - [PAC Exercise](./pac-exercise.md) + - [Generating and Using a PAC](./pac-exercise.md) + - [Exercise: Generating a PAC ](./generating-pac.md) + - [Reading PAC Documentation ](./pac-docs.md) + - [Exercise: Enabling the UARTE0 Peripheral ](./enabling-uarte.md) - [Advanced Workbook](./advanced-workbook.md) - [Code Organization](./code-organisation.md) - [Listing USB Devices](./listing-usb-devices.md) diff --git a/embedded-workshop-book/src/enabling-uarte.md b/embedded-workshop-book/src/enabling-uarte.md new file mode 100644 index 0000000..9e16a0a --- /dev/null +++ b/embedded-workshop-book/src/enabling-uarte.md @@ -0,0 +1,89 @@ +# Enabling the UARTE0 peripheral + +Write a simple program which uses the PAC to enable the UART. See how writing arbitrary values to the ENABLE field in the ENABLE register is unsafe, because only values 0 or 8 should be used. + +## In this exercise you will learn how to: +* to safely write into a register +* how to unsafely write into a register +* how to read a register + +## Prerequisites +* basic use of closures +* usage of the svd2rust's read/write/modify API + +## Tasks +* Find out which values can be written into the `enable` register. +* Take ownership of the boards peripherals +* Write a helper function that reads the UARTE0's `enable` register and print's status. +* Enable the UARTE0 peripheral using a safe method. +* Disable the UARTE0 peripheral by writing raw bits in it (unsafe). + +Final terminal output: + +```terminal +Uarte0 is disabled. +Uarte0 is ensabled. +Uarte0 is disabled. +``` + +## Step-by-Step Solution + +✅ Find the values that can be written in the `enable` register: + +0: disabled +8: enabled + +✅ Import the PAC + +In `down-the-stack/apps/Cargo.toml`: + +``` +dk_pac = { path = "../dk_pac", features = ["critical-section"]} +``` +In `apps/bin/uarte_enable.rs`: + +```rust +use dk_pac::UARTE0; +``` + +✅ Take ownership of the peripherals with `take()` and bind the `UARTE0` peripheral to it's own variable + +```rust +let periph = dk_pac::Peripherals::take().unwrap(); +let uarte = periph.UARTE0; +``` + +✅ Write a helper function that reads the bits of the enable register. It prints "Uarte0 is enabled", when the value is not 0. If it is 0, it prints "Uarte0 is disabled". Add a function call to `fn main()` + +Run the code. The terminal output should read: "Uarte0 is disabled". + +```rust +fn is_uarte_enabled(uarte: &UARTE0) { + if uarte.enable.read().enable().is_enabled() { + defmt::println!("Uarte0 is enabled"); + } else { + defmt::println!("Uarte0 is disabled"); + } +} +``` + +✅ Enable the peripheral safely by passing `w.enable().enabled()` in the closure. Call the helper function after this new line and run your code. + +It should print: + +```terminal +Uarte0 is disabled. +Uarte0 is ensabled. +``` + +```rust +uarte.enable.write(|w| w.enable().enabled()); +``` + +✅ Disable the peripheral unsafely by writing raw bits into the register. + +```rust +unsafe { + uarte.enable.write(|w| w.bits(0x00 as u32)); + } +``` diff --git a/embedded-workshop-book/src/generating-pac.md b/embedded-workshop-book/src/generating-pac.md new file mode 100644 index 0000000..ae22952 --- /dev/null +++ b/embedded-workshop-book/src/generating-pac.md @@ -0,0 +1,67 @@ +# Generating the PAC + +Generate your own PAC from an SVD file. + +## In this exercise you will learn how to +* generate a PAC from an SVD file. +* format the generated code. +* split the single PAC file into it's modules. + +## Prerequisites +* usage of cargo install +* generating docs + +## Tasks +* Install `svd2rust` and `form` via cargo. +* Download the [nrf-svd] file and place it into `down-the-stack/dk-pac`. +* Run svd2rust on the file using the `cortex-m` flag. +* Format the generated file to make it readable. +* Split the file into its modules using `form`. +* Check the documentation. + +## Step-by-Step Solution + + +✅ Install the necessary tools using the following commands: + +```terminal +cargo install svd2rust +cargo install form +``` + +✅ Download https://github.com/NordicSemiconductor/nrfx/blob/master/mdk/nrf52.svd (This version has an error: writeonce needs to be changed to writeOnce) +Place the file into `down-the-stack/dk-pac`. Note how we provide a `Cargo.toml` file, as it will not be generated by svd2rust. + +✅ In the terminal, go to the file's location. Run `svd2rust` with the SVD file to generate a PAC using the `cortex-m` flag. + +``` +svd2rust --target cortex-m -i nrf52.svd +``` +If you check the folder `down-the-stack/dk-pac` now, you see three new files: +* lib.rs - the file that contains the generated code for the pac +* device.x - linker sections(?) +* build.rs - linker script + +✅ Open the generated `lib.rs` with an editor. +Notice how it's barely correctly formatted. + +✅ Look at the PAC docs with the following command: + +```terminal +cargo doc --open +``` + +✅ Format the crate using `cargo fmt`. +This does not change to the docs, but `lib.rs` is a bit more readable. + + +✅ Use form to process the `lib.rs` to split it into modules, so that each module in in it's own file. + +```terminal +form -i src/lib.rs -o src/ +``` + +✅ Re-run `cargo fmt`. + + +[nrf svd]: (https://github.com/NordicSemiconductor/nrfx/blob/master/mdk/nrf52.svd ) \ No newline at end of file diff --git a/embedded-workshop-book/src/pac-docs.md b/embedded-workshop-book/src/pac-docs.md new file mode 100644 index 0000000..4d208bc --- /dev/null +++ b/embedded-workshop-book/src/pac-docs.md @@ -0,0 +1,41 @@ +# Reading PAC Documentation +(This should be covered or at least preceded by a lecture that includes basic use of closures and the read/write/modify API) + +Generate and open the PAC's docs using the following command: + +``` +cargo doc --open +``` + +In the `Structs` section look for the `struct Peripherals`. Taking ownership of it will be the first step later on. Note that only the method `steal()` is documented. It is an unsafe method, and to be avoided. `Peripherals` has a field named `UARTE0`. + +In the `modules` section, look for the `uarte0` module. It is divided into submodules. `enable` is the register we are concerned about. Clicking on it shows the associated type definitions. + +* `W` - the register ENABLE writer with the following methods: + * `enable()` returns the field ENABLE writer `ENABLE_W`. + * `unsafe bits()` writes raw bits into the register. +* `R` - the register ENABLE reader writer with the following methods: + * `enable()` returns the field ENABLE reader `ENABLE_R`. + * `bits()` reads raw bits from the register. + +The types `ENABLE_R` and `ENABLE_W` have methods that you can use if you don't want to deal with raw bits. Check them out! + +Usage: If you want to write or read something from the uarte register and you want to avoid dealing with raw bits, you first have to call a method that gives you access to the respective reader or writer, and then call the method that does what you want. + +Example: + +```rust +// this reads the enable register, and returns true if the register is disabled. +uarte.enable.read().is_disabled() +``` + +Note the difference between the struct field `UARTE0` in `Peripherals` and the module `uarte0`. + +## Finding corresponding sections in the PAC + +* `dk_pac/src/lib.rs` defines the single peripherals with their register block addresses and contains a struct defintion for the `struct Peripherals`. There are two methods for this struct: `take()` and `steal()`. `take()` assures, that only one instance of this can exist. Hence, it's safe. Note that `take()` is only available with the `critical-section` feature enabled. + +* `dk_pac/src/uarte0.rs` defines a struct that contains all the registers of the `UARTE0` register block. The `enable` field represents the register of the same name. + +* `dk_pac/src/uarte0/enable.rs` defines the types associated with this register that you already saw in the docs. + diff --git a/embedded-workshop-book/src/pac-exercise.md b/embedded-workshop-book/src/pac-exercise.md index bd885ed..7f66e4a 100644 --- a/embedded-workshop-book/src/pac-exercise.md +++ b/embedded-workshop-book/src/pac-exercise.md @@ -1,150 +1,5 @@ -# PAC Exercise +# Generating and Using a PAC -In this exercise you will generate a PAC (Peripheral Access Crate) from an svd file, and write a small program that enables the UARTE0 register. - -## In this exercise you will learn how to -* Generate a Peripheral Access Crate from an svd file -* Two ways to write into a register to enable and disable it - -## Prerequisites -* basic use of closures -* read/write/modify api - -## Tasks +In this module you will learn how to generate a PAC (Peripheral Access Crate) from an SVD file, read it's documentation and write a small program that enables the UARTE0 register. -## Generating the PAC - -✅ Install `svd2rust` using the following command: -``` -cargo install svd2rust -``` - -✅ Download https://github.com/NordicSemiconductor/nrfx/blob/master/mdk/nrf52.svd (This version has an error: writeonce needs to be changed to writeOnce) -Place the file into `down-the-stack/dk-pac`. Note how we provide a `Cargo.toml` file, as it will not be generated by svd2rust. - -✅ In the terminal, go to the file's location. Run `svd2rust` with the SVD file to generate a PAC using the `cortex-m` flag. - -``` -svd2rust --target cortex-m -i nrf52.svd -``` -If you check the folder `down-the-stack/dk-pac` now, you see three new files: -* lib.rs - the file that contains the generated code for the pac -* device.x - linker sections(?) -* build.rs - linker script - -✅ Open the generated `lib.rs` with an editor. -Notice how it's one long line of text in the source file. - -✅ Look at the PAC docs with cargo doc --open. - -✅ cargo fmt the crate. No change to the docs, but a bit more readable. - -✅ Install form with the following command: - -``` -cargo install form -``` - -``` -✅ use form to process the one-big-file into one-file-per-module with the following command: -``` -form -i src/lib.rs -o src/ -``` - -✅ Re-run `cargo fmt`. - - -## Enabling the UARTE0 peripheral - - - -Write a simple program which uses the PAC to enable the UART. See how writing arbitrary values to the ENABLE field in the ENABLE register is unsafe, because only values 0 or 8 should be used. - -✅ Finding your way through the docs: -(This better be a lecture) - -* In the `Structs` section look for the `struct Peripherals`. Taking ownerhip of it will be the first step later on. Note that only the method `steal()` is documented. It is an unsafe method, and to be avoided. `Peripherals` has a field named `UARTE0` -* In the `modules` section, look for the `uarte0` module. It is divided into submodules. `enable` is important for us. Clicking on it shows the associated type definitions. - - -* `W` - the register ENABLE writer with the following methods: - * `enable()` returns the field ENABLE writer `ENABLE_W`. - * `unsafe bits()` writes raw bits into the register. -* `R` - the register ENABLE reader writer with the following methods: - * `enable()` returns the field ENABLE reader `ENABLE_R`. - * `bits()` reads raw bits from the register. -The types `ENABLE_R` and `ENABLE_W` have useful methods themselves, check them out. - -Usage: if you want to write or read something from the uarte register and you want to avoid dealing with raw bits, you first have to call a method that gives you access to the respective reader or writer, and then call the method that does what you want. - -Example: - -uarte.enable.read(). - -Note the difference between the struct field `UARTE0` in `Peripherals` and the module `uarte0`. - -✅ Finding your way through the PAC - -* `dk_pac/src/lib.rs` defines the single peripherals with their register block addresses and contains a struct defintion for the `struct Peripherals`. There are two methods for this struct: `take()` and `steal()`. `take()` assures, that only one instance of this can exist. Hence, it's safe. Note that `take()` is only available with the `critical-section` feature enabled. - -* `dk_pac/src/uarte0.rs` defines a struct that contains all the registers of the `UARTE0` register block. The `enable` field represents the register of the same name. - -* `dk_pac/src/uarte0/enable.rs` defines the types associated with this register that you already saw in the docs. - -* Find the definition of the ENABLE register for UARTE0, in the PDF datasheet and in the SVD file - -* - - -✅ Import the PAC - -down-the-stack/apps/Cargo.toml - -``` -dk_pac = { path = "../dk_pac", features = ["critical-section"]} -``` -apps/bin/uarte_enable.rs - -```rust -use dk_pac::UARTE0; -``` - -✅ Take ownership of the peripherals with `take()` and bind the `UARTE0` peripheral to it's own variable - -```rust -let periph = dk_pac::Peripherals::take().unwrap(); -let uarte = periph.UARTE0; -``` - -✅ Write a helper function that reads the bits of the enable register. It prints "Uarte0 is enabled", when the value is not 0. If it is 0, it prints "Uarte0 is disabled". Add a function call to `fn main()` - -Run the code. The terminal output should read: "Uarte0 is disabled". - -```rust -fn is_uarte_enabled(uarte: &UARTE0) { - if uarte.enable.read().enable().is_enabled() { - defmt::println!("Uarte0 is enabled"); - } else { - defmt::println!("Uarte0 is disabled"); - } -} -``` - -✅ Enable the peripheral safely by passing `w.enable().enabled()` in the closure. Call the helper function after this new line and run your code. - -It should print: -"Uarte0 is disabled" -"Uarte0 is ensabled" - -``` -uarte.enable.write(|w| w.enable().enabled()); -``` - -✅ Disable the peripheral with unsafely by writing raw bits into the register. - -```rust -unsafe { - uarte.enable.write(|w| w.bits(0x00 as u32)); - } -```