diff --git a/examples/rtic_bare1.rs b/examples/rtic_bare1.rs index 11248f4e1eaa427af7aff5f812ad18ea94a4037c..e6eee85600b61383687342a5b8b0a553eed20cc7 100644 --- a/examples/rtic_bare1.rs +++ b/examples/rtic_bare1.rs @@ -20,14 +20,14 @@ 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 { + /*unsafe { core::ptr::read_volatile(&x); - } + }*/ } } }; @@ -45,11 +45,14 @@ const APP: () = { // // Paste the error message: // -// ** your answer here ** +// ** My 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 ** +// ** My answer here ** +// core::u32::MAX - 1 sets the value of x to the maximum value a 32 unsigned bit can hold - 1 and +// then starts a loop with an addition of 1 to x, that's a recipe for overflow. // // Commit your answer (bare1_1) // @@ -65,11 +68,28 @@ const APP: () = { // // Paste the backtrace: // -// ** your answer here +// ** My answer here ** +/* + #0 lib::__bkpt () at asm/lib.rs:49 + #1 0x0800104e in cortex_m::asm::bkpt () at /home/decending/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.1/src/asm.rs:15 + #2 rust_begin_unwind (info=0x2000fed8) at /home/decending/.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/decending/Desktop/e7020e_2021/examples/rtic_bare1.rs:24 + #6 0x08000f08 in rtic_bare1::APP::main () at /home/decending/Desktop/e7020e_2021/examples/rtic_bare1.rs:15 +*/ // // Explain in your own words the chain of calls. // -// ** your answer here +// ** My answer here ** +// This will run from the "bottom up": +// 0# We enter a function with a breakpoint +// 1# Calling function for breakpoint +// 2# We unwind to catch the panic +// 3# We continue to handle the panic +// 4# We start to panic +// 5# We start the init task. +// 6# We call the APP::main task, // // Commit your answer (bare1_2) // @@ -82,11 +102,14 @@ const APP: () = { // // What is the value of `x`? // -// ** your answer here ** +// ** My answer here ** +// x = 4294967294; // // Explain in your own words where this value comes from. // -// ** your answer here ** +// ** My answer here ** +// This is the value of a 32-bit unsigned integer with the form: +// 11111111111111111111111111111110, which is core::u32::MAX - 1. // // Now continue the program, since you are in a loop // the program will halt again at line 24. @@ -95,7 +118,10 @@ const APP: () = { // // Explain in your own words why `x` now has this value. // -// ** your answer here ** +// ** My answer here ** +// x = 4294967295; +// 4294967294 + 1 = 4294967295 +// This is what the loop is meant to do, so nothing strange here. // // Now continue again. // @@ -109,7 +135,9 @@ const APP: () = { // // Explain in your own words why a panic makes sense at this point. // -// ** your answer here ** +// ** My answer here ** +// Since we're not using any sort of wrapping the new number, which is 4294967296 can't be contained +// in a u32 datastructure, so this becomes an undefined behaviour and hence the code panics. // // Commit your answer (bare1_3) // @@ -126,13 +154,15 @@ const APP: () = { // // Explain in your own words what this assembly line does. // -// ** your answer here ** +// ** My answer here ** +// It'll load the sp with an immediate offset of 0 into r0. This should be our x. // // In Cortex Registers (left) you can see the content of `r0` // // What value do you observe? // -// ** your answer here ** +// ** My answer here ** +// -2 = 0xfffffffe. // // You can also get the register info from GDB directly. // @@ -150,7 +180,8 @@ const APP: () = { // // Explain in your own words what is happening here. // -// ** your answer here ** +// ** My answer here ** +// We will add r0 and the immidate value 1 together (x + 1) // // We move to the next assembly instruction: // @@ -159,7 +190,8 @@ const APP: () = { // // What is the reported value for `r0` // -// ** your answer here ** +// ** My answer here ** +// 0xffffffff = -1 // // So far so good. // @@ -190,7 +222,8 @@ const APP: () = { // // What does BCS do? // -// ** your answer here ** +// ** My answer here ** +// It'll check for the carry flag and if it is set the instruction will jump to the provided address. // // Now let's see what happens. // @@ -204,7 +237,8 @@ const APP: () = { // // Explain in your own words where we are heading. // -// ** your answer here ** +// ** My answer here ** +// We are heading into the panicking system. // // To validate that your answer, let's let the program continue // @@ -220,9 +254,10 @@ 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 ** +// ** My answer here ** +// We save the relevant information regarding the panic. // -// Commit your answer (bare1_4) +// Commit your answer (bare1_3) // // 5. Now we can remove the break point (click the `Remove All Breakpoints`), // and instead uncomment the two breakpoint instructions (on lines 23 and 25). @@ -233,7 +268,7 @@ const APP: () = { // // The disassembly should look like this: // -// +//Release // 0x08000f18 <+20>: bl 0x800103e <lib::__bkpt> // => 0x08000f1c <+24>: ldr r0, [sp, #0] // 0x08000f1e <+26>: adds r0, #1 @@ -273,7 +308,8 @@ const APP: () = { // // Do you see any way this code may end up in a panic? // -// ** your answer here ** +// ** My answer here ** +// There is no reference to the panic handler, so this will not be able to generate a panic. I guess the default is to have a wrapping addition in release mode. // // So clearly, the "semantics" (meaning) of the program has changed. // This is on purpose, Rust adopts "unchecked" (wrapping) additions (and subtractions) @@ -288,16 +324,32 @@ const APP: () = { // // Paste the generated assembly: // -// ** your answer here ** +// ** My answer here ** +/* +Dump of assembler code for function rtic_bare1::APP::main: + 0x0800025a <+0>: push {r7, lr} + 0x0800025c <+2>: mov r7, sp + 0x0800025e <+4>: movw r0, #60688 ; 0xed10 +=> 0x08000262 <+8>: cpsid i + 0x08000264 <+10>: movt r0, #57344 ; 0xe000 + 0x08000268 <+14>: ldr r1, [r0, #0] + 0x0800026a <+16>: orr.w r1, r1, #2 + 0x0800026e <+20>: str r1, [r0, #0] + 0x08000270 <+22>: bl 0x8000240 <rtic_bare1::init> +End of assembler dump. +*/ // // Can this code generate a panic? // -// ** your answer here ** +// ** My answer here ** +// No, there is no reference to the panic handler. // // Is there now any reference to the panic handler? // If not, why is that the case? // -// ** your answer here ** +// ** My answer here ** +// The reference to the panic handler is not present anymore, which indicates that the +// compiler have found the code to be unable to generate a panic. // // commit your answers (bare1_5) // @@ -327,12 +379,22 @@ const APP: () = { // // Dump the generated assembly. // -// ** your answer here ** +// ** My answer here ** +/* +Dump of assembler code for function rtic_bare1::init: + 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> +End of assembler dump. +*/ // // Where is the local variable stored? // What happened, and why is Rust + LLVM allowed to optimize out your code? // -// ** your answer here ** +// ** My answer here ** +// It is not stored anywhere, as it is optimized out. Since x is not used, the rust compiler removed it. // // Commit your answers (bare1_6) // @@ -386,4 +448,4 @@ const APP: () = { // If you write a library depending on wrapping arithmetics // do NOT rely on a compiler flag. (The end user might compile // it without this flag enabled, and thus get erroneous results.) -// +// \ No newline at end of file diff --git a/examples/rtic_bare2.rs b/examples/rtic_bare2.rs index 04266d7cbbfa598a29b99e95f7310f0c80c0967c..a9e867e344fa5e60a86d0d8ff2f82ed8dbb2fcdd 100644 --- a/examples/rtic_bare2.rs +++ b/examples/rtic_bare2.rs @@ -39,7 +39,7 @@ const APP: () = { hprintln!("End {:?}", end).ok(); hprintln!("Diff {:?}", end.wrapping_sub(start)).ok(); - // wait(100); + wait(100); } }; @@ -61,7 +61,7 @@ fn wait(i: u32) { // If it does not auto-open, then copy paste the path shown in your browser. // // Notice, it will try to document all dependencies, you may have only one -// one panic handler, so temporarily comment out all but one in `Cargo.toml`. +// panic handler, so temporarily comment out all but one in `Cargo.toml`. // // In the docs, search (`S`) for DWT, and click `cortex_m::peripheral::DWT`. // Read the API docs. @@ -71,16 +71,24 @@ 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 ** +// ** My answer here ** +// Start 233354 +// End 167233437 +// Diff 167000083 // // Rebuild and run in (Cortex Release). // -// ** your answer here ** +// ** My answer here ** +// Start 1590210211 +// End 1594210227 +// Diff 4000016 // // Compute the ratio between debug/release optimized code // (the speedup). // -// ** your answer here ** +// ** My answer here ** +// 167000083 / 4000016 = 41.75 +// Release is 41.75 times faster than debug, or 4175% faster // // commit your answers (bare2_1) // @@ -105,7 +113,17 @@ fn wait(i: u32) { // // Dump generated assembly for the "wait" function. // -// ** your answer here ** +// ** My 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 +133,13 @@ fn wait(i: u32) { // // Answer in your own words, how they assign r0 to 1000000. // -// ** your answer here ** +// ** My answer here ** +// movw - This instruction will set the bottom half of the register +// to 16960, so the bottom half will be: 0100001001000000 +// movt - This instruction will set the top half of the register +// to 15, so the top half will be: 0000000000001111 +// Put together: +// 00000000000011110100001001000000 (binary) = 1000000 (decimal) // // Commit your answers (bare2_2) // @@ -125,10 +149,20 @@ fn wait(i: u32) { // // Dump the generated assembly for the "wait" function. // -// ** your answer here ** +// ** My 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 ** +// ** My answer here ** +// Because the variable is different, if we change the second call to +// to contain the same variable we get the same generated code. // -// Commit your answers (bare2_3) +// Commit your answers (bare2_3) \ No newline at end of file diff --git a/examples/rtic_bare3.rs b/examples/rtic_bare3.rs index 9173175c051d4b3e4615e0db20d2b08265d59763..105d2dc7eec879bea5e2b7cbd31be739a01f2e15 100644 --- a/examples/rtic_bare3.rs +++ b/examples/rtic_bare3.rs @@ -23,12 +23,12 @@ const APP: () = { let start = Instant::now(); wait(1_000_000); - let end = Instant::now(); + let end = start.elapsed(); // notice all printing outside of the section to measure! hprintln!("Start {:?}", start).ok(); - hprintln!("End {:?}", end).ok(); - // hprintln!("Diff {:?}", (end - start) ).ok(); + hprintln!("End {:?}", end.as_cycles()).ok(); + hprintln!("Diff {:?}", (end.as_cycles()) ).ok(); } }; @@ -62,7 +62,9 @@ fn wait(i: u32) { // // What is the output in the Adapter Output console? // -// ** your answer here ** +// ** My answer here ** +// Start Instant(2158334454) +// End Instant(2162334471) // // As you see line 31 is commented out (we never print the difference). // @@ -76,7 +78,10 @@ fn wait(i: u32) { // // What is now the output in the Adapter Output console? // -// ** your answer here ** +// ** My answer here ** +// Start Instant(3665593903) +// End Instant(3669593919) +// Diff 4000016 // // Commit your answers (bare3_1) // @@ -86,7 +91,11 @@ fn wait(i: u32) { // // What is now the output in the Adapter Output console? // -// ** your answer here ** +// ** My answer here ** +// (Isn't this just the same exercise as 1?) +// Start Instant(3665593903) +// End Instant(3669593919) +// Diff 4000016 // // Commit your answers (bare3_2) // @@ -95,7 +104,10 @@ fn wait(i: u32) { // // What is now the output in the Adapter Output console? // -// ** your answer here ** +// ** My answer here ** +// Start Instant(1120238038) +// End 4000016 +// Diff 4000016 // // Commit your answers (bare3_3) // @@ -126,4 +138,4 @@ fn wait(i: u32) { // We are working to further generalize timing semantics, by building // on a richer abstraction `https://docs.rs/embedded-time/0.10.1/embedded_time/`. // -// Support for embedded time is projected for next RTIC release. +// Support for embedded time is projected for next RTIC release. \ No newline at end of file diff --git a/examples/rtic_bare4.rs b/examples/rtic_bare4.rs index 1d53d13715b0afe372d3ab430e5fe1c301fb740a..121c0d2cd9020dbab92fd1d1bc8ef995defef44c 100644 --- a/examples/rtic_bare4.rs +++ b/examples/rtic_bare4.rs @@ -83,7 +83,9 @@ const APP: () = { // // 1. Did you enjoy the blinking? // -// ** your answer here ** +// ** My answer here ** +// It was annoying in the corner of my vision and once I noticed it +// I couldn't unnotice it. // // Now lookup the data-sheets, and read each section referred, // 6.3.11, 8.4.1, 8.4.7 @@ -100,12 +102,15 @@ const APP: () = { // // What was the error message and explain why. // -// ** your answer here ** +// ** My answer here ** +// We're trying to use unsafe code outside of an unsafe bracket. // // 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 ** +// ** My answer here ** +// There are conditions, which if met, will have undefined behaviour. +// It's not that the function itself is always unsafe, but sometimes it can be. // // Commit your answers (bare4_2) // @@ -118,16 +123,22 @@ const APP: () = { // // Why is it important that ordering of volatile operations are ensured by the compiler? // -// ** your answer here ** +// ** My answer here ** +// The volatile operations might have different results between accesses. // // 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 ** +// ** My answer here ** +// I don't know about HORRIBLY wrong, but changing around the order in +// init will not show any errors, yet the led will not blink. // // 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 ** +// ** My answer here ** +// If we are working with interrupts there's no guarantee that things will pan out +// the way we imagined it, which could interfer with volatile read / writes if the tasks +// work with the same register. // -// Commit your answers (bare4_3) +// Commit your answers (bare4_3) \ No newline at end of file diff --git a/examples/rtic_bare5.rs b/examples/rtic_bare5.rs index 5686e1b7a24c32db2f45dd120b87c33605af10ee..0de20a307eb4b852faab2db3535f6cf10d1d03e1 100644 --- a/examples/rtic_bare5.rs +++ b/examples/rtic_bare5.rs @@ -58,7 +58,16 @@ mod stm32f40x { impl VolatileCell<u32> { #[inline(always)] pub fn modify(&self, offset: u8, width: u8, value: u32) { - // your code here + let mut my_mask = 0; + let mut new_value = self.read(); + let a = 2 as u32; + + for i in 0..width{ + my_mask += a.pow(i as u32); + } + new_value = new_value + (value & my_mask) * a.pow(offset as u32) - (new_value & (my_mask * a.pow(offset as u32))); + //let new_value = my_mask; //Test function + &self.write(new_value); } } @@ -177,24 +186,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); } } @@ -243,4 +252,4 @@ const APP: () = { // // ** your answer here ** // -// Commit your answers (bare5_2) +// Commit your answers (bare5_2) \ No newline at end of file diff --git a/examples/rtic_bare6.rs b/examples/rtic_bare6.rs index 255ff36543eba6a24d3004793164498294fc1643..40a62fef4d0dfec066a79670dd1214c5e5dfcda0 100644 --- a/examples/rtic_bare6.rs +++ b/examples/rtic_bare6.rs @@ -55,28 +55,28 @@ 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 - // .sysclk(64.mhz()) - // .pclk1(64.mhz()) - // .pclk2(64.mhz()) - // .freeze(); - // - // let _clocks = rcc - // .cfgr - // .sysclk(84.mhz()) - // .pclk1(42.mhz()) - // .pclk2(64.mhz()) - // .freeze(); + /*let _clocks = rcc + .cfgr + .sysclk(64.mhz()) + .pclk1(64.mhz()) + .pclk2(64.mhz()) + .freeze();*/ + + let _clocks = rcc + .cfgr + .sysclk(84.mhz()) + .pclk1(42.mhz()) + .pclk2(64.mhz()) + .freeze(); // pass on late resources init::LateResources { @@ -121,23 +121,26 @@ 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| unsafe { w.mco2().bits(0b00).mco2pre().bits(0b110) }); + .modify(|_, w| unsafe { w.mco2().sysclk().mco2pre().div4() }); // 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().bits(0b10)); + gpioc.moder.modify(|_, w| w.moder9().alternate()); // 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()); } // 0. Background reading: @@ -202,11 +205,14 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // `rcc.cfgr.sysclk(64.mhz()).pclk1(64.mhz()).pclk2(64.mhz()).freeze()`; // -// ** your answer here ** +// ** My answer here ** +// pclk1 can only handle up to 42mhz // // `rcc.cfgr.sysclk(84.mhz()).pclk1(42.mhz()).pclk2(64.mhz()).freeze();` // -// ** your answer here ** +// ** My answer here ** +// the pclk1 and pclk2 configurations (42 and 64) doesn't seem to be compatible with the sysclk. +// The pclk1 and pclk2 clock speeds need to be sysclk / (1 or 2 or 4 or 8 or 16) to be compatible. // // Start `stm32cubemx` and select or create a project targeting stm32f401. // Go to the graphical clock configuration view. @@ -217,7 +223,8 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // What happens? // -// ** your answer here ** +// ** My answer here ** +// Pclk1 is too fast, it has a limit of 42 mhz // // Try to setup the clock according to: // @@ -225,7 +232,9 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // `rcc.cfgr.sysclk(84.mhz()).pclk1(42.mhz()).pclk2(64.mhz()).freeze();` // -// ** your answer here ** +// ** My answer here ** +// Since the pclk1 and pclk2 has to be in relation to sysclk according to: +// pclk(x) = sysclk / (1 or 2 or 4 or 8 or 16), this makes pclk2 and sysclk incompatible in this case. // // Commit your answers (bare6_0) // @@ -237,7 +246,8 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // What is the (default) MCU (SYSCLK) frequency? // -// ** your answer here ** +// ** My answer here ** +// 16 mhz // // What is the (default) DWT CYCCNT frequency? // @@ -245,7 +255,9 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // What is the frequency of blinking? // -// ** your answer here ** +// ** My answer here ** +// 8 000 000 / (16 * 10^6) = 0.5 seconds in between toggles, blinks with a frequency of 1 hz +// This can be confirmed in the tracing as well (8 000 000 difference) // // Commit your answers (bare6_1) // @@ -254,11 +266,15 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // Compute the value of SYSCLK based on the oscilloscope reading // -// ** your answer here ** +// ** My answer here ** +// Since the SYSCLK is sent directly to MCO2 we just need to measurement +// Measured frequency: 4 Mhz +// SYCLK = 4 * 4 = 16 Mhz. // // What is the peak to peak (voltage) reading of the signal? // -// ** your answer here ** +// ** My answer here ** +// Delta Y: Around 3.5V // // Make a folder called "pictures" in your git project. // Make a screen dump or photo of the oscilloscope output. @@ -271,7 +287,9 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { //` // What is the frequency of blinking? // -// ** your answer here ** +// ** My answer here ** +// 8 000 000 / (48 * 10^6) = 1 / 6 in between toggles +// The led blinks with a frequency of 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. @@ -282,15 +300,20 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // What is the frequency of MCO2 read by the oscilloscope? // -// ** your answer here ** +// ** My answer here ** +// 12 Mhz, which is three times the reading for 16 Mhz +// Getting an increase of 3 when we increase the clock frequency by a factor of three seems logical. // // Compute the value of SYSCLK based on the oscilloscope reading. // -// ** your answer here ** +// ** My answer here ** +// It's 48 Mhz (4 * 12) // // What is the peak to peak reading of the signal? // -// ** your answer here ** +// ** My answer here ** +// 5.4V, this seems like a bit much. +// We get 4.4V if we disconnect the ground. // // Make a screen dump or photo of the oscilloscope output. // Save the the picture as "bare_6_48mhz_high_speed". @@ -319,17 +342,27 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // Test that the application still runs as before. // +// ** My answer here ** +// Fixed, works as before. +// // Commit your code (bare6_5) // // 6. Now reprogram the PC9 to be "Low Speed", and re-run at 48Mz. // // Did the frequency change in comparison to assignment 5? // -// ** your answer here ** +// ** My answer here ** +// No, we still get 4 Mhz // // What is the peak to peak reading of the signal (and why did it change)? // -// ** your answer here ** +// ** My answer here ** +// It dropped by 1v from 5.4 to 4.4ish. +// As to the reason why, it's a bit unclear. +// My best guess is that during the high_speed run we are updating so often +// that we appproach the voltage of our power supply (5v), and since the speed is +// lowered to low_speed, this will simply happen less often and we get futher away from +// the voltage of our power supply. // // Make a screen dump or photo of the oscilloscope output. // Save the the picture as "bare_6_48mhz_low_speed". @@ -342,11 +375,13 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // Does the code compile? // -// ** your answer here ** +// ** My answer here ** +// The compiler doesn't know that the settings are incorrect, so yes. // // What happens at run-time? // -// ** your answer here ** +// ** My answer here ** +// During runtime we get a panic // // Try setting the clocks according to: // @@ -354,11 +389,16 @@ fn clock_out(rcc: &RCC, gpioc: &GPIOC) { // // Does the code compile? // -// ** your answer here ** +// ** My answer here ** +// Yes, as there are no coding errors. // // What happens at run-time? // -// ** your answer here ** +// ** My answer here ** +// It flashes the LED really fast, which is weird, according to STM32cubeMX +// these settings hould be incompatible. +// We can't get any measurements from the board, which was the expected outcome, +// but it's a bit weird that there is no panic. // // Is that a correct? // diff --git a/examples/rtic_bare7.rs b/examples/rtic_bare7.rs index 0f2dea18411d7e7c80325ad9cff46836177451f1..500de0e32179a2ec8cfb1b883b0859eda37f30f0 100644 --- a/examples/rtic_bare7.rs +++ b/examples/rtic_bare7.rs @@ -17,7 +17,7 @@ use stm32f4xx_hal::{ gpio::{gpioa::PA5, Output, PushPull}, prelude::*, }; -; + use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin}; const OFFSET: u32 = 8_000_000; @@ -26,8 +26,8 @@ const OFFSET: u32 = 8_000_000; const APP: () = { struct Resources { // late resources - GPIOA: stm32::GPIOA, - // led: PA5<Output<PushPull>>, + //GPIOA: stm32::GPIOA, + led: PA5<Output<PushPull>>, //PA5 implements output } #[init(schedule = [toggle])] fn init(cx: init::Context) -> init::LateResources { @@ -55,7 +55,8 @@ const APP: () = { // pass on late resources init::LateResources { - GPIOA: device.GPIOA, + //GPIOA: device.GPIOA, + led: device.GPIOA.split().pa5.into_push_pull_output(), //split the GPIOA into pins, choose pa5 and convert into push/pull output (this took a while to figure out) } } @@ -67,18 +68,22 @@ const APP: () = { } } - #[task(resources = [GPIOA], schedule = [toggle])] + #[task(resources = [led], schedule = [toggle])] fn toggle(cx: toggle::Context) { - static mut TOGGLE: bool = false; + //static mut TOGGLE: bool = false; //Uncomment when variable no longer needed rprintln!("toggle @ {:?}", Instant::now()); + /* if *TOGGLE { - cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit()); + cx.resources.led.set_high().ok(); //Change out GPIO for led } else { - cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit()); + cx.resources.led.set_low().ok(); //Change out GPIO for led } + */ - *TOGGLE = !*TOGGLE; + //*TOGGLE = !*TOGGLE; + //_toggle_generic(cx.resources.led, TOGGLE); //Pass led resource and toggle to generic function + _toggleable_generic(cx.resources.led); //Utilize the generic toggle function, toggle variable no longer needed cx.schedule.toggle(cx.scheduled + OFFSET.cycles()).unwrap(); } @@ -122,6 +127,13 @@ fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) { // // Comment your code to explain the steps taken. // +// ** My answer here ** +// 1. We had to change around in the resources, as the GPIO is no longer needed +// this means that we have to uncomment the led variable in the resources struct +// and insert the correct struct into lateresources. +// 2. Now we have our resources set up, so I changed the GPIO into led under the +// toggle function. +// // Confirm that your implementation correctly toggles the LED as in // previous exercise. // @@ -163,6 +175,9 @@ fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) { // // Commit your code (bare7_2) // +// ** My answer here ** +// This was merely a question of passing the toggle variable to the generic function. +// // 3. What about the state? // // In your code `TOGGLE` holds the "state". However, the underlying @@ -186,6 +201,13 @@ fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) { // Confirm that your implementation correctly toggles the LED as in // previous exercise. // +// ** My answer here ** +// This is merely a question of uncommenting the toggle variable, as well +// as the calls to the functions we are not to use. Since the toggleable_generic +// works in the same was as toggle_generic, in the sense that it generically +// handles pins which we can read and write from, so passing the led resource +// is enough. +// // Commit your code (bare7_3) // // 4. Discussion: diff --git a/examples/rtic_bare8.rs b/examples/rtic_bare8.rs index b4b18ee4a72d728359e36c70467f4de9ba8643a0..c951176f2c204e890e51d39edc2ac9795011374b 100644 --- a/examples/rtic_bare8.rs +++ b/examples/rtic_bare8.rs @@ -11,7 +11,7 @@ use panic_rtt_target as _; -use nb::block; +use stm32f4xx_hal::nb::block; use stm32f4xx_hal::{ gpio::{gpioa::PA, Output, PushPull}, @@ -69,15 +69,21 @@ const APP: () = { fn idle(cx: idle::Context) -> ! { let rx = cx.resources.RX; let tx = cx.resources.TX; + let mut received = 0; + let mut errors = 0; loop { match block!(rx.read()) { Ok(byte) => { - rprintln!("Ok {:?}", byte); + //rprintln!("Ok {:?}", byte); + received += 1; + rprintln!("Received: {:?}", received); tx.write(byte).unwrap(); } Err(err) => { - rprintln!("Error {:?}", err); + //rprintln!("Error {:?}", err); + errors += errors; + rprintln!("Errors: {:?}", errors); } } } @@ -113,31 +119,40 @@ const APP: () = { // // What do you receive in `moserial`? // -// ** your answer here ** +// ** My answer here ** +// a // // What do you receive in the RTT terminal? // -// ** your answer here ** +// ** My answer here ** +// Ok 97 // // Try sending: "abcd" as a single sequence, don't send the quotation marks, just abcd. // // What did you receive in `moserial`? // -// ** your answer here ** +// ** My answer here ** +// abcd // // What do you receive in the RTT terminal? // -// ** your answer here ** +// ** My answer here ** +// Ok 97 +// Ok 98 +// Ok 99 +// Ok 100 // // What do you believe to be the problem? // // Hint: Look at the code in `idle` what does it do? // -// ** your answer here ** +// ** My answer here ** +// There doesn't seem to be a problem... // // Experiment a bit, what is the max length sequence you can receive without errors? // -// ** your answer here ** +// ** My answer here ** +// I can send 16 letters, after that they simply don't show up but I don't get an error message... // // Commit your answers (bare8_1) // @@ -152,11 +167,13 @@ const APP: () = { // // 3. Experiment a bit, what is the max length sequence you can receive without errors? // -// ** your answer here ** +// ** My answer here ** +// I can send 16 letters, but I don't get errors afterwards, they simply don't show up. // // How did the added tracing/instrumentation affect the behavior? // -// ** your answer here ** +// ** My answer here ** +// Not at all. // // Commit your answer (bare8_3) // @@ -168,7 +185,8 @@ const APP: () = { // // Experiment a bit, what is the max length sequence you can receive without errors? // -// ** your answer here ** +// ** My answer here ** +// It's still 16 letters, and it still refuses to produce any errors. // // Commit your answer (bare8_4) // diff --git a/examples/rtic_bare9.rs b/examples/rtic_bare9.rs index a1fc61c6b3a97855fc50f1fb85419a0bfe7c27ce..aba3befa131a487b7193e62ec31d17dbcb686302 100644 --- a/examples/rtic_bare9.rs +++ b/examples/rtic_bare9.rs @@ -1,4 +1,4 @@ -//! bare8.rs +//! bare9.rs //! //! Serial //! @@ -17,6 +17,7 @@ use stm32f4xx_hal::{ use rtic::app; use rtt_target::{rprintln, rtt_init_print}; +use stm32f4xx_hal::nb::block; #[app(device = stm32f4xx_hal::stm32, peripherals = true)] const APP: () = { @@ -24,6 +25,8 @@ const APP: () = { // Late resources TX: Tx<USART2>, RX: Rx<USART2>, + Errors: u16, + Received: u16, } // init runs in an interrupt free section @@ -43,6 +46,9 @@ const APP: () = { let tx = gpioa.pa2.into_alternate_af7(); let rx = gpioa.pa3.into_alternate_af7(); + + let mut received = 0; + let mut errors = 0; let mut serial = Serial::usart2( device.USART2, @@ -59,7 +65,7 @@ const APP: () = { let (tx, rx) = serial.split(); // Late resources - init::LateResources { TX: tx, RX: rx } + init::LateResources { TX: tx, RX: rx, Errors: errors, Received: received } } // idle may be interrupted by other interrupts/tasks in the system @@ -71,19 +77,34 @@ const APP: () = { } // capacity sets the size of the input buffer (# outstanding messages) - #[task(resources = [TX], priority = 1, capacity = 128)] + #[task(resources = [TX], priority = 1, capacity = 126)] fn rx(cx: rx::Context, data: u8) { let tx = cx.resources.TX; tx.write(data).unwrap(); - rprintln!("data {}", data); + //rprintln!("data {}", data); } // Task bound to the USART2 interrupt. - #[task(binds = USART2, priority = 2, resources = [RX], spawn = [rx])] + #[task(binds = USART2, priority = 2, resources = [RX, Received, Errors], spawn = [rx])] fn usart2(cx: usart2::Context) { let rx = cx.resources.RX; - let data = rx.read().unwrap(); - cx.spawn.rx(data).unwrap(); + let mut received = cx.resources.Received; + let mut errors = cx.resources.Errors; + //let data = rx.read().unwrap(); + //cx.spawn.rx(data).unwrap(); + match block!(rx.read()) { // Move the read into block, saves a few cycles + Ok(byte) => { // Obligatory line, byte seems to be a standard + //rprintln!("Ok {:?}", byte); + *received += 1; + //rprintln!("Received: {:?}", received); + cx.spawn.rx(byte).unwrap(); // Write to the transceiver + } + Err(err) => { + //rprintln!("Error {:?}", err); + *errors += 1; + rprintln!("Errors: {:?}", errors); + } + } } extern "C" { @@ -148,7 +169,8 @@ const APP: () = { // // Were you able to crash it? // -// ** your answer here ** +// ** My answer here ** +// No, we were not able to "crash" it // // Notice, the input tracing in `moserial` seems broken, and may loose data. // So don't be alarmed if data is missing, its a GUI tool after all. @@ -194,6 +216,13 @@ const APP: () = { // // Once finished, comment your code. // +// ** My answer here ** +// By copying the received / error function from bare8 we get the functionality which was requested, +// but we produce a few errors during manual stress tests (at around 1 error per 150 characters). +// To get rid of these errors we simply reduce the program to only "report" on errors and not +// received characters. +// To produce the errors agin, simply uncomment the "reporting" of data and received. +// // Commit your code (bare9_2) // // 3. Discussion