//! bare8.rs //! //! Serial //! //! What it covers: //! - serial communication //! - bad design #![no_main] #![no_std] use panic_rtt_target as _; use nb::block; use stm32f4xx_hal::{ gpio::{gpioa::PA, Output, PushPull}, prelude::*, serial::{config::Config, Rx, Serial, Tx}, stm32::USART2, }; use rtic::app; use rtt_target::{rprintln, rtt_init_print}; #[app(device = stm32f4xx_hal::stm32, peripherals = true)] const APP: () = { struct Resources { // Late resources TX: Tx<USART2>, RX: Rx<USART2>, } // init runs in an interrupt free section #[init] fn init(cx: init::Context) -> init::LateResources { rtt_init_print!(); rprintln!("init"); let device = cx.device; let rcc = device.RCC.constrain(); // 16 MHz (default, all clocks) let clocks = rcc.cfgr.freeze(); let gpioa = device.GPIOA.split(); let tx = gpioa.pa2.into_alternate_af7(); let rx = gpioa.pa3.into_alternate_af7(); let serial = Serial::usart2( device.USART2, (tx, rx), Config::default().baudrate(115_200.bps()), clocks, ) .unwrap(); // Separate out the sender and receiver of the serial port let (tx, rx) = serial.split(); // Late resources init::LateResources { TX: tx, RX: rx } } // idle may be interrupted by other interrupts/tasks in the system #[idle(resources = [RX, TX])] fn idle(cx: idle::Context) -> ! { let rx = cx.resources.RX; let tx = cx.resources.TX; loop { match block!(rx.read()) { Ok(byte) => { rprintln!("Ok {:?}", byte); tx.write(byte).unwrap(); } Err(err) => { rprintln!("Error {:?}", err); } } } } }; // 0. Background // // The Nucleo st-link programmer provides a Virtual Com Port (VCP). // It is connected to the PA2(TX)/PA3(RX) pins of the stm32f401/411. // On the host, the VCP is presented under `/dev/ttyACMx`, where // `x` is an enumerated number (ff 0 is busy it will pick 1, etc.) // // 1. In this example we use RTT. // // > cargo run --example rtic_bare8 // // 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. // // Send a single character (byte), (set the option `No end` in `moserial`). // Verify that sent bytes are echoed back, and that RTT tracing is working. // // Try sending "a", don't send the quotation marks, just a. // // What do you receive in `moserial`? // // ** your answer here ** // // What do you receive in the RTT terminal? // // ** your answer here ** // // Try sending: "abcd" as a single sequence, don't send the quotation marks, just abcd. // // What did you receive in `moserial`? // // ** your answer here ** // // What do you receive in the RTT terminal? // // ** your answer here ** // // What do you believe to be the problem? // // Hint: Look at the code in `idle` what does it do? // // ** your answer here ** // // Experiment a bit, what is the max length sequence you can receive without errors? // // ** your answer here ** // // Commit your answers (bare8_1) // // 2. Add a local variable `received` that counts the number of bytes received. // Add a local variable `errors` that counts the number of errors. // // Adjust the RTT trace to print the added information inside the loop. // // Compile/run reconnect, and verify that it works as intended. // // Commit your development (bare8_2) // // 3. Experiment a bit, what is the max length sequence you can receive without errors? // // ** your answer here ** // // How did the added tracing/instrumentation affect the behavior? // // ** your answer here ** // // Commit your answer (bare8_3) // // 4. Now try compile and run the same experiment 3 but in --release mode. // // > cargo run --example rtic_bare8 --release // // Reconnect your `moserial` terminal. // // Experiment a bit, what is the max length sequence you can receive without errors? // // ** your answer here ** // // Commit your answer (bare8_4) // // 5. Discussion // // (If you ever used Arduino, you might feel at home with the `loop` and poll design.) // // Typically, this is what you can expect from a polling approach, if you // are not very careful what you are doing. This exemplifies a bad design. // // Loss of data might be Ok for some applications but this typically NOT what we want. // // (With that said, Arduino gets away with some simple examples as their drivers do // internal magic - buffering data etc.)