//! bare4.rs //! Simple bare metal application //! #![feature(used)] #![feature(custom_attribute)] // needed for #[rustfmt_skip] #![no_std] extern crate cortex_m; extern crate cortex_m_rt; // Peripheral addresses as constants #[rustfmt_skip] mod address { pub const PERIPH_BASE: u32 = 0x40000000; pub const AHB1PERIPH_BASE: u32 = PERIPH_BASE + 0x00020000; pub const RCC_BASE: u32 = AHB1PERIPH_BASE + 0x3800; pub const RCC_AHB1ENR: u32 = RCC_BASE + 0x30; pub const GBPIA_BASE: u32 = AHB1PERIPH_BASE + 0x0000; pub const GPIOA_MODER: u32 = GBPIA_BASE + 0x00; pub const GPIOA_BSRR: u32 = GBPIA_BASE + 0x18; } use address::*; // see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf) // rcc, chapter 6 // gpio, chapter 8 #[inline(always)] fn read_u32(addr: u32) -> u32 { //unsafe { core::ptr::read_volatile(addr as *const _) } core::ptr::read_volatile(addr as *const _) } #[inline(always)] fn write_u32(addr: u32, val: u32) { unsafe { core::ptr::write_volatile(addr as *mut _, val); } } fn wait(i: u32) { for _ in 0..i { cortex_m::asm::nop(); // no operation (cannot be optimized out) } } fn main() { // power on GPIOA let r = read_u32(RCC_AHB1ENR); // read write_u32(RCC_AHB1ENR, r | 1); // set enable // configure PA5 as output let r = read_u32(GPIOA_MODER) & !(0b11 << (5 * 2)); // read and mask write_u32(GPIOA_MODER, r | 0b01 << (5 * 2)); // set output mode // and alter the data output through the BSRR register // this is more efficient as the read register is not needed. loop { // set PA5 high write_u32(GPIOA_BSRR, 1 << 5); // set bit, output hight (turn on led) wait(10_000); // set PA5 low write_u32(GPIOA_BSRR, 1 << (5 + 16)); // clear bit, output low (turn off led) wait(10_000); } } // 1. build and run the application (debug build) // did you enjoy the blinking? // ** your answer here ** // No, it is enoing. // // now lookup the data-sheets, and read each section referred, // 6.3.11, 8.4.1, 8.4.7 // // document each low level access *code* by the appropriate section in the // data sheet // // commit your answers (bare4_1) // // 2. comment out line 30 and uncomment line 31 (essentially omitting the `unsafe`) // what was the error message and explain why, // ** your answer here ** // call to unsafe function recvier unsafe function or blok // // digging a bit deeper, why do you think `read_volatile` is declared `unsafe` // (https://doc.rust-lang.org/core/ptr/fn.read_volatile.html, for some food for thought ) // ** your answer here ** // it is reading a operation from a perifial. perifials ar critical resorses and writ operations // kan cas race condition in combination with read. // // commit your answers (bare4_2) // // 3. // volatile read/writes are explicit *volatile operations* in Rust, while in C they // are declared at type level (i.e., access to varibles declared volatile amounts to // volatile reads/and writes) // // both C and Rust (even more) allows code optimization to re-order operations, as long // as data dependencies are preserved. // // why is important that ordering of volatile operations are ensured by the compiler? // ** your answer here ** // The order of the operations can efekt the out come of the program, race condition. // // give an example in the above code, where reordering might make things go horribly wrong // (hint, accessing a peripheral not being powered...) // ** your answer here ** // in som cases wen seting an walue or aktivating a perifial is nessesary to do befor a read or // simelar. // seting gpioA ass activ befor reading. the compiler do not know if a perifial writ is to set a // setin or blink a led. // // without the non-reording proprety of `write_volatile/read_volatile` could that happen in theory // (argue from the point of data dependencies) // ** your answer here ** // If the compiler is left to it self wil it in som case changes the order of the read/write // operation. if somthig can gow wrong it will. sow it is lickly that the program is broken if the // is no forsd ordering // // commit your answers (bare4_3) // As we are not using interrupts, we just register a dummy catch all handler #[link_section = ".vector_table.interrupts"] #[used] static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; extern "C" fn default_handler() { cortex_m::asm::bkpt(); }