Select Git revision
bare6.rs 6.42 KiB
//! bare6.rs
//!
//! Clocking
//!
//! What it covers:
//! - setting the clock via script (again)
//! - routing the clock to a PIN for monitoring by an oscilloscope
//! - changing the clock using Rust code
//!
// #![feature(used)]
// #![no_std]
// extern crate f4;
// extern crate stm32f40x;
// #[macro_use]
// extern crate cortex_m_debug;
// use f4::clock;
// use f4::prelude::*;
// use stm32f40x::{DWT, FLASH, GPIOA, GPIOC, RCC};
#![no_main]
#![no_std]
#![feature(uniform_paths)]
extern crate panic_halt;
use cortex_m::{iprint, iprintln, peripheral::itm::Stim, peripheral::syst::SystClkSource};
use cortex_m_rt::{entry, exception};
use stm32f4::stm32f411;
use stm32f411::{interrupt, Interrupt, DWT, GPIOA, GPIOC, ITM, NVIC, RCC, SYST};
#[entry]
fn main() -> ! {
let p = stm32f411::Peripherals::take().unwrap();
let mut c = stm32f411::CorePeripherals::take().unwrap();
let stim = &mut c.ITM.stim[0];
iprintln!(stim, "Hello, 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);
// clock::set_84_mhz(rcc, flash);
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.55s
// 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 = high speed
gpioc
.ospeedr
.modify(|_, w| w.ospeedr9().bits(0b11) );
}
// 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
//
// 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.
// Save 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.
//
//
// 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?
//
// ** your answer here **
//
// 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. Now we will put the MCU in 84MHz using the function
// clock::set_84_mhz(rcc, flash);
//
// This function is part of the `f4` support crate (by Johonnes Sjölund)
// besides `rcc` (for clocking) it takes `flash` as a parameter to set
// up correct latency (wait states) for the flash memory (where our
// program typically resides). This is required since the flash cannot
// operate at the full 84MHz, so the MCU has to wait for the memory.
//
// 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.
// Save the the picture as "bare_6_84mhz_high_speed"
//
// commit your answers (bare6_5)
//
// 6. Now reprogram the PC9 to be "Low Speed", and re-run at 84Mz.
//
// Did the frequency change in comparison to assignment 5?
//
// ** your answer here **
//
// What is the peak to peak reading of the signal (and why did it change)?
//
// ** your answer here **
//
// Make a screen dump or photo of the oscilloscope output.
// Save the the picture as "bare_6_84mhz_low_speed".
//
// commit your answers (bare6_6)