diff --git a/examples/bare7.rs b/examples/bare7.rs new file mode 100644 index 0000000000000000000000000000000000000000..d343ad0734752989aa20e511b1389af78708ca0d --- /dev/null +++ b/examples/bare7.rs @@ -0,0 +1,239 @@ +//! 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