Skip to content
Snippets Groups Projects
Commit 7bbafc33 authored by Per Lindgren's avatar Per Lindgren
Browse files

readme and examples

parent fd4618b6
No related branches found
No related tags found
No related merge requests found
...@@ -94,6 +94,24 @@ ...@@ -94,6 +94,24 @@
], ],
"cwd": "${workspaceRoot}" "cwd": "${workspaceRoot}"
}, },
{
"type": "gdb",
"request": "attach",
"name": "bare0",
"gdbpath": "/usr/bin/arm-none-eabi-gdb",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare0",
"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", "type": "gdb",
"request": "attach", "request": "attach",
...@@ -184,5 +202,23 @@ ...@@ -184,5 +202,23 @@
], ],
"cwd": "${workspaceRoot}" "cwd": "${workspaceRoot}"
}, },
{
"type": "gdb",
"request": "attach",
"name": "bare6",
"gdbpath": "/usr/bin/arm-none-eabi-gdb",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare6",
"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
...@@ -63,6 +63,18 @@ ...@@ -63,6 +63,18 @@
"isDefault": true "isDefault": true
} }
}, },
{
"type": "shell",
"label": "xargo build --example bare0",
"command": "xargo build --example bare0",
"problemMatcher": [
"$rustc"
],
"group": {
"kind": "build",
"isDefault": true
}
},
{ {
"type": "shell", "type": "shell",
"label": "xargo build --example bare1", "label": "xargo build --example bare1",
......
...@@ -123,6 +123,62 @@ The content of the file `r` is simply: ...@@ -123,6 +123,62 @@ The content of the file `r` is simply:
monitor reset init monitor reset init
``` ```
---
# Examples
In the `examples` folder you find:
## bare0.rs
This is a simple bare metal applicaiton:
- The `cortex-m-rt` provides a minimalistic runtime and startup of the ARM Cortex M. Providing:
- Linker script, telling the linker howto generate the binary.
- The `reset` handler, initiating the memory (and FPU if available on the target), and calls the user `main` function.
- Default exception handlers.
- A user defined `main()`
``` rust
fn main() {
let mut x = 0;
loop {
x += 1;
}
}
```
- User defined interrupt handlers.
``` rust
// 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();
}
```
As seen, we need to tell the compiler in what `section` the interrupt "vector" (array) should go. The ARM-Cortex-M has 16 exceptions and serves a maximum of 240 interrupt sources.
The target specific memory layout is given by the file `memory.x`.
``` txt
/* STM32F401re */
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 96K
}
```
In effect, `bare0::main` will be stored in the `FLASH` memory segment, while our
# License # License
Licensed under either of Licensed under either of
......
//! bare0.rs
//! Simple bare metal application
// feature to ensure symbols to be linked
#![feature(used)]
// build without the Rust standard library
#![no_std]
// Minimal runtime / startup for Cortex-M microcontrollers
extern crate cortex_m_rt;
static mut X: u32 = 10;
fn main() {
let mut x = unsafe { X };
loop {
x += 1;
unsafe {
X += 1;
assert!(x == X);
}
}
}
// 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() {}
...@@ -7,27 +7,27 @@ ...@@ -7,27 +7,27 @@
#![no_std] #![no_std]
// API to the ARM Cortex M Peripherals // API to the ARM Cortex M Peripherals
extern crate cortex_m; //extern crate cortex_m;
// Minimal runtime / startup for Cortex-M microcontrollers // Minimal runtime / startup for Cortex-M microcontrollers
extern crate cortex_m_rt; extern crate cortex_m_rt;
// Convenient tracing over semihosting and ITM // Convenient tracing over semihosting and ITM
#[macro_use] // #[macro_use]
extern crate cortex_m_debug; // extern crate cortex_m_debug;
#[inline(never)] #[inline(never)]
fn main() { fn main() {
// ITM trace (fast) // ITM trace (fast)
// start `itmdump` before `openocd` // start `itmdump` before `openocd`
ipln!("ITM: Hello World"); // ipln!("ITM: Hello World");
// semihosting trace (slow) // semihosting trace (slow)
sprintln!("SEMIHOSTING: Hello World"); // sprintln!("SEMIHOSTING: Hello World");
// to prevent returning // to prevent returning
loop { loop {
cortex_m::asm::nop(); // cortex_m::asm::nop();
} }
} }
...@@ -37,5 +37,5 @@ fn main() { ...@@ -37,5 +37,5 @@ fn main() {
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240]; static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
extern "C" fn default_handler() { extern "C" fn default_handler() {
cortex_m::asm::bkpt(); // cortex_m::asm::bkpt();
} }
...@@ -2,19 +2,24 @@ ...@@ -2,19 +2,24 @@
//! Simple bare metal application //! Simple bare metal application
//! //!
#![feature(used)] #![feature(used)]
#![feature(custom_attribute)] // needed for #[rustfmt_skip]
#![no_std] #![no_std]
extern crate cortex_m; extern crate cortex_m;
extern crate cortex_m_rt; extern crate cortex_m_rt;
// Peripheral addresses as constants // Peripheral addresses as constants
const PERIPH_BASE: u32 = 0x40000000; #[rustfmt_skip]
const AHB1PERIPH_BASE: u32 = PERIPH_BASE + 0x00020000; mod address {
const RCC_BASE: u32 = AHB1PERIPH_BASE + 0x3800; pub const PERIPH_BASE: u32 = 0x40000000;
const RCC_AHB1ENR: u32 = RCC_BASE + 0x30; pub const AHB1PERIPH_BASE: u32 = PERIPH_BASE + 0x00020000;
const GBPIA_BASE: u32 = AHB1PERIPH_BASE + 0x0000; pub const RCC_BASE: u32 = AHB1PERIPH_BASE + 0x3800;
const GPIOA_MODER: u32 = GBPIA_BASE + 0x00; pub const RCC_AHB1ENR: u32 = RCC_BASE + 0x30;
const GPIOA_BSRR: u32 = GBPIA_BASE + 0x18; 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) // see the Reference Manual RM0368 (www.st.com/resource/en/reference_manual/dm00096844.pdf)
// rcc, chapter 6 // rcc, chapter 6
...@@ -40,7 +45,6 @@ fn wait(i: u32) { ...@@ -40,7 +45,6 @@ fn wait(i: u32) {
fn main() { fn main() {
// power on GPIOA, RM0368 6.3.11 // power on GPIOA, RM0368 6.3.11
let r = read_u32(RCC_AHB1ENR); // read let r = read_u32(RCC_AHB1ENR); // read
write_u32(RCC_AHB1ENR, r | 1); // set enable write_u32(RCC_AHB1ENR, r | 1); // set enable
...@@ -49,8 +53,7 @@ fn main() { ...@@ -49,8 +53,7 @@ fn main() {
write_u32(GPIOA_MODER, r | 0b01 << (5 * 2)); // set output mode write_u32(GPIOA_MODER, r | 0b01 << (5 * 2)); // set output mode
// and alter the data output through the BSRR register // and alter the data output through the BSRR register
// this is more efficient as the read register (in modify) // this is more efficient as the read register is not needed.
// is not needed.
loop { loop {
// set PA5 high, RM0368 8.4.7 // set PA5 high, RM0368 8.4.7
......
...@@ -8,13 +8,10 @@ ...@@ -8,13 +8,10 @@
extern crate cortex_m; extern crate cortex_m;
extern crate cortex_m_rt; extern crate cortex_m_rt;
// #[macro_use] // C like API...
// extern crate cortex_m_debug;
mod stm32f40x { mod stm32f40x {
use core::{cell, ptr}; use core::{cell, ptr};
// C like API...
#[rustfmt_skip] #[rustfmt_skip]
mod address { mod address {
pub const PERIPH_BASE: u32 = 0x40000000; pub const PERIPH_BASE: u32 = 0x40000000;
...@@ -123,9 +120,7 @@ fn wait(i: u32) { ...@@ -123,9 +120,7 @@ fn wait(i: u32) {
} }
fn main() { fn main() {
// // power on GPIOA, RM0368 6.3.11 // power on GPIOA, RM0368 6.3.11
// p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
let rcc = RCC::get(); // get the reference to RCC in memory let rcc = RCC::get(); // get the reference to RCC in memory
unsafe { unsafe {
let r = (*rcc).AHB1ENR.read(); // read let r = (*rcc).AHB1ENR.read(); // read
......
//! bare6.rs
//! Simple bare metal application
//!
#![feature(used)]
#![feature(use_nested_groups)]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
#[macro_use]
extern crate cortex_m_debug;
use cortex_m::{asm::bkpt, peripheral::DWT};
// uses the DWT.CYCNT
// doc: ARM trm_100166_0001_00_en.pdf, chapter 9.2
// we use the `cortex-m` abstraction
fn wait_cycles(nr_cycles: u32) {
unsafe {
let t = (*DWT.get()).cyccnt.read().wrapping_add(nr_cycles);
while ((*DWT.get()).cyccnt.read().wrapping_sub(t) as i32) < 0 {}
}
}
fn main() {
unsafe { (*DWT.get()).enable_cycle_counter() };
let mut i = 0;
loop {
ipln!("tick {}", i);
wait_cycles(64_000_000);
i += 1; // this will eventually cause a panic, when the counter wraps.
}
}
// 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();
}
/* STM32F103C8V6 */ /* STM32F401re */
MEMORY MEMORY
{ {
FLASH : ORIGIN = 0x08000000, LENGTH = 64K FLASH : ORIGIN = 0x08000000, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 20K RAM : ORIGIN = 0x20000000, LENGTH = 96K
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment