//! bare7.rs //! //! Serial echo //! //! What it covers: //! - changing the clock using Rust code //! - working with the svd2rust API //! - working with the HAL (Hardware Abstraction Layer) //! - USART polling (blocking wait) #![deny(unsafe_code)] #![no_main] #![no_std] extern crate panic_halt; use cortex_m::iprintln; use cortex_m_rt::entry; use nb::block; extern crate stm32f4xx_hal as hal; use crate::hal::prelude::*; use crate::hal::serial::{config::Config, Serial}; #[entry] fn main() -> ! { let mut c = hal::stm32::CorePeripherals::take().unwrap(); let stim = &mut c.ITM.stim[0]; let p = hal::stm32::Peripherals::take().unwrap(); let rcc = p.RCC.constrain(); // 16 MHz (default, all clocks) let clocks = rcc.cfgr.freeze(); // 84 MHz (with valid config for pclk1 and pclk2) // let clocks = rcc.cfgr.sysclk(84.mhz()).pclk1(42.mhz()).pclk2(84.mhz()).freeze(); let gpioa = p.GPIOA.split(); let tx = gpioa.pa2.into_alternate_af7(); let rx = gpioa.pa3.into_alternate_af7(); // try comment out // let rx = gpioa.pa3.into_alternate_af6(); // try uncomment let serial = Serial::usart2( p.USART2, (tx, rx), Config::default().baudrate(115_200.bps()), clocks, ) .unwrap(); iprintln!(stim, "bare7"); // Separate out the sender and receiver of the serial port let (mut tx, mut rx) = serial.split(); loop { match block!(rx.read()) { Ok(byte) => { iprintln!(stim, "Ok {:?}", byte); tx.write(byte).unwrap(); } Err(err) => { iprintln!(stim, "Error {:?}", err); } } } } // Optional assignment // 0. Background reading: // STM32F401xD STM32F401xE, section 3.11 // We have two AMBA High-performance Bus (AHB) // APB1 low speed bus (max freq 42 MHz) // APB2 high speed bus (max frex 84 MHz) // // RM0368 Section 6.2 // Some important/useful clock acronyms and their use: // // SYSCLK - the clock that drives the `core` // HCLK - the clock that drives the AMBA bus(es), memory, DMA, trace unit, etc. // // Typically we set HCLK = SYSCLK / 1 (no prescale) for our applications // // FCLK - Free running clock runing at HCLK // // CST - CoreSystemTimer drives the SysTick counter, HCLK/(1 or 8) // PCLK1 - The clock driving the APB1 (<= 42 MHz) // Timers on the APB1 bus will be triggered at PCLK1 * 2 // PCLK2 - The clock driving the APB2 (<= 84 MHz) // Timers on the APB2 bus will be triggered at PCLK2 // // Compliation: // > cargo build --example bare7 --features "stm32fxx-hal" // (or use the vscode build task) // // // Cargo.toml: // // [dependencies.stm32f4] // version = "0.5.0" // features = ["stm32f413", "rt"] // optional = true // // [dependencies.stm32f4xx-hal] // version = "0.6.0" // features = ["stm32f401", "rt"] // optional = true // // Notice, stm32f4xx-hal internally enables the dependency to stm32f4, // so we don't need to explicitly enable it. // // The HAL provides a generic abstraction over the whole stm32f4 family. // // 1. The rcc.cfgr.x.freeze() sets the clock according to the configuration x given. // // rcc.cfgr.freeze(); sets a default configuration. // sysclk = hclk = pclk1 = pclk2 = 16MHz // // What is wrong with the following configurations? // // rcc.cfgr.sysclk(64.mhz()).pclk1(64.mhz()).pclk2(64.mhz()).freeze(); // // ** your answer here ** // // rcc.cfgr.sysclk(84.mhz()).pclk1(42.mhz()).pclk2(64.mhz()).freeze(); // // ** your answer here ** // // Commit your answers (bare7_1) // // Tip: You may use `stm32cubemx` to get a graphical view for experimentation. // // 2. Now give the system with a valid clock, sysclk of 84 MHz. // // Include the code for outputting the clock to MCO2. // // Repeat the experiment bare6_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_7_84mhz_high_speed" // // Commit your answers (bare7_2) // // 3. Now reprogram the PC9 to be "Low Speed", and re-run at 84Mz. // // Did the frequency change in comparison to assignment 6? // // ** 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_7_84mhz_low_speed". // // Commit your answers (bare7_3) // // 4. Revisit the `README.md` regarding serial communication. // start a terminal program, e.g., `moserial`. // Connect to the port // // Device /dev/ttyACM0 // Baude Rate 115200 // Data Bits 8 // Stop Bits 1 // Parity None // // This setting is typically abbreviated as 115200 8N1. // // Run the example, make sure your ITM is set to 84MHz. // // Send a single character (byte), (set the option No end in moserial). // Verify that sent bytes are echoed back, and that ITM tracing is working. // // If not go back check your ITM setting, clocks etc. // // Try sending: "abcd" as a single sequence, don't send the quotation marks, just abcd. // // What did you receive, and what was the output of the ITM trace. // // ** your answer here ** // // commit your answers (bare7_4) // // 5. Now, set the CPU to run at 16MHz. // Repeat the experiment 7.4 (make sure your ITM is set to 16MHz) // // Try sending: "abcd" as a single sequence, don't send the quotation marks, just abcd. // // What did you receive, and what was the output of the ITM trace. // // ** your answer here ** // // Explain why the buffer overflows. // // ** your answer here ** // // commit your answers (bare7_4) // // Discussion: // Common to all MCUs is that they have multiple clocking options. // Understanding the possibilities and limitations of clocking is fundamental // to designing both the embedded hardware and software. Tools like // `stm32cubemx` can be helpful to give you the big picture. // // The `stm32f4xx-hal` gives you an abstraction for programming, // setting up clocks, assigning pins, etc. // // The hal overs basic functionality like serial communication. // Still, in order to fully understand what is going on under the hood you need to // check the documentation (data sheets, user manuals etc.) // // Your crate can be documented by: // // > cargo doc --open --features "stm32f4xx-hal" // // This will document both your crate and its dependencies besides the `core` library. // // You can open the `core` library documentation by // // > rustup doc // // or just show the path to the doc (to open it manually) // // > rustup doc --path