diff --git a/examples/bare6.rs b/examples/bare6.rs index 493b814787224ae0d6cc27937fdf71ee22dcb496..d7c42b9d73f9b613298d26101b6d496888a8d755 100644 --- a/examples/bare6.rs +++ b/examples/bare6.rs @@ -5,39 +5,158 @@ #![feature(use_nested_groups)] #![no_std] -extern crate cortex_m; -extern crate cortex_m_rt; +extern crate stm32f40x; #[macro_use] extern crate cortex_m_debug; -use cortex_m::{asm::bkpt, peripheral::DWT}; +use stm32f40x::{DWT, GPIOA, GPIOC, RCC}; + +fn main() { + ipln!("init"); + let dwt = unsafe { &mut *DWT.get() }; // get the reference to DWD in memory + let rcc = unsafe { &mut *RCC.get() }; // get the reference to RCC in memory + let gpioa = unsafe { &mut *GPIOA.get() }; // get the reference to GPIOA in memory + let gpioc = unsafe { &mut *GPIOC.get() }; // get the reference to GPIOC in memory + + dwt.enable_cycle_counter(); + clock_out(rcc, gpioc); + idle(dwt, rcc, gpioa); +} // uses the DWT.CYCNT // doc: ARM trm_100166_0001_00_en.pdf, chapter 9.2 -// we use the `cortex-m` abstraction -fn wait_cycles(nr_cycles: u32) { - unsafe { - let t = (*DWT.get()).cyccnt.read().wrapping_add(nr_cycles); - while ((*DWT.get()).cyccnt.read().wrapping_sub(t) as i32) < 0 {} - } +// we use the `cortex-m` abstraction, as re-exported by the stm32f40x +fn wait_cycles(dwt: &mut DWT, nr_cycles: u32) { + let t = dwt.cyccnt.read().wrapping_add(nr_cycles); + while (dwt.cyccnt.read().wrapping_sub(t) as i32) < 0 {} } -fn main() { - unsafe { (*DWT.get()).enable_cycle_counter() }; - let mut i = 0; - loop { - ipln!("tick {}", i); - wait_cycles(64_000_000); - i += 1; // this will eventually cause a panic, when the counter wraps. - } +// see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf) +// rcc, chapter 6 +// gpio, chapter 8 +fn clock_out(rcc: &mut RCC, gpioc: &mut GPIOC) { + // output MCO2 to pin PC9 + + // mco2 : SYSCLK = 0b00 + // mcopre : divide by 4 = 0b110 + rcc.cfgr + .modify(|_, w| unsafe { w.mco2().bits(0b00).mco2pre().bits(0b110) }); + + // power on GPIOC, RM0368 6.3.11 + rcc.ahb1enr.modify(|_, w| w.gpiocen().set_bit()); + + // 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| unsafe { w.moder9().bits(0b10) }); + + // otyper reset state push/pull, in reset state (don't need to change) + + // ospeedr 0b11 = high speed + gpioc + .ospeedr + .modify(|_, w| unsafe { w.ospeedr9().bits(0b11) }); } +// user application +fn idle(dwt: &mut DWT, rcc: &mut RCC, gpioa: &mut GPIOA) { + ipln!("idle"); + // power on GPIOA, RM0368 6.3.11 + rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); -// As we are not using interrupts, we just register a dummy catch all handler -#[link_section = ".vector_table.interrupts"] -#[used] -static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; + // configure PA5 as output, RM0368 8.4.1 + gpioa.moder.modify(|_, w| w.moder5().bits(1)); -extern "C" fn default_handler() { - cortex_m::asm::bkpt(); + // at 16 Mhz, 8000_0000 cycles = 0.5s + // at 64 Mhz, 8000_0000 cycles = 0.125s + loop { + ipln!("led on"); + // set PA5 high, RM0368 8.4.7 + gpioa.bsrr.write(|w| w.bs5().set_bit()); + wait_cycles(dwt, 8000_000); + + ipln!("led off"); + // set PA5 low, RM0368 8.4.7 + gpioa.bsrr.write(|w| w.br5().set_bit()); + wait_cycles(dwt, 8000_000); + } } + +// 1. compile and run the example, in 16Mhz +// the processor SYSCLK defaults to HCI 16Mhz +// (this is what you get after a `monitor reset halt`) +// +// confirm that your ITM dump traces the init, idle and led on/off +// make sure your TPIU is set to a system clock at 16Mhz +// +// you may use either ITM tracing using ITM dump or internally in +// vscode using the new "cortex debug" plugin +// +// what is the frequency of blinking +// ** your answer here ** +// +// commit your answers (bare6_1) +// +// 2. now connect an oscilloscope to PC9, which is set to +// output the MCO2 +// +// what is the frequency of MCO2 read by the oscilloscope +// ** your answer here ** +// +// compute the value of SYSCLK based on the oscilloscope reading +// ** your answer here ** +// +// what is the peak to peak reading of the signal +// ** your answer here ** +// +// make a folder called "pictures" in your git project +// make a screen dump or photo of the oscilloscope output +// sove the the picture as "bare_6_16mhz_high_speed" +// +// commit your answaaasers (bare6_2) +// +// 3. now run the example in 64Mz +// you can do that by issuing a `monitor reset init` +// which reprograms SYSCLK to 4*HCI +// (make sure you have the latest openocd v 0.10) +// +// confirm that your ITM dump traces the init, idle and led on/off +// (make sure your TPIU is set to a system clock at 64Mhz) +// +// what is the frequency of blinking +// ** your answer here ** +// +// commit your answers (bare6_3) +// +// 4. repeat the experiment 2 +// what is the frequency of MCO2 read by the oscilloscope +// ** your answer here ** +// +// compute the value of SYSCLK based on the oscilloscope reading +// ** your answer here ** +// what is the peak to peak reading of the signal +// +// ** your answer here ** +// +// make a screen dump or photo of the oscilloscope output +// sove the the picture as "bare_6_64mhz_high_speed" +// +// commit your answers (bare6_4) +// +// 5. now reprogram the PC9 to be "Low Speed", and re-run at 64Mz +// +// did the frequency change in comparison to assignment 4. +// ** your answer here ** +// +// what is the peak to peak reading of the signal +// ** your answer here ** +// +// why does it differ? +// ** your answer here ** +// +// make a screen dump or photo of the oscilloscope output +// sove the the picture as "bare_6_64mhz_low_speed" +// +// commit your answers (bare6_24)