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 (22)
......@@ -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 **
// As the MCU encounters a value that is the max size of an 32 bit integer and tries to
// add one, the ALU will flip an overflow flag that trigger the panic.
//
// Commit your answer (bare1_1)
//
......@@ -65,11 +66,19 @@ const APP: () = {
//
// Paste the backtrace:
//
// ** your answer here
// #0 rust_begin_unwind (info=0x2000fed8) at /home/josef/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.5.6/src/lib.rs:95
// #1 0x0800039a in core::panicking::panic_fmt () at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b//library/core/src/panicking.rs:92
// #2 0x08000374 in core::panicking::panic () at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b//library/core/src/panicking.rs:50
// #3 0x08000ebe in rtic_bare1::init (_cx=...) at /home/josef/Kod/e7020e_2021/examples/rtic_bare1.rs:24
// #4 0x08000f08 in rtic_bare1::APP::main () at /home/josef/Kod/e7020e_2021/examples/rtic_bare1.rs:15
//
// Explain in your own words the chain of calls.
//
// ** your answer here
// From bottom of the stack up; RTICs main function is called, that will call the init function
// declared in this main file. This will trigger the panic and the panic_fmt functions. Im not
// sure exactly what rust_begin_unwind does, but my guess is that it collects data to help in
// the debugging process.
//
// Commit your answer (bare1_2)
//
......@@ -82,20 +91,23 @@ 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 **
// 4294967294 would correspond to 0xFFFFFFFE, which 1 for bits[31:1] and 0 for bit 0.
// This is the second highest value that can be reprecented in u32.
//
// Now continue the program, since you are in a loop
// the program will halt again at line 24.
//
// What is the value of `x`?
//
// 4294967295
//
// Explain in your own words why `x` now has this value.
//
// ** your answer here **
// Because the program added 1 to it...
//
// Now continue again.
//
......@@ -109,7 +121,9 @@ const APP: () = {
//
// Explain in your own words why a panic makes sense at this point.
//
// ** your answer here **
// The panic occures as an attempt to add 1 to the highest number representable in u32 has been
// made. As this would result in an overflow, the program paniced instead of carrying out the
// operation (x is still 4294967295 and not 0).
//
// Commit your answer (bare1_3)
//
......@@ -126,13 +140,13 @@ const APP: () = {
//
// Explain in your own words what this assembly line does.
//
// ** your answer here **
// It loads a word from sp into register r0
//
// In Cortex Registers (left) you can see the content of `r0`
//
// What value do you observe?
//
// ** your answer here **
// -2
//
// You can also get the register info from GDB directly.
//
......@@ -150,7 +164,9 @@ const APP: () = {
//
// Explain in your own words what is happening here.
//
// ** your answer here **
// The Add instruction adds a value from a register or an immedial (I think that is the correct
// word for it) to the first register. The s suffics specifies that the condition code flags
// should be updated as a result of the operation.
//
// We move to the next assembly instruction:
//
......@@ -159,7 +175,7 @@ const APP: () = {
//
// What is the reported value for `r0`
//
// ** your answer here **
// -1
//
// So far so good.
//
......@@ -190,7 +206,7 @@ const APP: () = {
//
// What does BCS do?
//
// ** your answer here **
// It branches to a label if the conditional C is set
//
// Now let's see what happens.
//
......@@ -204,7 +220,8 @@ const APP: () = {
//
// Explain in your own words where we are heading.
//
// ** your answer here **
// It seems to be moving a bunch of what I guess is adresses into the r registers and then
// branch to a panic function.
//
// To validate that your answer, let's let the program continue
//
......@@ -220,7 +237,8 @@ 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 **
// Those are the memory adresses for the move operations, so I would guess that it
// archives something there for debugging purpuses.
//
// Commit your answer (bare1_4)
//
......@@ -273,7 +291,9 @@ const APP: () = {
//
// Do you see any way this code may end up in a panic?
//
// ** your answer here **
// It seems to have removed the branch on conditional check that makes it panic on an
// overflow. I guess this would mean that it either break without an explination, or
// carries on with an incorrect x.
//
// So clearly, the "semantics" (meaning) of the program has changed.
// This is on purpose, Rust adopts "unchecked" (wrapping) additions (and subtractions)
......@@ -288,16 +308,21 @@ const APP: () = {
//
// Paste the generated assembly:
//
// ** your answer here **
// => 0x08000e9c <+24>: ldr r0, [sp, #0]
// 0x08000e9e <+26>: adds r0, #1
// 0x08000ea0 <+28>: bcs.n 0x8000eb0 <rtic_bare1::init+44>
// 0x08000ea2 <+30>: str r0, [sp, #0]
//
// Can this code generate a panic?
//
// ** your answer here **
// Yea, but a controlled one that goes to the panic handler.
//
// Is there now any reference to the panic handler?
// If not, why is that the case?
//
// ** your answer here **
// It reference the panic handler when it runs the bcs.n operation.
// It will jump to a section a few adresses down that moves some data
// and calls the panic handler.
//
// commit your answers (bare1_5)
//
......@@ -327,12 +352,17 @@ const APP: () = {
//
// Dump the generated assembly.
//
// ** your answer here **
// 0x0800024c <+12>: bkpt 0x0000
// 0x0800024e <+14>: adds r0, #1
// 0x08000250 <+16>: str r0, [sp, #4]
// 0x08000252 <+18>: bkpt 0x0000
// 0x08000254 <+20>: ldr r0, [sp, #4]
// 0x08000256 <+22>: b.n 0x800024c <rtic_bare1::init+12>
//
// Where is the local variable stored?
// What happened, and why is Rust + LLVM allowed to optimize out your code?
//
// ** your answer here **
// It only stores the variable in a register. It does this to increse speed I would guess.
//
// Commit your answers (bare1_6)
//
......@@ -348,7 +378,10 @@ const APP: () = {
//
// What is now the disassembly of the loop (in debug/dev mode):
//
// ** your answer here **
// 0x08000e9c <+24>: ldr r0, [sp, #0]
// 0x08000e9e <+26>: adds r0, #1
// 0x08000ea0 <+28>: bcs.n 0x8000eb0 <rtic_bare1::init+44>
// 0x08000ea2 <+30>: str r0, [sp, #0]
//
// commit your answers (bare1_7)
//
......
......@@ -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 43935
// End 167044018
// Diff 167000083
//
// Rebuild and run in (Cortex Release).
//
// ** your answer here **
// Start 1464520643
// End 1468520659
// Diff 4000016
//
// Compute the ratio between debug/release optimized code
// (the speedup).
//
// ** your answer here **
// The release version is 41.7 times faster
//
// 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,8 @@ fn wait(i: u32) {
//
// Answer in your own words, how they assign r0 to 1000000.
//
// ** your answer here **
// It is a two step process to write a 32 bit register. The Movw operation writes
// to the lower 16 bits, and the movt to the upper n16 bits
//
// Commit your answers (bare2_2)
//
......@@ -125,10 +137,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 **
// It seems to have optimized away the upper word as the input value for the function
// is under 2^16.
//
// Commit your answers (bare2_3)
......@@ -23,12 +23,13 @@ const APP: () = {
let start = Instant::now();
wait(1_000_000);
let diff = start.elapsed().as_cycles();
let end = Instant::now();
// notice all printing outside of the section to measure!
hprintln!("Start {:?}", start).ok();
hprintln!("End {:?}", end).ok();
// hprintln!("Diff {:?}", (end - start) ).ok();
hprintln!("Diff {:?}", diff).ok();
}
};
......@@ -62,7 +63,8 @@ fn wait(i: u32) {
//
// What is the output in the Adapter Output console?
//
// ** your answer here **
// Start Instant(21208703)
// End Instant(25208720)
//
// As you see line 31 is commented out (we never print the difference).
//
......@@ -76,7 +78,9 @@ fn wait(i: u32) {
//
// What is now the output in the Adapter Output console?
//
// ** your answer here **
// Start Instant(1308087640)
// End Instant(1312087656)
// Diff 4000016
//
// Commit your answers (bare3_1)
//
......@@ -86,7 +90,9 @@ fn wait(i: u32) {
//
// What is now the output in the Adapter Output console?
//
// ** your answer here **
// Start Instant(28537515)
// End Instant(32537531)
// Diff 4000016
//
// Commit your answers (bare3_2)
//
......@@ -95,7 +101,9 @@ fn wait(i: u32) {
//
// What is now the output in the Adapter Output console?
//
// ** your answer here **
// Start Instant(1347038883)
// End Instant(1351038906)
// Diff 4000016
//
// Commit your answers (bare3_3)
//
......
......@@ -33,12 +33,14 @@ use address::*;
// rcc, chapter 6
// gpio, chapter 8
// Here we have low level access to a bit in a register
#[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 _)
}
// Here we have low level access to a bit in a register
#[inline(always)]
fn write_u32(addr: u32, val: u32) {
unsafe {
......@@ -83,7 +85,7 @@ const APP: () = {
//
// 1. Did you enjoy the blinking?
//
// ** your answer here **
// I prefere longer intervals in my blinking, but it was quite pleasant.
//
// Now lookup the data-sheets, and read each section referred,
// 6.3.11, 8.4.1, 8.4.7
......@@ -100,12 +102,13 @@ const APP: () = {
//
// What was the error message and explain why.
//
// ** your answer here **
// error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
// I guess this is because you cant make sure that the adress is valid.
//
// 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 **
// Because you can get undefined behaviour.
//
// Commit your answers (bare4_2)
//
......@@ -118,16 +121,19 @@ const APP: () = {
//
// Why is it important that ordering of volatile operations are ensured by the compiler?
//
// ** your answer here **
// Because you can get race conditions when you have multiple read and writes to the same registers
//
// 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 you have a register being accessed before its been setup correctly yet, there would
// be undefined behaviour.
//
// 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 **
// When you have read and write operations to the same register, as in line 62-63 and
// 66-67, there would be a problem if the compiler swapped the operations around, as
// there wouldn't be any data to write if it hasn't been read yet.
//
// Commit your answers (bare4_3)
......@@ -25,6 +25,7 @@ mod stm32f40x {
pub const GPIOA_BASE: u32 = AHB1PERIPH_BASE + 0x0000;
}
use address::*;
use cortex_m_semihosting::hprint;
pub struct VolatileCell<T> {
pub value: cell::UnsafeCell<T>,
......@@ -58,7 +59,19 @@ mod stm32f40x {
impl VolatileCell<u32> {
#[inline(always)]
pub fn modify(&self, offset: u8, width: u8, value: u32) {
// your code here
let cell_val = VolatileCell::read(&self);
let mut mask = 0;
for i in 0..width {
mask |= 1 << i;
}
let masked_value = value & mask;
let return_val = (cell_val & !(mask << offset)) | masked_value << offset;
VolatileCell::write(&self, return_val)
}
}
......@@ -177,24 +190,24 @@ const APP: () = {
let r = gpioa.MODER.read() & !(0b11 << (5 * 2)); // read and mask
gpioa.MODER.write(r | 0b01 << (5 * 2)); // set output mode
// test_modify();
test_modify();
loop {
// set PA5 high
gpioa.BSRRH.write(1 << 5); // set bit, output hight (turn on led)
// gpioa.BSRRH.write(1 << 5); // set bit, output hight (turn on led)
// alternatively to set the bit high we can
// read the value, or with PA5 (bit 5) and write back
// gpioa.ODR.write(gpioa.ODR.read() | (1 << 5));
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.BSRRL.write(1 << 5); // clear bit, output low (turn off led)
// alternatively to clear the bit we can
// read the value, mask out PA5 (bit 5) and write back
// gpioa.ODR.write(gpioa.ODR.read() & !(1 << 5));
gpioa.ODR.write(gpioa.ODR.read() & !(1 << 5));
wait(10_000);
}
}
......@@ -214,6 +227,8 @@ const APP: () = {
//
// Run and see that the program behaves the same.
//
// It does blink the same if thats what you mean.
//
// Commit your answers (bare5_1)
//
// 2. Extend the read/write API with a `modify` for u32, taking the
......@@ -241,6 +256,6 @@ const APP: () = {
// What if we could automatically generate that from Vendors specifications (SVD files)?
// Wouldn't that be great?
//
// ** your answer here **
// Sure, I guess...
//
// Commit your answers (bare5_2)
......@@ -70,7 +70,7 @@ const APP: () = {
// .pclk1(64.mhz())
// .pclk2(64.mhz())
// .freeze();
//
// let _clocks = rcc
// .cfgr
// .sysclk(84.mhz())
......@@ -202,11 +202,11 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
//
// `rcc.cfgr.sysclk(64.mhz()).pclk1(64.mhz()).pclk2(64.mhz()).freeze()`;
//
// ** your answer here **
// PCLK1 can only run up to 48MHz
//
// `rcc.cfgr.sysclk(84.mhz()).pclk1(42.mhz()).pclk2(64.mhz()).freeze();`
//
// ** your answer here **
// I guess that there should be some kind of divission factor between pcklk1 and 2 or something
//
// Start `stm32cubemx` and select or create a project targeting stm32f401.
// Go to the graphical clock configuration view.
......@@ -217,16 +217,14 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) {
//
// What happens?
//
// ** your answer here **
// Nothing happens. The led is off
//
// Try to setup the clock according to:
//
// What happens?
// The led blinks way to fast
//
// `rcc.cfgr.sysclk(84.mhz()).pclk1(42.mhz()).pclk2(64.mhz()).freeze();`
//
// ** your answer here **
//
// Commit your answers (bare6_0)
//
// 1. In this example you will use RTT.
......