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
  • master
1 result

Target

Select target project
  • Frappe/e7020e_2021
  • rognda-6/e7020e_2021
  • Klomega/e7020e_2021
  • pln/e7020e_2021
  • CarlOsterberg/e7020e_2021
  • jonjac-6/e7020e_2021
  • deux-babiri-futari/e7020e_2021
  • samgra-7/e7020e_2021
  • JosefUtbult/e7020e_2021
  • edwkll-7/e7020e_2021
10 results
Select Git revision
  • master
1 result
Show changes
Commits on Source (17)
......@@ -20,13 +20,13 @@ const APP: () = {
fn init(_cx: init::Context) {
let mut x = core::u32::MAX - 1;
loop {
// cortex_m::asm::bkpt();
x += 1;
// cortex_m::asm::bkpt();
cortex_m::asm::bkpt();
x = x.wrapping_add(1);
cortex_m::asm::bkpt();
// prevent optimization by read-volatile (unsafe)
unsafe {
core::ptr::read_volatile(&x);
//core::ptr::read_volatile(&x);
}
}
}
......@@ -45,11 +45,12 @@ const APP: () = {
//
// Paste the error message:
//
// ** your answer here **
// panicked at 'attempt to add with overflow', examples/rtic_bare1.rs:24:13
//
// Explain in your own words why the code panic:ed.
//
// ** your answer here **
// The program tried to add to 1 to an integer variable which already
// were on the integer max (2^32-1) thus resulting in a panic
//
// Commit your answer (bare1_1)
//
......@@ -65,11 +66,20 @@ const APP: () = {
//
// Paste the backtrace:
//
// ** your answer here
// #0 lib::__bkpt () at asm/lib.rs:49
// #1 0x0800104e in cortex_m::asm::bkpt () at /home/frappe/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.1/src/asm.rs:15
// #2 panic_semihosting::panic (info=0x2000fed8) at /home/frappe/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.5.6/src/lib.rs:92
// #3 0x0800039a in core::panicking::panic_fmt () at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b//library/core/src/panicking.rs:92
// #4 0x08000374 in core::panicking::panic () at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b//library/core/src/panicking.rs:50
// #5 0x08000ebe in rtic_bare1::init (_cx=...) at /home/frappe/document/E7020E/software_labs/e7020e_2021/examples/rtic_bare1.rs:24
// #6 0x08000f08 in rtic_bare1::APP::main () at /home/frappe/document/E7020E/software_labs/e7020e_2021/examples/rtic_bare1.rs:15
//
// Explain in your own words the chain of calls.
//
// ** your answer here
// App calls init, init initializes a mutable variable x to int max -2
// init loops while adding to x, x goes over max, rust calls panic
// panic calls panic_format, panic_fmt calls semihosting_panic
// panic semihosting calls brakpoint.
//
// Commit your answer (bare1_2)
//
......@@ -82,11 +92,11 @@ const APP: () = {
//
// What is the value of `x`?
//
// ** your answer here **
// 4294967294
//
// Explain in your own words where this value comes from.
//
// ** your answer here **
// core::u32::MAX = 4294967295 = 2^32-1; we assign x to be MAX-1
//
// Now continue the program, since you are in a loop
// the program will halt again at line 24.
......@@ -95,7 +105,7 @@ const APP: () = {
//
// Explain in your own words why `x` now has this value.
//
// ** your answer here **
// we added 1 to x
//
// Now continue again.
//
......@@ -109,7 +119,9 @@ const APP: () = {
//
// Explain in your own words why a panic makes sense at this point.
//
// ** your answer here **
// Since x had the value of MAX which is the maximum value x can't get bigger.
// since the purpose of adding to a variable is to make it bigger,
// and if it can't get any bigger rust has chosen to panic.
//
// Commit your answer (bare1_3)
//
......@@ -126,13 +138,13 @@ const APP: () = {
//
// Explain in your own words what this assembly line does.
//
// ** your answer here **
// load the value of the address sp + offset 0 to register address r0
//
// In Cortex Registers (left) you can see the content of `r0`
//
// What value do you observe?
//
// ** your answer here **
// -2 (MAX-2)
//
// You can also get the register info from GDB directly.
//
......@@ -150,7 +162,7 @@ const APP: () = {
//
// Explain in your own words what is happening here.
//
// ** your answer here **
// add to the register r0 the immidiate constant 1
//
// We move to the next assembly instruction:
//
......@@ -159,7 +171,7 @@ const APP: () = {
//
// What is the reported value for `r0`
//
// ** your answer here **
// -1 (MAX) (0xffffffff)
//
// So far so good.
//
......@@ -190,7 +202,7 @@ const APP: () = {
//
// What does BCS do?
//
// ** your answer here **
// BCS.n branches if there was a carry bit from the last addition. (.n makes the instruction to be 16 bits)
//
// Now let's see what happens.
//
......@@ -204,7 +216,7 @@ const APP: () = {
//
// Explain in your own words where we are heading.
//
// ** your answer here **
// We are heading toward a branch to the panic "function"
//
// To validate that your answer, let's let the program continue
//
......@@ -220,7 +232,7 @@ const APP: () = {
// Hint 3, the code is generated by the Rust compiler to produce the error message.
// there is no "magic" here, just a compiler generating code...
//
// ** your answer here **
// it is to generate the error message.
//
// Commit your answer (bare1_4)
//
......@@ -273,7 +285,7 @@ const APP: () = {
//
// Do you see any way this code may end up in a panic?
//
// ** your answer here **
// No since there is no branching when there is a carry.
//
// So clearly, the "semantics" (meaning) of the program has changed.
// This is on purpose, Rust adopts "unchecked" (wrapping) additions (and subtractions)
......@@ -288,16 +300,32 @@ const APP: () = {
//
// Paste the generated assembly:
//
// ** your answer here **
// 0x08000e84 <+0>: push {r4, r6, r7, lr}
// 0x08000e86 <+2>: add r7, sp, #8
// 0x08000e88 <+4>: sub sp, #16
// 0x08000e8a <+6>: movw r0, #5808 ; 0x16b0
// 0x08000e8e <+10>: mov r4, sp
// 0x08000e90 <+12>: movt r0, #2048 ; 0x800
// 0x08000e94 <+16>: ldr r0, [r0, #0]
// 0x08000e96 <+18>: str r0, [sp, #0]
// 0x08000e98 <+20>: bl 0x8000fa6 <lib::__bkpt>
// => 0x08000e9c <+24>: ldr r0, [sp, #0]
// 0x08000e9e <+26>: adds r0, #1
// 0x08000ea0 <+28>: str r0, [sp, #0]
// 0x08000ea2 <+30>: bl 0x8000fa6 <lib::__bkpt>
// 0x08000ea6 <+34>: mov r0, r4
// 0x08000ea8 <+36>: bl 0x8000f46 <_ZN4core3ptr13read_volatile17hb977623ea709e27cE>
// 0x08000eac <+40>: b.n 0x8000e98 <rtic_bare1::init+20>
//
// Can this code generate a panic?
//
// ** your answer here **
// No, no branch to a panic "function"
//
// Is there now any reference to the panic handler?
// If not, why is that the case?
//
// ** your answer here **
// There is no reference since there is no need for it as we have stated that
// wrapping is the intended outcome
//
// commit your answers (bare1_5)
//
......@@ -327,12 +355,17 @@ const APP: () = {
//
// Dump the generated assembly.
//
// ** your answer here **
// 0x08000240 <+0>: push {r7, lr}
// 0x08000242 <+2>: mov r7, sp
// => 0x08000244 <+4>: bkpt 0x0000
// 0x08000246 <+6>: bkpt 0x0000
// 0x08000248 <+8>: b.n 0x8000244 <rtic_bare1::init+4>
//
// Where is the local variable stored?
// What happened, and why is Rust + LLVM allowed to optimize out your code?
//
// ** your answer here **
// Since the local variable is no longer read then the compiler can
// optimize away the variable.
//
// Commit your answers (bare1_6)
//
......
......@@ -39,7 +39,7 @@ const APP: () = {
hprintln!("End {:?}", end).ok();
hprintln!("Diff {:?}", end.wrapping_sub(start)).ok();
// wait(100);
wait(100);
}
};
......@@ -71,16 +71,20 @@ fn wait(i: u32) {
// What is the output in the Adapter Output console?
// (Notice, it will take a while we loop one million times at only 16 MHz.)
//
// ** your answer here **
// Start 21255840
// End 188255923
// Diff 167000083
//
// Rebuild and run in (Cortex Release).
//
// ** your answer here **
// Start 1446208745
// End 1450208761
// Diff 4000016
//
// Compute the ratio between debug/release optimized code
// (the speedup).
//
// ** your answer here **
// The release version is 41.74 times faster than the debug version
//
// commit your answers (bare2_1)
//
......@@ -105,7 +109,14 @@ fn wait(i: u32) {
//
// Dump generated assembly for the "wait" function.
//
// ** your answer here **
// => 0x080004a0 <+0>: push {r7, lr}
// 0x080004a2 <+2>: mov r7, sp
// 0x080004a4 <+4>: movw r0, #16960 ; 0x4240
// 0x080004a8 <+8>: movt r0, #15
// 0x080004ac <+12>: nop
// 0x080004ae <+14>: subs r0, #1
// 0x080004b0 <+16>: bne.n 0x80004ac <rtic_bare2::wait+12>
// 0x080004b2 <+18>: pop {r7, pc}
//
// Under the ARM calling convention, r0.. is used as arguments.
// However in this case, we se that r0 is set by the assembly instructions,
......@@ -115,7 +126,9 @@ fn wait(i: u32) {
//
// Answer in your own words, how they assign r0 to 1000000.
//
// ** your answer here **
// movt "loads" the immidiate value to the upper part of the word [31:16].
// movw "loads" the immidiate value to the lower part of the word [15:0].
// they are then "or":ed together.
//
// Commit your answers (bare2_2)
//
......@@ -125,10 +138,16 @@ fn wait(i: u32) {
//
// Dump the generated assembly for the "wait" function.
//
// ** your answer here **
// => 0x080004a0 <+0>: push {r7, lr}
// 0x080004a2 <+2>: mov r7, sp
// 0x080004a4 <+4>: nop
// 0x080004a6 <+6>: subs r0, #1
// 0x080004a8 <+8>: bne.n 0x80004a4 <rtic_bare2::wait+4>
// 0x080004aa <+10>: pop {r7, pc}
//
// Answer in your own words, why you believe the generated code differs?
//
// ** your answer here **
// Now that the function needs to be more generic (it has several uses), the
// argument is now stored and used inside r0 instead of initialized inside the function.
//
// Commit your answers (bare2_3)
......@@ -25,10 +25,13 @@ const APP: () = {
wait(1_000_000);
let end = Instant::now();
let diff = Instant::elapsed(&start);
// notice all printing outside of the section to measure!
hprintln!("Start {:?}", start).ok();
hprintln!("End {:?}", end).ok();
// hprintln!("Diff {:?}", (end - start) ).ok();
//let diff = Instant::duration_since(&end,start);
hprintln!("Diff {:?}", diff.as_cycles()).ok();
}
};
......@@ -62,7 +65,8 @@ fn wait(i: u32) {
//
// What is the output in the Adapter Output console?
//
// ** your answer here **
// Start Instant(2694714472)
// End Instant(2698714489)
//
// As you see line 31 is commented out (we never print the difference).
//
......@@ -76,7 +80,9 @@ fn wait(i: u32) {
//
// What is now the output in the Adapter Output console?
//
// ** your answer here **
// Start Instant(2100880231)
// End Instant(2104880247)
// Diff 4000016
//
// Commit your answers (bare3_1)
//
......@@ -86,7 +92,9 @@ fn wait(i: u32) {
//
// What is now the output in the Adapter Output console?
//
// ** your answer here **
// Start Instant(20606036)
// End Instant(24606052)
// Diff 4000016
//
// Commit your answers (bare3_2)
//
......@@ -95,7 +103,10 @@ fn wait(i: u32) {
//
// What is now the output in the Adapter Output console?
//
// ** your answer here **
// Start Instant(2395620599)
// End Instant(2399620615)
// Diff 4000020
//
// Commit your answers (bare3_3)
//
......
......@@ -36,7 +36,7 @@ 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 _)
//core::ptr::read_volatile(addr as *const _);
}
#[inline(always)]
......@@ -58,22 +58,22 @@ const APP: () = {
fn init(_cx: init::Context) {
// power on GPIOA
let r = read_u32(RCC_AHB1ENR); // read
write_u32(RCC_AHB1ENR, r | 1); // set enable
write_u32(RCC_AHB1ENR, r | 1); // set enable GPIOAEN, IOPort A clock
// 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
let r = read_u32(GPIOA_MODER) & !(0b11 << (5 * 2)); // read and mask, keep all values except MODER5, MODER5 = 00.
write_u32(GPIOA_MODER, r | 0b01 << (5 * 2)); // set output mode, set MODER5 to 01 = general purpose 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)
write_u32(GPIOA_BSRR, 1 << 5); // set bit, output hight (turn on led), sets the 5:th ODRx bit
wait(10_000);
// set PA5 low
write_u32(GPIOA_BSRR, 1 << (5 + 16)); // clear bit, output low (turn off led)
write_u32(GPIOA_BSRR, 1 << (5 + 16)); // clear bit, output low (turn off led), resets the 5:th ODRx bit
wait(10_000);
}
}
......@@ -83,7 +83,7 @@ const APP: () = {
//
// 1. Did you enjoy the blinking?
//
// ** your answer here **
// Yes, it is very nice.
//
// Now lookup the data-sheets, and read each section referred,
// 6.3.11, 8.4.1, 8.4.7
......@@ -100,12 +100,13 @@ const APP: () = {
//
// What was the error message and explain why.
//
// ** your answer here **
// This operation is unsafe and requires an unsafe function or block.
// The function read_volatile is declared to be 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 **
// It is unsafe because it can't guarantee the value is the expected value.
//
// Commit your answers (bare4_2)
//
......@@ -118,16 +119,21 @@ const APP: () = {
//
// Why is it important that ordering of volatile operations are ensured by the compiler?
//
// ** your answer here **
// Since you are accessing memory outside of the aqusition of rust
// the ordering is very important.
//
// 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 **
// If the write instruction on line 65 before the read instruction on line 64
// The word on address GPIOA_MODER would look completely different since r is no longer a copy
// with modifications for the word you are writing to.
// Or if one of the writes for PA5 happens before any of the initialization writes to RCC_AHB1ENR or BPIOA_MODER.
//
// 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 **
// Since the PA5 write does not depend on anything from the initialization in software point of view,
// Theoretically it could happen.
//
// Commit your answers (bare4_3)
......@@ -59,6 +59,16 @@ mod stm32f40x {
#[inline(always)]
pub fn modify(&self, offset: u8, width: u8, value: u32) {
// your code here
let current = self.read();
let mut mask = 0;
for _ in 0..width {
mask = (mask << 1 | 1);
}
//mask = mask << offset;
let test = (current & !(mask << offset));
let test2 = ((value & (mask))<<offset);
let modified = (current & !(mask << offset)) | ((value & (mask))<<offset);
self.write(modified);
}
}
......@@ -170,12 +180,16 @@ const APP: () = {
let gpioa = unsafe { &mut *GPIOA::get() }; // get the reference to GPIOA in memory
// power on GPIOA
let r = rcc.AHB1ENR.read(); // read
rcc.AHB1ENR.write(r | 1 << (0)); // set enable
// let r = rcc.AHB1ENR.read(); // read
// rcc.AHB1ENR.write(r | 1 << (0)); // set enable
rcc.AHB1ENR.modify(0, 1, 1);
// 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
// let r = gpioa.MODER.read() & !(0b11 << (5 * 2)); // read and mask
// gpioa.MODER.write(r | 0b01 << (5 * 2)); // set output mode
gpioa.MODER.modify(5*2, 2, 0b01);
//test_modify();
......@@ -241,6 +255,6 @@ const APP: () = {
// What if we could automatically generate that from Vendors specifications (SVD files)?
// Wouldn't that be great?
//
// ** your answer here **
// Yes.
//
// Commit your answers (bare5_2)
......@@ -18,7 +18,7 @@ use stm32f4xx_hal::{
stm32::{self, GPIOC, RCC},
};
const OFFSET: u32 = 8_000_000;
const OFFSET: u32 = 24_000_000;
#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
const APP: () = {
......@@ -55,14 +55,14 @@ const APP: () = {
let rcc = device.RCC.constrain();
let _clocks = rcc.cfgr.freeze();
// let _clocks = rcc.cfgr.freeze();
// Set up the system clock. 48 MHz?
// let _clocks = rcc
// .cfgr
// .sysclk(48.mhz())
// .pclk1(24.mhz())
// .freeze();
let _clocks = rcc
.cfgr
.sysclk(48.mhz())
.pclk1(24.mhz())
.freeze();
// let _clocks = rcc
// .cfgr
......@@ -202,7 +202,7 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
//
// `rcc.cfgr.sysclk(64.mhz()).pclk1(64.mhz()).pclk2(64.mhz()).freeze()`;
//
// ** your answer here **
// PCLK1 needs to have a clock frequency of <= 42 MHz
//
// `rcc.cfgr.sysclk(84.mhz()).pclk1(42.mhz()).pclk2(64.mhz()).freeze();`
//
......@@ -237,15 +237,15 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
//
// What is the (default) MCU (SYSCLK) frequency?
//
// ** your answer here **
// 16 Mhz
//
// What is the (default) DWT CYCCNT frequency?
//
// ** your answer here **
// Same as SYSCLK?
//
// What is the frequency of blinking?
//
// ** your answer here **
// 1 hz
//
// Commit your answers (bare6_1)
//
......@@ -271,7 +271,7 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
//`
// What is the frequency of blinking?
//
// ** your answer here **
// about 3 Hz
//
// Now change the constant `OFFSET` so you get the same blinking frequency as in 1.
// Test and validate that you got the desired behavior.
......