Skip to content
Snippets Groups Projects
Commit dd94f406 authored by Per's avatar Per
Browse files

bare 7 and 8 updated

parent 95e6b2aa
No related branches found
No related tags found
No related merge requests found
......@@ -464,8 +464,30 @@
"interface/stlink.cfg",
"target/stm32f4x.cfg"
],
"postLaunchCommands": [
"continue"
"swoConfig": {
"enabled": true,
"cpuFrequency": 16000000,
"swoFrequency": 2000000, // you may try 1000000 if not working
"source": "probe",
"decoders": [
{
"type": "console",
"label": "Name",
"port": 0
}
]
},
"cwd": "${workspaceRoot}"
},
{
"type": "cortex-debug",
"request": "launch",
"servertype": "openocd",
"name": "c bare8 16Mhz",
"executable": "./target/thumbv7em-none-eabihf/debug/examples/bare8",
"configFiles": [
"interface/stlink.cfg",
"target/stm32f4x.cfg"
],
"swoConfig": {
"enabled": true,
......
//! Serial interface loopback
#![deny(unsafe_code)]
#![deny(warnings)]
//#![deny(warnings)]
#![feature(proc_macro)]
#![no_std]
......@@ -27,7 +27,6 @@ const BAUD_RATE: Hertz = Hertz(115_200);
app! {
device: f4::stm32f40x,
}
// static BUFFER: Vec<u8, [u8; 8]> = Vec::new();
// Init executes with interrupts disabled
// Hence its safe to access all peripherals (no race-conditions)
......@@ -40,13 +39,13 @@ fn init(p: init::Peripherals) {
serial.init(BAUD_RATE.invert(), None, p.GPIOA, p.RCC);
let mut buffer: Vec<u8, [u8; 4]> = Vec::new();
let mut vector: Vec<u8, [u8; 4]> = Vec::new();
loop {
match block!(serial.read()) {
Ok(byte) => {
let _ = buffer.push(byte);
ipln!("Ok {:?}", buffer);
block!(serial.write(byte)).ok();
let _ = vector.push(byte);
ipln!("Ok {:?}", vector);
let _ = serial.write(byte);
}
Err(err) => {
ipln!("Error {:?}", err);
......@@ -108,7 +107,7 @@ fn idle() -> ! {
// your job now is to check the API of `heapless`
// https://docs.rs/heapless/0.2.1/heapless/
//
// and catch the case we are trying to write to a full buffer
// and catch the case we are trying to write to a full buffer/vector
// and write a suiteble error message
//
// commit your answers (bare7_2)
......
//! Serial interface loopback
#![deny(unsafe_code)]
#![deny(warnings)]
#![feature(proc_macro)]
#![no_std]
extern crate cortex_m_rtfm as rtfm;
extern crate f4;
extern crate heapless;
#[macro_use]
extern crate cortex_m_debug;
use f4::prelude::*;
use f4::Serial;
use f4::time::Hertz;
use heapless::Vec;
use rtfm::{app, Resource, Threshold};
// CONFIGURATION
const BAUD_RATE: Hertz = Hertz(115_200);
// RTFM FRAMEWORK
app! {
device: f4::stm32f40x,
resources: {
static VECTOR: Vec<u8, [u8; 4]> = Vec::new();
},
tasks: {
USART2: {
path: rx,
priority: 2,
resources: [VECTOR, USART2],
},
EXTI1: {
path: trace,
priority: 1,
resources: [VECTOR],
}
},
}
// `rx` task trigger on arrival of a USART2 interrupt
fn rx(t: &mut Threshold, r: USART2::Resources) {
let serial = Serial(&**r.USART2);
// we don't need to block waiting for data to arrive
// (as we were triggered) by the data arrival (or error)
match serial.read() {
Ok(byte) => {
// received byte correct
r.VECTOR.claim_mut(t, |vector, _| {
// critical section for the shared vector
let _ = vector.push(byte);
// here you could put your error handling for vector full
});
let _ = serial.write(byte);
}
Err(err) => {
// some transmission error
ipln!("Error {:?}", err);
r.USART2.dr.read(); // clear the error by reading the data register
}
}
// trigger the `trace` task
rtfm::set_pending(f4::stm32f40x::Interrupt::EXTI1);
}
// `trace` task triggered by the hight priority `rx` task
// a low priority task for the background processing (like tracing)
fn trace(t: &mut Threshold, r: EXTI1::Resources) {
let mut b = [0; 4]; // local buffer
let mut l = 0; // length of the received vector
r.VECTOR.claim(t, |vector, _| {
// critical section for the shared vector
// here the task `rx` will be blocked from executing
l = vector.len();
b[..l].copy_from_slice(&***vector); // efficent copy vector to the local buffer
});
// since we do the actual tracing (relatively slow)
// OUTSIDE the claim (critical section), there will be no
// additional blocking of `rx`
ipln!("Vec {:?}", &b[..l]);
}
// Here we see the typical use of init INITIALIZING the system
fn init(p: init::Peripherals, _r: init::Resources) {
ipln!("init");
let serial = Serial(p.USART2);
serial.init(BAUD_RATE.invert(), None, p.GPIOA, p.RCC);
// in effect telling the USART2 to trigger the `rx` task/interrupt
serial.listen(f4::serial::Event::Rxne);
}
// We will spend all time sleeping (unless we have work to do)
// reactive programming in RTFM ftw!!!
fn idle() -> ! {
// Sleep
loop {
rtfm::wfi();
}
}
// 1. compile and run the project at 16MHz
// make sure its running (not paused)
// 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
// Handshake None
//
// (this is also known in short as 15200 8N1)
//
// you should now be able to send data and recive an echo from the MCU
//
// try sending: "abcd" as a single sequence (set the option No end in moserial)
// (don't send the quation marks, just abcd)
//
// what did you receive, and what was the output of the ITM trace
// ** your answer here **
//
// did you experience any over-run errors?
// ** your answer here **
//
// what is the key problem and its solution (try to follow the commented code)
// ** your answer here **
//
// commit your answers (bare8_1)
//
// 2. now catch the case when we are trying to write to a full vector/buffer
// and write a suiteble error message
//
// commit your answers (bare8_2)
//
// as a side note....
//
// The concurrency model behind RTFM offers
// 1. Race-free resource access
//
// 2. Deadlock-free exection
//
// 3. Shared execution stack (no pre-allocated stack regions)
//
// 4. Bound priority inversion
//
// 5. Theoretical underpinning ->
// + proofs of soundness
// + schedulability analysis
// + response time analysis
// + stack memory analysis
// + ... leverages on 25 years of reseach in the real-time community
// based on the seminal work of Baker in the early 1990s
// (known as the Stack Resource Policy, SRP)
//
// Our implementation in Rust offers
// 1. compile check and analysis of tasks and resources
// + the API implementation together with the Rust compiler will ensure that
// both RTFM (SRP) soundness and the Rust memory model invariants
// are upheld (under all circumpstances).
//
// 2. arguably the worlds fastest real time scheduler *
// + task invocation 0-cycle OH on top of HW interrupt handling
// + 2 cycle OH for locking a shared resource (on claim entry)
// + 1 cycle OH for releasineg a shared resoure (on claim exit)
//
// 3. arguably the worlds most memory efficient scheduler *
// + 1 byte stack memory OH for each (nested) claim
// (no additional book-keeping during run-time)
//
// * applies to static task/resource models with single core
// pre-emptive, static priority scheduling
//
// in comparison "real-time" schedulers for threaded models like FreeRTOS
// - CPU and memory OH magnitudes larger (100s of cycles/kilobytes of memory)
// - ... and what's worse OH is typically unbound (no proofs of worst case)
// - potential race conditions (up to the user to verify)
// - potential dead-locks (up to the implementation)
// - potential unbound priority inversion (up to the implementation)
//
// Rust RTFM (currently) target ONLY STATIC SYSTEMS, there is no notion
// of dynamically creating new executions contexts/threads
// so a direct comparison is not completely fair.
//
// On the other hand, embedded applications are typically static by nature
// so a STATIC model is to that end better suitable.
//
// RTFM is reactive by nature, a task execute to end, triggered
// by an internal or external event, (where an interrupt is an external event
// from the environment, like a HW peripheral such as the USART2).
//
// Threads on the other hand are concurrent and infinte by nature and
// actively blocking/yeilding awaiting stimuli. Hence reactivity needs to be CODED.
// This leads to an anomaly, the underlying HW is reactive (interrupts),
// requiring an interrupt handler, that creates a signal to the scheduler.
//
// The scheduler then needs to keep track of all threads and at some point choose
// to dispatch the awaiting thread. So reactivity is bottlenecked to the point
// of scheduling by que management, context switching and other additional
// book keeping.
//
// In essence, the thread scheduler tries to re-establish the reactivity that
// were there (interrupts), a battle that cannot be won...
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment