diff --git a/.vscode/launch.json b/.vscode/launch.json index 822733975745f91aebca8adc45f67da9da4e1e3e..3ff1ffe70c09208c57b589d1e8a2d7ad7f893150 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -76,5 +76,95 @@ ], "cwd": "${workspaceRoot}" }, + { + "type": "gdb", + "request": "attach", + "name": "gpio_raw", + "gdbpath": "/usr/bin/arm-none-eabi-gdb", + "executable": "./target/thumbv7em-none-eabihf/debug/examples/gpio_raw", + "target": ":3333", + "remote": true, + "autorun": [ + "monitor reset init", + "monitor arm semihosting enable", + "monitor tpiu config internal /tmp/itm.log uart off 64000000", + "monitor itm port 0 on", + "load", + "monitor reset init" + ], + "cwd": "${workspaceRoot}" + }, + { + "type": "gdb", + "request": "attach", + "name": "bare1", + "gdbpath": "/usr/bin/arm-none-eabi-gdb", + "executable": "./target/thumbv7em-none-eabihf/debug/examples/bare1", + "target": ":3333", + "remote": true, + "autorun": [ + "monitor reset init", + "monitor arm semihosting enable", + "monitor tpiu config internal /tmp/itm.log uart off 64000000", + "monitor itm port 0 on", + "load", + "monitor reset init" + ], + "cwd": "${workspaceRoot}" + }, + { + "type": "gdb", + "request": "attach", + "name": "bare2", + "gdbpath": "/usr/bin/arm-none-eabi-gdb", + "executable": "./target/thumbv7em-none-eabihf/debug/examples/bare2", + "target": ":3333", + "remote": true, + "autorun": [ + "monitor reset init", + "monitor arm semihosting enable", + "monitor tpiu config internal /tmp/itm.log uart off 64000000", + "monitor itm port 0 on", + "load", + "monitor reset init" + ], + "cwd": "${workspaceRoot}" + }, + { + "type": "gdb", + "request": "attach", + "name": "bare3", + "gdbpath": "/usr/bin/arm-none-eabi-gdb", + "executable": "./target/thumbv7em-none-eabihf/debug/examples/bare3", + "target": ":3333", + "remote": true, + "autorun": [ + "monitor reset init", + "monitor arm semihosting enable", + "monitor tpiu config internal /tmp/itm.log uart off 64000000", + "monitor itm port 0 on", + "load", + "monitor reset init" + ], + "cwd": "${workspaceRoot}" + }, + { + "type": "gdb", + "request": "attach", + "name": "bare4", + "gdbpath": "/usr/bin/arm-none-eabi-gdb", + "executable": "./target/thumbv7em-none-eabihf/debug/examples/bare4", + "target": ":3333", + "remote": true, + "autorun": [ + "monitor reset init", + "monitor arm semihosting enable", + "monitor tpiu config internal /tmp/itm.log uart off 64000000", + "monitor itm port 0 on", + "load", + "monitor reset init" + ], + "cwd": "${workspaceRoot}" + }, ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d2d5a4664d418c9789dc34933231b4ab644f4fc1..760e36e48ef828d6684034a1aafa7d04ec45a8de 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -51,5 +51,65 @@ "isDefault": true } }, + { + "type": "shell", + "label": "xargo build --example gpio_raw", + "command": "xargo build --example gpio_raw", + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "shell", + "label": "xargo build --example bare1", + "command": "xargo build --example bare1", + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "shell", + "label": "xargo build --example bare2", + "command": "xargo build --example bare2", + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "shell", + "label": "xargo build --example bare3", + "command": "xargo build --example bare3", + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "shell", + "label": "xargo build --example bare4", + "command": "xargo build --example bare4", + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, ] } \ No newline at end of file diff --git a/examples/bare1.rs b/examples/bare1.rs new file mode 100644 index 0000000000000000000000000000000000000000..16931d37ea55359086f33d852a9765de0ae575b8 --- /dev/null +++ b/examples/bare1.rs @@ -0,0 +1,41 @@ +//! bare1.rs +//! Simple bare metal application + +// feature to ensure symbols to be linked +#![feature(used)] +// build without the Rust standard library +#![no_std] + +// API to the ARM Cortex M Peripherals +extern crate cortex_m; + +// Minimal runtime / startup for Cortex-M microcontrollers +extern crate cortex_m_rt; + +// Convenient tracing over semihosting and ITM +#[macro_use] +extern crate cortex_m_debug; + +#[inline(never)] +fn main() { + // ITM trace (fast) + // start `itmdump` before `openocd` + ipln!("ITM: Hello World"); + + // semihosting trace (slow) + sprintln!("SEMIHOSTING: Hello World"); + + // to prevent returning + loop { + cortex_m::asm::nop(); + } +} + +// 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(); +} diff --git a/examples/bare2.rs b/examples/bare2.rs new file mode 100644 index 0000000000000000000000000000000000000000..bf49b9243f1e1c2919b7068a0a8379e18ab2af22 --- /dev/null +++ b/examples/bare2.rs @@ -0,0 +1,40 @@ +//! bare2.rs +//! Simple bare metal application +#![feature(used)] +#![no_std] + +extern crate cortex_m; +extern crate cortex_m_rt; + +#[macro_use] +extern crate cortex_m_debug; + +// burns CPU cycles by just looping `i` times +fn wait(i: u32) { + for _ in 0..i { + // no operation (ensured not optimized out) + cortex_m::asm::nop(); + } +} + +fn main() { + ipln!("Start"); + + // a "mutable" (changeable) variable + let mut s = 0; + + loop { + ipln!("s = {}", s); + s += 1; + wait(100_000); + } +} + +// 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(); +} diff --git a/examples/bare3.rs b/examples/bare3.rs new file mode 100644 index 0000000000000000000000000000000000000000..964a4fb9da7b2350eca6d51511997f38feff3c14 --- /dev/null +++ b/examples/bare3.rs @@ -0,0 +1,33 @@ +//! bare3.rs +//! Simple bare metal application +//! +#![feature(used)] +#![no_std] + +extern crate cortex_m; +extern crate cortex_m_rt; + +#[macro_use] +extern crate cortex_m_debug; + +fn main() { + let s = "ABCD"; + ipln!("s = {:?}", s); + + // iterate over the byte repr. of s + for c in s.as_bytes() { + ip!("{},", c) + } + + ipln!(); + loop {} +} + +// 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(); +} diff --git a/examples/bare4.rs b/examples/bare4.rs new file mode 100644 index 0000000000000000000000000000000000000000..1cf587d5a5affc069208ce87e6ba25775f4f8380 --- /dev/null +++ b/examples/bare4.rs @@ -0,0 +1,72 @@ +//! bare4.rs +//! Simple bare metal application +//! +#![feature(used)] +#![no_std] + +extern crate cortex_m; +extern crate cortex_m_rt; + +#[macro_use] +extern crate cortex_m_debug; + +const RCC_AHPB1ENR: u32 = 0x4002_3810; +const GPIOA_MODER: u32 = 0x4002_0000; +//const GPIOA_ODR: u32 = 0x4002_0014; +const GPIOA_BSRR: u32 = 0x4002_0018; + +// see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf) +// rcc, chapter 6 +// gpio, chapter 8 + +fn read_u32(addr: u32) -> u32 { + unsafe { core::ptr::read_volatile(addr as *const _) } +} + +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, RM0368 6.3.11 + // p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + + let r = read_u32(RCC_AHPB1ENR); // read + write_u32(RCC_AHPB1ENR, r | 1 << (0)); // set enable + + // // configure PA5 as output, RM0368 8.4.1 + // p.GPIOA.moder.modify(|_, w| w.moder5().bits(1)); + 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 (in modify) + // is not needed. + + loop { + // set PA5 high, RM0368 8.4.7 + write_u32(GPIOA_BSRR, r | 1 << 5); // set output mode + wait(10_000); + + // set PA5 low, RM0368 8.4.7 + write_u32(GPIOA_BSRR, r | 1 << (5 + 16)); // set output mode + wait(10_000); + } +} + +// 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(); +} diff --git a/examples/gpio_raw.rs b/examples/gpio_raw.rs new file mode 100644 index 0000000000000000000000000000000000000000..75e6c59035121f8e6f08d35122becf9ea4d40832 --- /dev/null +++ b/examples/gpio_raw.rs @@ -0,0 +1,78 @@ +//! Simple access to gpio + +// build without the Rust standard library +#![no_std] + +// API to the ARM Cortex M Peripherals +extern crate cortex_m; + +// API to the ST stm32f401x Micro controller +extern crate stm32f40x; + +// Convenient tracing over semihosting and ITM +#[macro_use] +extern crate cortex_m_debug; + +fn main() { + ipln!("ITM: Hello World"); + sprintln!("SEMIHOSTING: Hello World"); + + // to prevent returning + loop {} +} + +// use rtfm::app; + +// app! { +// device: stm32f40x, +// } + +// fn wait(i: u32) { +// for _ in 0..i { +// cortex_m::asm::nop(); // no operation (cannot be optimized out) +// } +// } + +// // see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf) +// // rcc, chapter 6 +// // gpio, chapter 8 + +// fn init(p: init::Peripherals) { +// // power on GPIOA, RM0368 6.3.11 +// p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + +// // configure PA5 as output, RM0368 8.4.1 +// p.GPIOA.moder.modify(|_, w| w.moder5().bits(1)); + +// // loop { +// // // set PA5 high, RM0368 8.4.6 +// // p.GPIOA.odr.modify(|_, w| w.odr5().bit(true)); +// // wait(10_000); + +// // // set PA5 low, RM0368 8.4.6 +// // p.GPIOA.odr.modify(|_, w| w.odr5().bit(false)); +// // wait(10_000); +// // } + +// // rewrite the above code to have the GPIO as output +// // and alter the data output through the BSRR register +// // this is more efficient as the read register (in modify) +// // is not needed. + +// loop { +// // set PA5 high, RM0368 8.4.7 +// p.GPIOA.bsrr.write(|w| w.bs5().set_bit()); +// wait(10_000); + +// // set PA5 low, RM0368 8.4.7 +// p.GPIOA.bsrr.write(|w| w.br5().set_bit()); +// wait(10_000); +// } +// } + +// #[inline(never)] +// fn idle() -> ! { +// loop { +// rtfm::wfi(); +// } +// }