Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • student
1 result

Target

Select target project
  • pln/e7020e_2019
  • Henrik/e7020e_2019
  • wijk/e7020e_2019
  • sheepwall/e7020e_2019
  • Tiberg/e7020e_2019
  • Tyllstrom/e7020e_2019
  • Ridgep/e7020e_2019
7 results
Select Git revision
  • nrf52
  • student
2 results
Show changes
Commits on Source (47)
Showing
with 435 additions and 175 deletions
......@@ -3,3 +3,4 @@
.gdb_history
Cargo.lock
target/
*.pdf
\ No newline at end of file
......@@ -12,7 +12,7 @@
"preLaunchTask": "cargo build --example hello",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/hello",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
......@@ -59,7 +59,7 @@
"preLaunchTask": "cargo build --example itm",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/itm",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
......@@ -89,7 +89,7 @@
"preLaunchTask": "cargo build --example panic",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/panic",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
......@@ -119,7 +119,7 @@
"preLaunchTask": "cargo build --example exception_itm --release",
"executable": "./target/thumbv7em-none-eabihf/release/examples/exception_itm",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
......@@ -145,7 +145,7 @@
"preLaunchTask": "cargo build --example exception_itm_raw",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/exception_itm_raw",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
......@@ -171,7 +171,7 @@
"preLaunchTask": "cargo build --example crash --release",
"executable": "./target/thumbv7em-none-eabihf/release/examples/crash",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
......@@ -216,7 +216,7 @@
"executable": "./target/thumbv7em-none-eabihf/debug/examples/device",
// uses local config files
"configFiles": [
"./stlink.cfg",
"./stlink-v2-1.cfg",
"./stm32f4x.cfg"
],
"postLaunchCommands": [
......@@ -275,7 +275,7 @@
"executable": "./target/thumbv7em-none-eabihf/debug/examples/rtfm_blinky",
// uses local config files
"configFiles": [
"./stlink.cfg",
"./stlink-v2-1.cfg",
"./stm32f4x.cfg"
],
"swoConfig": {
......@@ -302,7 +302,7 @@
"preLaunchTask": "cargo build --example bare0",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare0",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"cwd": "${workspaceRoot}"
......@@ -360,7 +360,7 @@
]
},
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"cwd": "${workspaceRoot}"
......@@ -434,7 +434,7 @@
"monitor arm semihosting enable"
],
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"cwd": "${workspaceRoot}"
......@@ -450,7 +450,7 @@
"monitor arm semihosting enable"
],
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"cwd": "${workspaceRoot}"
......@@ -466,7 +466,7 @@
"monitor arm semihosting enable"
],
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"cwd": "${workspaceRoot}"
......@@ -482,7 +482,7 @@
"monitor arm semihosting enable"
],
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"cwd": "${workspaceRoot}"
......@@ -495,7 +495,7 @@
"preLaunchTask": "cargo build --example bare6",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare6",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
......@@ -524,7 +524,7 @@
"preLaunchTask": "cargo build --example bare6",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare6",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
......@@ -585,7 +585,7 @@
"preLaunchTask": "cargo build --example bare7",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare7",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
......@@ -616,7 +616,7 @@
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare7",
// uses local config files
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
......@@ -646,7 +646,7 @@
"preLaunchTask": "cargo build --example bare8",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare8",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
......@@ -673,7 +673,7 @@
"preLaunchTask": "cargo build --example bare9",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare9",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
......@@ -700,7 +700,7 @@
"preLaunchTask": "cargo build --example bare9 --release",
"executable": "./target/thumbv7em-none-eabihf/release/examples/bare9",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
......@@ -727,7 +727,7 @@
"preLaunchTask": "cargo build --example bare10 --release",
"executable": "./target/thumbv7em-none-eabihf/release/examples/bare10",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
......@@ -759,7 +759,7 @@
"preLaunchTask": "cargo build --example bare10",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare10",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
......@@ -791,7 +791,7 @@
"preLaunchTask": "cargo build --example marcus --release",
"executable": "./target/thumbv7em-none-eabihf/release/examples/marcus",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
......@@ -823,7 +823,7 @@
"preLaunchTask": "cargo build --example equivalence --release",
"executable": "./target/thumbv7em-none-eabihf/release/examples/equivalence",
"configFiles": [
"interface/stlink.cfg",
"interface/stlink-v2-1.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
......
......@@ -28,19 +28,19 @@ optional = true
[dependencies.cortex-m]
version = "0.5.8"
# features = ["inline-asm"] # <- currently requires nightly compiler
features = ["inline-asm"] # <- currently requires nightly compiler
# Uncomment for the allocator example.
# alloc-cortex-m = "0.3.5"
[dependencies.stm32f4]
version = "0.5.0"
version = "0.6.0"
features = ["stm32f413", "rt"]
optional = true
[dependencies.stm32f4xx-hal]
git = "https://github.com/stm32-rs/stm32f4xx-hal.git"
version = "0.2.8"
version = "0.3.0"
features = ["stm32f413", "rt"]
optional = true
......
......@@ -19,7 +19,7 @@ extern crate panic_halt;
use cortex_m_rt::entry;
// a constant (cannot be changed at run-time)
const X_INIT: u32 = 10;
const X_INIT: u32 = u32::max_value();
// global mutabale variables (changed using unsafe code)
static mut X: u32 = X_INIT;
......@@ -27,17 +27,36 @@ static mut Y: u32 = 0;
#[entry]
fn main() -> ! {
// local mutabale variable (changed in safe code)
let mut x = unsafe { X };
// local mutable variable (changed in safe code)
let mut x = read_x();
let mut x_tmp: u32;
loop {
x += 1; // <- place breakpoint here (3)
unsafe {
X += 1;
Y = X;
assert!(x == X && X == Y);
x = x.wrapping_add(1u32);
// I assume that there was a point in not setting X = x directly since the assert is there;
// hence the x_tmp variable.
x_tmp = read_x();
x_tmp = x_tmp.wrapping_add(1u32);
write_x(x_tmp);
write_y(read_x());
}
}
fn write_x(x: u32) {
unsafe { X = x; }
}
fn write_y(y: u32) {
unsafe { Y = y; }
}
fn read_x() -> u32 {
unsafe { X }
}
fn read_y() -> u32 {
unsafe { Y }
}
// 0. Compile/build the example in debug (dev) mode.
......@@ -48,45 +67,46 @@ fn main() -> ! {
// 1. Run the program in the debugger, let the program run for a while and
// then press pause. Look in the (Local -vscode) Variables view what do you find.
//
// ** your answer here **
// * x: 540217
//
// In the Expressions (WATCH -vscode) view add X and Y
// what do you find
//
// ** your answer here **
// * X: 540217
// * Y: 540217
//
// Step through one complete iteration of the loop
// and see how the (Local) Variables are updated
// can you foresee what will eventually happen?
//
// ** place your answer here **
// * It will increase x, X and Y. After a while, x will overflow and go to 0.
//
// Commit your answers (bare0_1)
//
// 2. Alter the constant X_INIT so that `x += 1` directly causes `x` to wrap
// what happens when `x` wraps
//
// ** your answer here **
// * Changed to 4294967295 (2^32 - 1). The program runs and ends up in a panic.
//
// Commit your answers (bare0_2)
//
// 3. Place a breakpoint at `x += 1`
//
// Change (both) += opertions to use wrapping_add
// load and run the progam, what happens
// ** your answer here **
// load and run the program, what happens
// * x, X, and Y start over at 0 again.
//
// Now continue exectution, what happens
// ** your answer here **
// * The program runs as it normally did.
//
// Commit your answers (bare0_3)
//
// (If the program did not succeed back to the breakpoint
// you have some fault in the program and go back to 3.)
//
// 4. Change the asserion to `assert!(x == X && X == Y + 1)`, what happens?
// 4. Change the assertion to `assert!(x == X && X == Y + 1)`, what happens?
//
// ** place your answer here **
// * The program enters a panic loop.
//
// Commit your answers (bare0_4)
//
......
......@@ -13,17 +13,24 @@
extern crate panic_halt;
use cortex_m_rt::entry;
use cortex_m::{iprintln, Peripherals};
use cortex_m_semihosting::hprintln;
#[entry]
#[inline(never)]
fn main() -> ! {
// Prepend by `x` by _ to avoid warning (never used).
// The compiler is smart enough to figure out that
// `x` is not used in any menaningful way.
// `x` is not used in any meaningful way.
let mut _x = 0;
// let mut p = Peripherals::take().unwrap();
// let stim = &mut p.ITM.stim[0];
loop {
// hprintln!("{}", _x).unwrap();
_x += 1;
// iprintln!(stim, "{}", _x);
cortex_m::asm::nop();
cortex_m::asm::bkpt();
_x -= 1;
......@@ -33,11 +40,11 @@ fn main() -> ! {
// 0. Setup
// For this example we will use the `nightly` compiler
// to get inline assembly.
// (Inline assembly is currently not stabelized.)
// (Inline assembly is currently not stabilized.)
//
// > rustup override set nightly
//
// In the `Corgo.toml` file, uncomment
// In the `Cargo.toml` file, uncomment
// # features = ["inline-asm"] # <- currently requires nightly compiler
//
// You may need/want to install addititonal components also,
......@@ -55,10 +62,16 @@ fn main() -> ! {
// loop, (press pause/suspend to verify this).
// what is the output in the ITM console
//
// ** your answer here **
// * 1
// * 1
// * 1
// * ...
//
// What is the output in the semihosting (openocd) console
// ** your answer here **
// * 0
// * 0
// * 0
// * ...
//
// Commit your answers (bare1_1)
//
......@@ -68,7 +81,40 @@ fn main() -> ! {
// What is the output of:
// (gdb) disassemble
//
// ** your answer here **
// disassemble
// {"token":41,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
// Dump of assembler code for function main:
// 0x08000400 <+0>: sub sp, #16
// 0x08000402 <+2>: movs r0, #0
// 0x08000404 <+4>: str r0, [sp, #12]
// 0x08000406 <+6>: b.n 0x8000408 <main+8>
// => 0x08000408 <+8>: ldr r0, [sp, #12]
// 0x0800040a <+10>: adds r1, r0, #1
// 0x0800040c <+12>: mov r2, r1
// 0x0800040e <+14>: cmp r1, r0
// 0x08000410 <+16>: str r2, [sp, #8]
// 0x08000412 <+18>: bvs.n 0x800042c <main+44>
// 0x08000414 <+20>: b.n 0x8000416 <main+22>
// 0x08000416 <+22>: ldr r0, [sp, #8]
// 0x08000418 <+24>: str r0, [sp, #12]
// 0x0800041a <+26>: ldr r1, [sp, #12]
// 0x0800041c <+28>: subs r2, r1, #1
// 0x0800041e <+30>: cmp r1, #1
// 0x08000420 <+32>: str r2, [sp, #4]
// 0x08000422 <+34>: bvs.n 0x800043a <main+58>
// 0x08000424 <+36>: b.n 0x8000426 <main+38>
// 0x08000426 <+38>: ldr r0, [sp, #4]
// 0x08000428 <+40>: str r0, [sp, #12]
// 0x0800042a <+42>: b.n 0x8000408 <main+8>
// 0x0800042c <+44>: movw r0, #2268 ; 0x8dc
// 0x08000430 <+48>: movt r0, #2048 ; 0x800
// 0x08000434 <+52>: bl 0x800045c <panic>
// 0x08000438 <+56>: udf #254 ; 0xfe
// 0x0800043a <+58>: movw r0, #2340 ; 0x924
// 0x0800043e <+62>: movt r0, #2048 ; 0x800
// 0x08000442 <+66>: bl 0x800045c <panic>
// 0x08000446 <+70>: udf #254 ; 0xfe
// End of assembler dump.
//
// Commit your answers (bare1_2)
//
......@@ -78,7 +124,42 @@ fn main() -> ! {
// What is the output of:
// (gdb) disassemble
//
// ** your answer here **
// disassemble
// {"token":41,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
// Dump of assembler code for function main:
// 0x08000404 <+0>: sub sp, #16
// 0x08000406 <+2>: movs r0, #0
// 0x08000408 <+4>: str r0, [sp, #12]
// 0x0800040a <+6>: b.n 0x800040c <main+8>
// => 0x0800040c <+8>: ldr r0, [sp, #12]
// 0x0800040e <+10>: adds r1, r0, #1
// 0x08000410 <+12>: mov r2, r1
// 0x08000412 <+14>: cmp r1, r0
// 0x08000414 <+16>: str r2, [sp, #8]
// 0x08000416 <+18>: bvs.n 0x8000436 <main+50>
// 0x08000418 <+20>: b.n 0x800041a <main+22>
// 0x0800041a <+22>: ldr r0, [sp, #8]
// 0x0800041c <+24>: str r0, [sp, #12]
// 0x0800041e <+26>: bl 0x8000400 <cortex_m::asm::nop>
// 0x08000422 <+30>: b.n 0x8000424 <main+32>
// 0x08000424 <+32>: ldr r0, [sp, #12]
// 0x08000426 <+34>: subs r1, r0, #1
// 0x08000428 <+36>: cmp r0, #1
// 0x0800042a <+38>: str r1, [sp, #4]
// 0x0800042c <+40>: bvs.n 0x8000444 <main+64>
// 0x0800042e <+42>: b.n 0x8000430 <main+44>
// 0x08000430 <+44>: ldr r0, [sp, #4]
// 0x08000432 <+46>: str r0, [sp, #12]
// 0x08000434 <+48>: b.n 0x800040c <main+8>
// 0x08000436 <+50>: movw r0, #2268 ; 0x8dc
// 0x0800043a <+54>: movt r0, #2048 ; 0x800
// 0x0800043e <+58>: bl 0x8000466 <panic>
// 0x08000442 <+62>: udf #254 ; 0xfe
// 0x08000444 <+64>: movw r0, #2340 ; 0x924
// 0x08000448 <+68>: movt r0, #2048 ; 0x800
// 0x0800044c <+72>: bl 0x8000466 <panic>
// 0x08000450 <+76>: udf #254 ; 0xfe
// End of assembler dump.
//
// Commit your answers (bare1_3)
//
......@@ -88,7 +169,44 @@ fn main() -> ! {
// What is the output of:
// (gdb) disassemble
//
// ** your answer here **
// disassemble
// {"token":39,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
// Dump of assembler code for function main:
// 0x08000404 <+0>: sub sp, #16
// 0x08000406 <+2>: movs r0, #0
// 0x08000408 <+4>: str r0, [sp, #12]
// 0x0800040a <+6>: b.n 0x800040c <main+8>
// 0x0800040c <+8>: ldr r0, [sp, #12]
// 0x0800040e <+10>: adds r1, r0, #1
// 0x08000410 <+12>: mov r2, r1
// 0x08000412 <+14>: cmp r1, r0
// 0x08000414 <+16>: str r2, [sp, #8]
// 0x08000416 <+18>: bvs.n 0x800043a <main+54>
// 0x08000418 <+20>: b.n 0x800041a <main+22>
// 0x0800041a <+22>: ldr r0, [sp, #8]
// 0x0800041c <+24>: str r0, [sp, #12]
// 0x0800041e <+26>: bl 0x8000400 <cortex_m::asm::nop>
// 0x08000422 <+30>: b.n 0x8000424 <main+32>
// => 0x08000424 <+32>: bkpt 0x0000
// 0x08000426 <+34>: b.n 0x8000428 <main+36>
// 0x08000428 <+36>: ldr r0, [sp, #12]
// 0x0800042a <+38>: subs r1, r0, #1
// 0x0800042c <+40>: cmp r0, #1
// 0x0800042e <+42>: str r1, [sp, #4]
// 0x08000430 <+44>: bvs.n 0x8000448 <main+68>
// 0x08000432 <+46>: b.n 0x8000434 <main+48>
// 0x08000434 <+48>: ldr r0, [sp, #4]
// 0x08000436 <+50>: str r0, [sp, #12]
// 0x08000438 <+52>: b.n 0x800040c <main+8>
// 0x0800043a <+54>: movw r0, #2268 ; 0x8dc
// 0x0800043e <+58>: movt r0, #2048 ; 0x800
// 0x08000442 <+62>: bl 0x800046a <panic>
// 0x08000446 <+66>: udf #254 ; 0xfe
// 0x08000448 <+68>: movw r0, #2340 ; 0x924
// 0x0800044c <+72>: movt r0, #2048 ; 0x800
// 0x08000450 <+76>: bl 0x800046a <panic>
// 0x08000454 <+80>: udf #254 ; 0xfe
// End of assembler dump.
//
// Commit your answers (bare1_4)
//
......@@ -101,7 +219,13 @@ fn main() -> ! {
// Compare the generated assembly for the loop
// between the dev (unoptimized) and release (optimized) build.
//
// ** your answer here **
// disassemble
// {"token":40,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
// Dump of assembler code for function main:
// 0x08000400 <+0>: nop
// => 0x08000402 <+2>: bkpt 0x0000
// 0x08000404 <+4>: b.n 0x8000400 <main>
// End of assembler dump.
//
// commit your answers (bare1_5)
//
......
......@@ -83,9 +83,9 @@ const APP: () = {
fn trace_data(byte: u8) {
let stim = &mut resources.ITM.stim[0];
iprintln!(stim, "data {}", byte);
// for _ in 0..10000 {
// asm::nop();
// }
for _ in 0..10000 {
asm::nop();
}
}
#[task(priority = 1, resources = [ITM])]
......@@ -145,15 +145,17 @@ const APP: () = {
//
// Did you loose any data (was the data correctly echoed)?
//
// ** your answer here **
// ** No, the data was correctly echoed. **
//
// Was the data correctly traced over the ITM?
//
// ** your answer here **
// ** No, only ab was traced. c and d generated RingBufferOverflow. **
//
// Why did you loose trace information?
//
// ** your asnwer here **
// ** The interrupt has higher priority so it takes over from the running
// trace_data task, but that task has not finished its nop-loop started
// in a previous interrupt. Therefore the block!() evaluates to an error. **
//
// Commit your answers (bare10_1)
//
......
......@@ -61,7 +61,7 @@ fn main() -> ! {
// This will document your crate, and open the docs in your browser.
// If it does not auto-open, then copy paste the path in your browser.
//
// In the docs, seach (`S`) for DWT, and click `cortex_m::peripheral::DWT`.
// In the docs, search (`S`) for DWT, and click `cortex_m::peripheral::DWT`.
// Read the API docs.
//
// 1. Build and run the application (debug build).
......@@ -71,18 +71,22 @@ fn main() -> ! {
//
// What is the output in the ITM console?
//
// ** your answer here **
// bare2
// Start 738524136
// End 1364524344
//
// Rebuild and run in release mode
//
// > cargo build --example bare2 --release
//
// ** your answer here **
// bare2
// Start 2513719548
// End 2517719556
//
// Compute the ratio between debug/release optimized code
// (the speedup).
//
// ** your answer here **
// 156.50... times speedup!
//
// commit your answers (bare2_1)
//
......
......@@ -18,26 +18,29 @@ use cortex_m_semihosting::{hprint, hprintln};
#[entry]
fn main() -> ! {
hprintln!("bare3").unwrap();
let s = "ABCD";
let bs = s.as_bytes();
let s: &str = "ABCD";
let bs: &[u8] = s.as_bytes();
hprintln!("s = {}", s).unwrap();
hprintln!("bs = {:?}", bs).unwrap();
hprintln!("iterate over slice").unwrap();
for c in bs {
let c: &u8 = c;
hprint!("{},", c).unwrap();
}
hprintln!("iterate iterate using (raw) indexing").unwrap();
for i in 0..s.len() {
let i: usize = i;
hprintln!("{},", bs[i]).unwrap();
}
hprintln!("").unwrap();
let a = [65u8; 4];
//let mut a = [0u8; 4];
let mut a: [u8; 4] = [0u8; 4];
a.clone_from_slice(bs);
hprintln!("").unwrap();
hprintln!("a = {}", core::str::from_utf8(&a).unwrap()).unwrap();
......@@ -52,27 +55,38 @@ fn main() -> ! {
//
// 1. What is the output in the `openocd` (Adapter Output) console?
//
// ** your answer here **
// bare3
// s = ABCD
// bs = [65, 66, 67, 68]
// iterate over slice
// 65,66,67,68,iterate iterate using (raw) indexing
// 65,
// 66,
// 67,
// 68,
//
//
// a = AAAA
//
// What is the type of `s`?
//
// ** your answer here **
// ** It is a string literal, more precise: It is a slice pointing to (&str) the string literal. **
//
// What is the type of `bs`?
//
// ** your answer here **
// ** It is a byte slice. A dynamic array. **
//
// What is the type of `c`?
//
// ** your answer here **
// ** It is an element of bs, a byte **
//
// What is the type of `a`?
//
// ** your answer here **
// ** An array of type u8 with length 4. **
//
// What is the type of `i`?
//
// ** your answer here **
// ** usize (32 or 64-bit unsigned.) from the str::len() **
//
// Commit your answers (bare3_1)
//
......@@ -84,7 +98,9 @@ fn main() -> ! {
//`
// Run the program, what happens and why?
//
// ** your answer here **
// ** Rust allows this shadowing and therefore builds without error.
// When the program runs, the last hprintln! prints "a =" without any characters.
// This is because a = [0, 0, 0, 0] and 0 in utf8 is the NULL character. **
//
// Commit your answers (bare3_3)
//
......
......@@ -19,13 +19,13 @@ 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;
pub const PERIPH_BASE: u32 = 0x40000000; // Seen in memory map, 2.3
pub const AHB1PERIPH_BASE: u32 = PERIPH_BASE + 0x00020000; // GPIO(A) registers, 8.4
pub const RCC_BASE: u32 = AHB1PERIPH_BASE + 0x3800; // RCC registers, 6.3
pub const RCC_AHB1ENR: u32 = RCC_BASE + 0x30; // 6.3.9
pub const GBPIA_BASE: u32 = AHB1PERIPH_BASE + 0x0000; // 8.4
pub const GPIOA_MODER: u32 = GBPIA_BASE + 0x00; // 8.4.1
pub const GPIOA_BSRR: u32 = GBPIA_BASE + 0x18; // GPIO port bit set/reset register BSRR 8.4.7
}
use address::*;
......@@ -36,8 +36,8 @@ use address::*;
#[inline(always)]
fn read_u32(addr: u32) -> u32 {
unsafe { core::ptr::read_volatile(addr as *const _) }
//core::ptr::read_volatile(addr as *const _)
// unsafe { core::ptr::read_volatile(addr as *const _) }
core::ptr::read_volatile(addr as *const _)
}
#[inline(always)]
......@@ -55,11 +55,11 @@ fn wait(i: u32) {
#[entry]
fn main() -> ! {
// power on GPIOA
// power on GPIOA, 6.3.9
let r = read_u32(RCC_AHB1ENR); // read
write_u32(RCC_AHB1ENR, r | 1); // set enable
// configure PA5 as output
// configure PA5 as output, 8.4.1
let r = read_u32(GPIOA_MODER) & !(0b11 << (5 * 2)); // read and mask
write_u32(GPIOA_MODER, r | 0b01 << (5 * 2)); // set output mode
......@@ -67,11 +67,11 @@ fn main() -> ! {
// this is more efficient as the read register is not needed.
loop {
// set PA5 high
// set PA5 high, 8.4.7
write_u32(GPIOA_BSRR, 1 << 5); // set bit, output hight (turn on led)
wait(10_000);
// set PA5 low
// set PA5 low, 8.4.7
write_u32(GPIOA_BSRR, 1 << (5 + 16)); // clear bit, output low (turn off led)
wait(10_000);
}
......@@ -84,7 +84,7 @@ fn main() -> ! {
//
// 1. Did you enjoy the blinking?
//
// ** your answer here **
// ** Thouroughly **
//
// Now lookup the data-sheets, and read each section referred,
// 6.3.11, 8.4.1, 8.4.7
......@@ -101,12 +101,14 @@ fn main() -> ! {
//
// What was the error message and explain why.
//
// ** your answer here **
// ** Compiler error E0133: "call to unsafe function is unsafe ..."
// Because read_volatile is defined as unsafe. **
//
// 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 **
// ** The section on safety reads that the behaviour is undefined if the parameter is not valid.
// The passed parameter must not be unaligned nor out of bounds. Undefined behaviour is unsafe! **
//
// Commit your answers (bare4_2)
//
......@@ -119,16 +121,23 @@ fn main() -> ! {
//
// Why is it important that ordering of volatile operations are ensured by the compiler?
//
// ** your answer here **
// ** If read/write instructions are reordered, the consequences are undefined, since
// what was intended to be read might not be there. And since peripherals' configurations
// depend on the contents of registers that are read from/written to, configurations might
// go wrong. **
//
// 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 **
// ** We set port A to general purpose output mode. There is undefined, unintended behaviour
// if we write to the port bits without enabling it. **
//
// Without the non-reording proprety of `write_volatile/read_volatile` could that happen in theory
// (argue from the point of data dependencies).
//
// ** your answer here **
// ** If we read from a register to apply a mask on it, it most probably needs to remain that value
// before writing the masked value to it, otherwise the masked value is not accurate. If read/writes
// are reordered during many reads and writes (e.g. during configuration), the configuration might end
// up faulty. **
//
// Commit your answers (bare4_3)
......@@ -13,6 +13,7 @@ extern crate panic_halt;
extern crate cortex_m;
use cortex_m_rt::entry;
use cortex_m_semihosting::{hprint, hprintln};
// C like API...
mod stm32f40x {
......@@ -56,13 +57,21 @@ mod stm32f40x {
// offset (field offset)
// width (field width)
// value (new value that the field should take)
//
// impl VolatileCell<u32> {
// #[inline(always)]
// pub fn modify(&self, offset: u8, width: u8, value: u32) {
// // your code here
// }
// }
impl VolatileCell<u32> {
#[inline(always)]
pub fn modify(&self, offset: u8, width: u8, value: u32) {
let mask: u32 = 2u32.pow(width as u32) - 1; // 'width' amount of binary 1s.
// Mask the input
let in_masked: u32 = value & mask;
// Mask the previous value
let previous: u32 = self.read();
let previous_masked: u32 = previous & !(mask * 2u32.pow(offset as u32));
self.write(previous_masked | (in_masked * 2u32.pow(offset as u32)));
}
}
#[repr(C)]
#[allow(non_snake_case)]
......@@ -151,15 +160,17 @@ fn wait(i: u32) {
// // ..0111000
// // ---------
// // 000101000
// hprintln!("{:b}", t.read()).unwrap();
// assert!(t.read() == 0b101 << 3);
// t.modify(4, 3, 0b10001);
// // 000101000
// // 111
// // 001
// // 000011000
// hprintln!("{:b}", t.read()).unwrap();
// assert!(t.read() == 0b011 << 3);
// if << is used, your code will panic in dev (debug), but not in release mode
// // if << is used, your code will panic in dev (debug), but not in release mode
// t.modify(32, 3, 1);
// }
......@@ -177,22 +188,29 @@ fn main() -> ! {
// user application
fn idle(rcc: &mut RCC, gpioa: &mut GPIOA) {
// power on GPIOA
let r = rcc.AHB1ENR.read(); // read
rcc.AHB1ENR.write(r | 1 << (0)); // set enable
rcc.AHB1ENR.modify(0u8, 1u8, 1u32);
// let r = rcc.AHB1ENR.read(); // read
// rcc.AHB1ENR.write(r | 1 << (0)); // set enable
// configure PA5 as output
let r = gpioa.MODER.read() & !(0b11 << (5 * 2)); // read and mask
gpioa.MODER.write(r | 0b01 << (5 * 2)); // set output mode
gpioa.MODER.modify(10u8, 2u8, 1u32);
// let r = gpioa.MODER.read() & !(0b11 << (5 * 2)); // read and mask
// gpioa.MODER.write(r | 0b01 << (5 * 2)); // set output mode
let led_odr = &gpioa.ODR;
loop {
// set PA5 high
gpioa.BSRRH.write(1 << 5); // set bit, output hight (turn on led)
// gpioa.ODR.modify(5u8, 1u8, 1u32);
led_odr.modify(5u8, 1u8, 1u32);
// gpioa.BSRRH.write(1 << 5); // set bit, output hight (turn on led)
// gpioa.ODR.write(gpioa.ODR.read() | (1 << 5));
wait(10_000);
// set PA5 low
gpioa.BSRRL.write(1 << 5); // clear bit, output low (turn off led)
// gpioa.ODR.modify(5u8, 1u8, 0u32);
led_odr.modify(5u8, 1u8, 0u32);
// gpioa.BSRRL.write(1 << 5); // clear bit, output low (turn off led)
// gpioa.ODR.write(gpioa.ODR.read() & !(1 << 5));
wait(10_000);
}
......
......@@ -43,10 +43,10 @@ fn idle(stim: &mut Stim, rcc: RCC, gpioa: GPIOA) {
iprintln!(stim, "idle");
// power on GPIOA, RM0368 6.3.11
rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled()); // .set_bit()
// configure PA5 as output, RM0368 8.4.1
gpioa.moder.modify(|_, w| w.moder5().bits(1));
gpioa.moder.modify(|_, w| w.moder5().output() ); // .bits(1)
// at 16 Mhz, 8_000_000 cycles = period 0.5s
// at 64 Mhz, 4*8_000_000 cycles = period 0.5s
......@@ -82,23 +82,22 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
// mco2 : SYSCLK = 0b00
// mcopre : divide by 4 = 0b110
rcc.cfgr
.modify(|_, w| unsafe { w.mco2().bits(0b00).mco2pre().bits(0b110) });
rcc.cfgr.modify(|_, w| w.mco2().sysclk().mco2pre().div4() ); // w.mco2().bits(0b00).mco2pre().bits(0b110)
// power on GPIOC, RM0368 6.3.11
rcc.ahb1enr.modify(|_, w| w.gpiocen().set_bit());
rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled() ); //
// MCO_2 alternate function AF0, STM32F401xD STM32F401xE data sheet
// table 9
// AF0, gpioc reset value = AF0
// configure PC9 as alternate function 0b10, RM0368 6.2.10
gpioc.moder.modify(|_, w| w.moder9().bits(0b10));
gpioc.moder.modify(|_, w| w.moder9().alternate()); //.bits(0b10)
// otyper reset state push/pull, in reset state (don't need to change)
// ospeedr 0b11 = very high speed
gpioc.ospeedr.modify(|_, w| w.ospeedr9().bits(0b11));
gpioc.ospeedr.modify(|_, w| w.ospeedr9().very_high_speed()); //.bits(0b11)
}
// 0. Compile and run the example, in 16Mhz
......@@ -128,7 +127,7 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
//
// What is the frequency of blinking?
//
// ** your answer here **
// ** Period of 3.932 seconds from "on" to next "on", 0.2543 Hz. **
//
// commit your answers (bare6_1)
//
......@@ -137,15 +136,16 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
//
// What is the frequency of MCO2 read by the oscilloscope?
//
// ** your answer here **
// ** 4.00 MHz. **
//
// Compute the value of SYSCLK based on the oscilloscope reading
//
// ** your answer here **
// ** MCO2 reads 4 MHz, MCO2 is set to take SYSCLK (0b00) and scale
// it down by 4 (0b110 in MCO2PRE bits). This makes SYSCLK 16 MHz. **
//
// What is the peak to peak reading of the signal?
//
// ** your answer here **
// ** Disregarding ringing, 325 mVpp. With ringing, 775 mVpp. **
//
// Make a folder called "pictures" in your git project.
// Make a screen dump or photo of the oscilloscope output.
......@@ -165,7 +165,7 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
//`
// What is the frequency of blinking?
//
// ** your answer here **
// ** Period of 1.008 ("on" to "on"), 0.9921 Hz. **
//
// Commit your answers (bare6_3)
//
......@@ -173,15 +173,15 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
//
// What is the frequency of MCO2 read by the oscilloscope?
//
// ** your answer here **
// ** 16 MHz **
//
// Compute the value of SYSCLK based on the oscilloscope reading.
//
// ** your answer here **
// ** MCO2PRE is still set to 4, so SYSCLK is 4 times higher, 64 MHz. **
//
// What is the peak to peak reading of the signal?
//
// ** your answer here **
// ** With the ringing tops: 5.3 V, without ringing: 3.1 V. **
//
// Make a screen dump or photo of the oscilloscope output.
// Save the the picture as "bare_6_64mhz_high_speed".
......
......@@ -30,10 +30,23 @@ fn main() -> ! {
let p = hal::stm32::Peripherals::take().unwrap();
let rcc = p.RCC.constrain();
// 16 MHz (default, all clocks)
let clocks = rcc.cfgr.freeze();
let rcc = p.RCC;
// Output MCO2 to PC9 as SYSCLK/4:
rcc.cfgr.modify(|_, w| w.mco2().sysclk().mco2pre().div1());
// Enable GPIOC:
rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
let gpioc = p.GPIOC;
// Set Port C pin 9 to alternate function MCO2.
gpioc.moder.modify(|_, w| w.moder9().alternate());
gpioc.ospeedr.modify(|_, w| w.ospeedr9().low_speed());
// Now lock the clocks:
let rcc = rcc.constrain();
let clocks = rcc.cfgr.sysclk(84.mhz()).pclk1(42.mhz()).pclk2(42.mhz()).freeze();
let gpioa = p.GPIOA.split();
......@@ -125,11 +138,12 @@ fn main() -> ! {
//
// rcc.cfgr.sysclk(64.mhz()).pclk1(64.mhz()).pclk2(64.mhz()).freeze();
//
// ** your answer here **
// ** PCLK1 must be lower than 42 MHz. **
//
// rcc.cfgr.sysclk(84.mhz()).pclk1(42.mhz()).pclk2(64.mhz()).freeze();
//
// ** your answer here **
// ** With sysclk at 84 MHz, it is impossible to get PCLK2 at 64 MHz with only a
// prescaler that divides by integer values. Closest PCLK2 are 84 MHz and 42 MHz. **
//
// Commit your answers (bare7_1)
//
......@@ -144,15 +158,15 @@ fn main() -> ! {
//
// What is the frequency of MCO2 read by the oscilloscope.
//
// ** your answer here **
// ** 21.053 MHz **
//
// Compute the value of SYSCLK based on the oscilloscope reading.
//
// ** your answer here **
// ** MCO2 * MCO2PRE = 21.053 * 4 which is about 84 MHz. **
//
// What is the peak to peak reading of the signal.
//
// ** your answer here **
// ** 6.20 including the ringing, and without ringing 3.1 V **
//
// Make a screen dump or photo of the oscilloscope output.
// Save the the picture as "bare_6_84mhz_high_speed"
......@@ -161,17 +175,26 @@ fn main() -> ! {
//
// 3. Now reprogram the PC9 to be "Low Speed", and re-run at 84Mz.
//
// Did the frequency change in comparison to assignment 5?
// Did the frequency change in comparison to assignment 5? << Assuming last task
//
// ** your answer here **
// ** The frequency is the same. BUT, changing the divider from 4 to 1, meaning
// that MCO2 = SYSCLK = 84 MHz, the output is zero, while it is not zero with
// "very_high_speed()" on. **
//
// What is the peak to peak reading of the signal (and why did it change)?
//
// ** your answer here **
// ** Zero at MCO2 = 84 MHz and low_speed mode. 3.95 V at MCO = 21 MHz.
// The voltage changed because more current is required to drive the CLK up and
// down at higher frequency. The speed setting exists to be able to conserve
// power when only little power is needed, i.e. at low frequencies. The current
// in the low speed setting can't drive the CLK all the way up to nominal voltage,
// charge, that fast. **
//
// Make a screen dump or photo of the oscilloscope output.
// Save the the picture as "bare_6_84mhz_low_speed".
//
// ** It is the MCO2 = 84 MHz, low_speed mode I put in the pictures/ folder. **
//
// Commit your answers (bare7_3)
//
// 4. Revisit the `README.md` regarding serial communication.
......@@ -197,11 +220,16 @@ fn main() -> ! {
//
// What did you receive, and what was the output of the ITM trace.
//
// ** your answer here **
// ** Serial: abcd
// ITM: Ok 97 Ok 98 Ok 99 Ok 100 **
//
// Explain why the buffer overflows.
//
// ** your answer here **
// ** There was no buffer overflow. I instead wrote 496 bytes, it failed after 336 ITM
// outputs. It failed to echo after 425 characters. It fails because the readout (and write)
// of the registers take time, and if bytes are added faster than the cpu reads them, the
// register can be cleared to make way for new incoming bytes even before all bytes
// have been read by the program. **
//
// commit your answers (bare7_4)
//
......
......@@ -73,14 +73,19 @@ const APP: () = {
let tx = resources.TX;
let stim = &mut resources.ITM.stim[0];
let mut received: u32 = 0;
let mut errors: u32 = 0;
loop {
match block!(rx.read()) {
Ok(byte) => {
iprintln!(stim, "Ok {:?}", byte);
received += 1;
iprintln!(stim, "Ok {:?}, received: {}", byte, received);
tx.write(byte).unwrap();
}
Err(err) => {
iprintln!(stim, "Error {:?}", err);
errors += 1;
iprintln!(stim, "Error {:?}, errors: {}", err, errors);
}
}
}
......@@ -114,7 +119,7 @@ const APP: () = {
//
// 1. Our CPU now runs slower, did it effect the behavior?
//
// ** your answer here **
// ** Upon entering "aaaa", only "aa" is returned. **
//
// Commit your answer (bare8_1)
//
......@@ -128,7 +133,9 @@ const APP: () = {
// 3. The added tracing, how did that effect the performance,
// (are you know loosing more data)?
//
// ** your answer here **
// ** The amount of characters received are inconsistent, but over several tries
// of writing four bytes, the received bytes are 1 or 2 each try, while the bare8_1
// version managed 2 bytes more reliably and sometimes 3 or 4. **
//
// Commit your answer (bare8_3)
//
......
......@@ -136,15 +136,32 @@ const APP: () = {
//
// What did you receive, and what was the output of the ITM trace.
//
// ** your answer here **
// **
// USART received:
// abcd
//
// ITM received (no timestamp):
// woken..
// data 97
// goto sleep
// woken..
// data 98
// goto sleep
// woken..
// data 99
// goto sleep
//
// **
//
// Did you experience any over-run errors?
//
// ** your answer here **
// ** Only if I send about 60+ bytes at a time with the terminal. **
//
// Why does it behave differently than bare7/bare8?
//
// ** your answer here **
// ** Instead of writing the debug directly to ITM from the interrupt,
// the byte is put in a queue for use when it is less busy, i.e. in
// idle(). **
//
// Commit your answers (bare9_1)
//
......@@ -158,16 +175,30 @@ const APP: () = {
//
// What did you receive, and what was the output of the ITM trace.
//
// ** your answer here **
// **
// USART received:
// ab
//
// ITM received (without timestamp):
// bare9
// goto sleep
// woke
// After unpausing again from the error:
// n..
// data 97
// data 98
// goto sleep
// **
//
// Did you experience any over-run errors?
//
// ** your answer here **
// ** Yes **
//
// Why does it behave differently than in release mode?
// Recall how the execution overhead changed with optimization level.
//
// ** your answer here **
// ** More overhead is added to the interrupt routine, so that the execution time
// becomes longer and no longer below the time between USART character receives. **
//
// Commit your answers (bare9_2)
//
......
//! Sends "Hello, agian!" over the ITM port 0
//! Sends "Hello, again!" over the ITM port 0
//!
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
//!
......@@ -22,6 +22,6 @@ fn main() -> ! {
let mut p = Peripherals::take().unwrap();
let stim = &mut p.ITM.stim[0];
iprintln!(stim, "Hello, again!");
iprintln!(stim, "Hello, again! {:x}", 10);
loop {}
}
......@@ -16,7 +16,7 @@ monitor arm semihosting enable
# send captured ITM to the file (fifo) /tmp/itm.log
# (the microcontroller SWO pin must be connected to the programmer SWO pin)
# 16000000 must match the core clock frequency
monitor tpiu config internal /tmp/itm.log uart off 16000000
monitor tpiu config internal /tmp/itm.log uart off 16000000 # 84000000 # 64000000
# OR: make the microcontroller SWO pin output compatible with UART (8N1)
# 8000000 must match the core clock frequency
......
pictures/bare_6_16mhz_high_speed.png

32.2 KiB

pictures/bare_6_64mhz_high_speed.bmp

422 KiB

pictures/bare_6_84mhz_high_speed.bmp

422 KiB

pictures/bare_6_84mhz_low_speed.bmp

422 KiB