Skip to content
Snippets Groups Projects
Commit ebed0a6f authored by Per Lindgren's avatar Per Lindgren
Browse files

bare0-4 updated

parent 1e2daa2c
No related branches found
No related tags found
No related merge requests found
......@@ -3,7 +3,7 @@
//! Inspecting the generated assembly
//!
//! What it covers
//! - ITM tracing
//! - Rust panic tracing using ITM
//! - assembly calls and inline assembly
//! - more on arithmetics
......@@ -45,7 +45,7 @@ fn main() -> ! {
//
// You may need/want to install additional components also.
// To that end look at the install section in the README.md.
// If you change toolchain, you may need to exit and re-start `vscode`.
// (If you change toolchain, you may need to exit and re-start `vscode`.)
//
// 1. Build and run the application
//
......
......@@ -6,13 +6,14 @@
//! - Generating documentation
//! - Using core peripherals
//! - Measuring time using the DWT
//! - ITM tracing
//! - ITM tracing using `iprintln`
//! - Panic halt
//!
#![no_main]
#![no_std]
extern crate panic_halt;
use panic_halt as _;
use cortex_m::{iprintln, peripheral::DWT, Peripherals};
use cortex_m_rt::entry;
......@@ -37,7 +38,7 @@ fn main() -> ! {
dwt.enable_cycle_counter();
// Reading the cycle counter can be done without `owning` access
// the DWT (since it has no side effetc).
// the DWT (since it has no side effect).
//
// Look in the docs:
// pub fn enable_cycle_counter(&mut self)
......@@ -89,7 +90,7 @@ fn main() -> ! {
//
// ** your answer here **
//
// commit your answers (bare2_1)
// commit your answers (bare2_1)
//
// 3. *Optional
// Inspect the generated binaries, and try stepping through the code
......
......@@ -5,7 +5,7 @@
//! What it covers:
//! - Types, str, arrays ([u8; usize]), slices (&[u8])
//! - Iteration, copy
//! - Semihosting (tracing)
//! - Semihosting (tracing using `hprintln`
#![no_main]
#![no_std]
......@@ -103,3 +103,46 @@ fn main() -> ! {
// Implement and test your solution.
//
// Commit your answers (bare3_5)
//
// 6. Optional
// Rust is heavily influenced by functional languages.
// Figure out how you can use an iterator to work over both
// the `a` and `bs` to copy the content of `bs` to `a`.
//
// You may use
// - `iter` (to turn a slice into an iterator)
// - `zip` (to merge two slices into an iterator)
// - a for loop to assign the elements
//
// Commit your solution (bare3_6)
//
// 7. Optional
// Iter using `foreach` and a closure instead of the for loop.
//
// Commit your solution (bare3_7)
//
// 8. Optional*
// Now benchmark your different solutions using the cycle accurate
// DWT based approach (in release mode).
//
// Cycle count for `raw` indexing
//
// ** your answer here **
//
// Cycle count for the primitive slice approach.
//
// ** your answer here **
//
// Cycle count for the primitive slice approach.
//
// ** your answer here **
//
// Cycle count for the zip + for loop approach.
//
// ** your answer here **
//
// Cycle count for the zip + for_each approach.
//
// What conclusions can you draw, does Rust give you zero-cost abstractions?
//
// ** your answer here **
//! bare4.rs
//!
//! Access to Peripherals
//!
//! What it covers:
//! - Raw pointers
//! - Volatile read/write
//! - Busses and clocking
//! - GPIO (a primitive abstraction)
#![no_std]
#![no_main]
extern crate panic_halt;
extern crate cortex_m;
use cortex_m_rt::entry;
// Peripheral addresses as constants
#[rustfmt::skip]
mod address {
pub const PERIPH_BASE: u32 = 0x40000000;
pub const AHB1PERIPH_BASE: u32 = PERIPH_BASE + 0x00020000;
pub const RCC_BASE: u32 = AHB1PERIPH_BASE + 0x3800;
pub const RCC_AHB1ENR: u32 = RCC_BASE + 0x30;
pub const GBPIA_BASE: u32 = AHB1PERIPH_BASE + 0x0000;
pub const GPIOA_MODER: u32 = GBPIA_BASE + 0x00;
pub const GPIOA_BSRR: u32 = GBPIA_BASE + 0x18;
}
use address::*;
// see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf)
// rcc, chapter 6
// gpio, chapter 8
#[inline(always)]
fn read_u32(addr: u32) -> u32 {
unsafe { core::ptr::read_volatile(addr as *const _) }
//core::ptr::read_volatile(addr as *const _)
}
#[inline(always)]
fn write_u32(addr: u32, val: u32) {
unsafe {
core::ptr::write_volatile(addr as *mut _, val);
}
}
fn wait(i: u32) {
for _ in 0..i {
cortex_m::asm::nop(); // no operation (cannot be optimized out)
}
}
#[entry]
fn main() -> ! {
// power on GPIOA
let r = read_u32(RCC_AHB1ENR); // read
write_u32(RCC_AHB1ENR, r | 1); // set enable
// configure PA5 as output
let r = read_u32(GPIOA_MODER) & !(0b11 << (5 * 2)); // read and mask
write_u32(GPIOA_MODER, r | 0b01 << (5 * 2)); // set output mode
// and alter the data output through the BSRR register
// this is more efficient as the read register is not needed.
loop {
// set PA5 high
write_u32(GPIOA_BSRR, 1 << 5); // set bit, output hight (turn on led)
wait(10_000);
// set PA5 low
write_u32(GPIOA_BSRR, 1 << (5 + 16)); // clear bit, output low (turn off led)
wait(10_000);
}
}
// 0. Build and run the application (debug build).
//
// > cargo run --example bare4
// (or use the vscode)
//
// 1. Did you enjoy the blinking?
//
// ** your answer here **
//
// Now lookup the data-sheets, and read each section referred,
// 6.3.11, 8.4.1, 8.4.7
//
// Document each low level access *code* by the appropriate section in the
// data sheet.
//
// Commit your answers (bare4_1)
//
// 2. Comment out line 40 and uncomment line 41 (essentially omitting the `unsafe`)
//
// //unsafe { core::ptr::read_volatile(addr as *const _) }
// core::ptr::read_volatile(addr as *const _)
//
// What was the error message and explain why.
//
// ** your answer here **
//
// Digging a bit deeper, why do you think `read_volatile` is declared `unsafe`.
// (https://doc.rust-lang.org/core/ptr/fn.read_volatile.html, for some food for thought )
//
// ** your answer here **
//
// Commit your answers (bare4_2)
//
// 3. Volatile read/writes are explicit *volatile operations* in Rust, while in C they
// are declared at type level (i.e., access to varibles declared volatile amounts to
// volatile reads/and writes).
//
// Both C and Rust (even more) allows code optimization to re-order operations, as long
// as data dependencies are preserved.
//
// Why is it important that ordering of volatile operations are ensured by the compiler?
//
// ** your answer here **
//
// Give an example in the above code, where reordering might make things go horribly wrong
// (hint, accessing a peripheral not being powered...)
//
// ** your answer here **
//
// Without the non-reordering property of `write_volatile/read_volatile` could that happen in theory
// (argue from the point of data dependencies).
//
// ** your answer here **
//
// Commit your answers (bare4_3)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment