Skip to content
Snippets Groups Projects
Select Git revision
  • 7f2f60fd755fba7c5f06993ab30ba5fe7404b7d2
  • student default protected
2 results

bare7.rs

Blame
  • Forked from Per Lindgren / e7020e_2019
    Source project has a limited visibility.
    bare6.rs 5.78 KiB
    //! bare6.rs
    //!
    //! Clocking
    //!
    //! What it covers:
    //! - using svd2rust generated API
    //! - setting the clock via script (again)
    //! - routing the clock to a PIN for monitoring by an oscilloscope
    
    #![no_main]
    #![no_std]
    
    extern crate panic_halt;
    
    use cortex_m::{iprintln, peripheral::itm::Stim};
    use cortex_m_rt::entry;
    
    use stm32f4::stm32f413::{self, DWT, GPIOA, GPIOC, RCC};
    
    #[entry]
    fn main() -> ! {
        let p = stm32f413::Peripherals::take().unwrap();
        let mut c = stm32f413::CorePeripherals::take().unwrap();
    
        let stim = &mut c.ITM.stim[0];
        iprintln!(stim, "bare6");
    
        c.DWT.enable_cycle_counter();
        unsafe {
            c.DWT.cyccnt.write(0);
        }
        let t = DWT::get_cycle_count();
        iprintln!(stim, "{}", t);
    
        clock_out(&p.RCC, &p.GPIOC);
        idle(stim, p.RCC, p.GPIOA);
    
        loop {}
    }
    
    // user application
    fn idle(stim: &mut Stim, rcc: RCC, gpioa: GPIOA) {
        iprintln!(stim, "idle");
    
        // power on GPIOA, RM0368 6.3.11
        rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
    
        // configure PA5 as output, RM0368 8.4.1
        gpioa.moder.modify(|_, w| w.moder5().bits(1));
    
        // at 16 Mhz, 8_000_000 cycles = period 0.5s
        // at 64 Mhz, 4*8_000_000 cycles = period 0.5s
        // let cycles = 8_000_000;
        let cycles = 4 * 8_000_000;
    
        loop {
            iprintln!(stim, "on {}", DWT::get_cycle_count());
            // set PA5 high, RM0368 8.4.7
            gpioa.bsrr.write(|w| w.bs5().set_bit());
            wait_cycles(cycles);
    
            iprintln!(stim, "off {}", DWT::get_cycle_count());
            // set PA5 low, RM0368 8.4.7
            gpioa.bsrr.write(|w| w.br5().set_bit());
            wait_cycles(cycles);
        }
    }
    
    // uses the DWT.CYCNT
    // doc: ARM trm_100166_0001_00_en.pdf, chapter 9.2
    // we use the `cortex-m` abstraction, as re-exported by the stm32f40x
    fn wait_cycles(nr_cycles: u32) {
        let t = DWT::get_cycle_count().wrapping_add(nr_cycles);
        while (DWT::get_cycle_count().wrapping_sub(t) as i32) < 0 {}
    }
    
    // see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf)
    // rcc,     chapter 6
    // gpio,    chapter 8
    fn clock_out(rcc: &RCC, gpioc: &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| w.moder9().bits(0b10));
        
        // 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));
    }
    
    // 0. Compile and run the example, in 16Mhz
    //
    //    > cargo build --example bare6 --features "pac"
    //    (or use the vscode build task)
    //
    //    The "pac" feature enables the optional dependency "stm32f4"
    //
    //    Cargo.toml:
    // 
    //    [dependencies.stm32f4]
    //    version = "0.5.0"
    //    features = ["stm32f413", "rt"]
    //    optional = true
    // 
    //    [features]
    //    pac = ["stm32f4"]    
    //
    //    Notice, we use the stm32f413 API, since it covers stm32f401/f411/f413.
    //
    // 1. 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
    //
    //    What is the frequency of blinking?
    //
    //    1s, 1Hz
    //
    //    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?
    //
    //    4Mhz
    //
    //    Compute the value of SYSCLK based on the oscilloscope reading
    //
    //    16Mhz
    //
    //    What is the peak to peak reading of the signal?
    //
    //    5.9V
    //
    //    Make a folder called "pictures" in your git project.
    //    Make a screen dump or photo of the oscilloscope output.
    //    Save the the picture as "bare_6_16mhz_high_speed".
    //
    //    Commit your answers (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.
    //
    //
    //    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)
    //
    //    Uncommnet: `let cycles = 4 * 8_000_000;
    //`
    //    What is the frequency of blinking?
    //
    //    0.5s, 2Hz
    //
    //    Commit your answers (bare6_3)
    //
    // 4. Repeat 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.
    //    Save the the picture as "bare_6_64mhz_high_speed".
    //
    //    Commit your answers (bare6_4)
    //
    // 5. In the `clock_out` function, the setup of registers is done through
    //    setting bitpattens manually, e.g. 
    //     rcc.cfgr
    //        .modify(|_, w| unsafe { w.mco2().bits(0b00).mco2pre().bits(0b110) });
    //
    //    However based on the vendor SVD file the svd2rust API provides  
    //    a better abstraction, based on pattern enums and functions.
    //
    //    To view the API you can generate documentation for your crate:
    //
    //    > cargo doc --features "pac" --open
    //
    //    By searching for `mco2` you find the enumerations and functions.
    //    So here 
    //       `w.mco2().bits{0b00}` is equivalent to 
    //       `w.mco2().sysclk()` and improves readabiity. 
    //
    //    Replace all bitpatterns used by the function name equivalents.
    //
    //    Test that the application still runs as before.
    //
    //    Commit your code (bare6_4)