Skip to content
Snippets Groups Projects
Commit 95c2e7b4 authored by Edward's avatar Edward
Browse files

add correct versions of rtic_bare exercises

parent 1c394e45
No related branches found
No related tags found
No related merge requests found
......@@ -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)
//
......
......@@ -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)
\ No newline at end of file
......@@ -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)
//
......
......@@ -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)
\ No newline at end of file
......@@ -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);
}
}
......
......@@ -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?
//
......
......@@ -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:
......
......@@ -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)
//
......
//! 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
......@@ -44,6 +47,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,
(tx, rx),
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment