Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
Loading items

Target

Select target project
  • Frappe/e7020e_2021
  • rognda-6/e7020e_2021
  • Klomega/e7020e_2021
  • pln/e7020e_2021
  • CarlOsterberg/e7020e_2021
  • jonjac-6/e7020e_2021
  • deux-babiri-futari/e7020e_2021
  • samgra-7/e7020e_2021
  • JosefUtbult/e7020e_2021
  • edwkll-7/e7020e_2021
10 results
Select Git revision
Loading items
Show changes
Commits on Source (1)
//! rtic_bare7.rs
//!
//! HAL OutputPin abstractions
//!
//! What it covers:
//! - using embedded hal, and the OutputPin abstraction
#![no_main]
#![no_std]
use panic_rtt_target as _;
use rtic::cyccnt::{Instant, U32Ext as _};
use rtt_target::{rprintln, rtt_init_print};
use stm32f4xx_hal::stm32;
use stm32f4xx_hal::{
gpio::{gpioa::PA1, gpioa::PA2, gpioa::PA3, Output, PushPull},
prelude::*,
};
use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
const OFFSET: u32 = 50_000_000;
#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
const APP: () = {
struct Resources {
// late resources
//GPIOA: stm32::GPIOA,
led_red: PA3<Output<PushPull>>,
led_green: PA2<Output<PushPull>>,
led_blue: PA1<Output<PushPull>>,
}
#[init(schedule = [toggle])]
fn init(cx: init::Context) -> init::LateResources {
rtt_init_print!();
rprintln!("init");
let mut core = cx.core;
let device = cx.device;
// Initialize (enable) the monotonic timer (CYCCNT)
core.DCB.enable_trace();
core.DWT.enable_cycle_counter();
// semantically, the monotonic timer is frozen at time "zero" during `init`
// NOTE do *not* call `Instant::now` in this context; it will return a nonsense value
let now = cx.start; // the start time of the system
// Schedule `toggle` to run 8e6 cycles (clock cycles) in the future
let number_of_toggles = 0;
cx.schedule.toggle(now + OFFSET.cycles(),number_of_toggles).unwrap();
// power on GPIOA, RM0368 6.3.11
device.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
// configure PA3 as output, RM0368 8.4.1
device.GPIOA.moder.modify(|_, w| w.moder3().bits(1));
device.GPIOA.moder.modify(|_, w| w.moder2().bits(1));
device.GPIOA.moder.modify(|_, w| w.moder1().bits(1));
let gpioa = device.GPIOA.split();
// pass on late resources
init::LateResources {
//GPIOA: device.GPIOA,
led_red: gpioa.pa3.into_push_pull_output(),
led_green: gpioa.pa2.into_push_pull_output(),
led_blue: gpioa.pa1.into_push_pull_output(),
}
}
#[idle]
fn idle(_cx: idle::Context) -> ! {
rprintln!("idle");
loop {
continue;
}
}
#[task(resources = [led_green,led_blue,led_red], schedule = [toggle])]
fn toggle(cx: toggle::Context, mut no_toggled: i32) {
static mut TOGGLE: bool = false;
//rprintln!("toggle @ {:?}", Instant::now());
//rprintln!("times I have toggled {:?}", no_toggled);
no_toggled +=1;
if no_toggled % 8 == 0{
rprintln!("White");
cx.resources.led_red.set_high().ok();
cx.resources.led_green.set_high().ok();
cx.resources.led_blue.set_high().ok();
} else if no_toggled % 8 == 1{
rprintln!("Green-yellow"); //Needs more oomph to be real yellow.
cx.resources.led_red.set_high().ok();
cx.resources.led_green.set_high().ok();
cx.resources.led_blue.set_low().ok();
} else if no_toggled % 8 == 2{
rprintln!("Purple");
cx.resources.led_red.set_high().ok();
cx.resources.led_green.set_low().ok();
cx.resources.led_blue.set_high().ok();
} else if no_toggled % 8 == 3{
rprintln!("Light blue");
cx.resources.led_red.set_low().ok();
cx.resources.led_green.set_high().ok();
cx.resources.led_blue.set_high().ok();
} else if no_toggled % 8 == 4{
rprintln!("Red");
cx.resources.led_red.set_high().ok();
cx.resources.led_green.set_low().ok();
cx.resources.led_blue.set_low().ok();
} else if no_toggled % 8 == 5{
rprintln!("Green");
cx.resources.led_red.set_low().ok();
cx.resources.led_green.set_high().ok();
cx.resources.led_blue.set_low().ok();
} else if no_toggled % 8 == 6{
rprintln!("Blue");
cx.resources.led_red.set_low().ok();
cx.resources.led_green.set_low().ok();
cx.resources.led_blue.set_high().ok();
} else {
rprintln!("Off");
cx.resources.led_red.set_low().ok();
cx.resources.led_green.set_low().ok();
cx.resources.led_blue.set_low().ok();
}
//*TOGGLE = !*TOGGLE;
cx.schedule.toggle(cx.scheduled + OFFSET.cycles(),no_toggled).unwrap();
}
extern "C" {
fn EXTI0();
}
};
fn _toggle_generic<E>(led: &mut dyn OutputPin<Error = E>, toggle: &mut bool) {
if *toggle {
led.set_high().ok();
} else {
led.set_low().ok();
}
*toggle = !*toggle;
}
fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) {
led.toggle().ok();
}
// 1. In this example you will use RTT.
//
// > cargo run --example rtic_bare7
//
// Look in the generated documentation for `set_high`/`set_low`.
// (You created documentation for your dependencies in previous exercise
// so you can just search (press `S`) for `OutputPin`).
// You will find that these methods are implemented for `Output` pins.
//
// Now change your code to use these functions instead of the low-level GPIO API.
//
// HINTS:
// - A GPIOx peripheral can be `split` into individual PINs Px0..Px15).
// - A Pxy, can be turned into an `Output` by `into_push_pull_output`.
// - You may optionally set other pin properties as well (such as `speed`).
// - An `Output` pin provides `set_low`/`set_high`
// - Instead of passing `GPIO` resource to the `toggle` task pass the
// `led: PA5<Output<PushPull>>` resource instead.
//
// Comment your code to explain the steps taken.
//
// Confirm that your implementation correctly toggles the LED as in
// previous exercise.
//
// Commit your code (bare7_1)
//
// 2. Further generalizations:
//
// Now look at the documentation for `embedded_hal::digital::v2::OutputPin`.
//
// You see that the OutputPin trait defines `set_low`/`set_high` functions.
// Your task is to alter the code to use the `set_low`/`set_high` API.
//
// The function `_toggle_generic` is generic to any object that
// implements the `OutputPin<Error = E>` trait.
//
// Digging deeper we find the type parameter `E`, which in this case
// is left generic (unbound).
//
// It will be instantiated with a concrete type argument when called.
//
// Our `PA5<Output<PushPull>>` implements `OutputPin` trait, thus
// we can pass the `led` resource to `_toggle_generic`.
//
// The error type is given by the stm32f4xx-hal implementation:
// where `core::convert::Infallible` is used to indicate
// there are no errors to be expected (hence infallible).
//
// Additionally, `_toggle_generic` takes a mutable reference
// `toggle: &mut bool`, so you need to pass your `TOGGLE` variable.
//
// As you see, `TOGGLE` holds the "state", switching between
// `true` and `false` (to make your led blink).
//
// Change your code into using the `_toggle_generic` function.
// (You may rename it to `toggle_generic` if wished.)
//
// Confirm that your implementation correctly toggles the LED as in
// previous exercise.
//
// Commit your code (bare7_2)
//
// 3. What about the state?
//
// In your code `TOGGLE` holds the "state". However, the underlying
// hardware ALSO holds the state (if the corresponding bit is set/cleared).
//
// What if we can leverage that, and guess what we can!!!!
//
// Look at the documentation for `embedded_hal::digital::v2::ToggleableOutputPin`,
// and the implementation of:
//
// fn _toggleable_generic(led: &mut dyn ToggleableOutputPin<Error = Infallible>) {
// led.toggle().ok();
// }
//
// The latter does not take any state variable, instead it directly `toggle()`
// the `ToggleableOutputPin`.
//
// Now alter your code to leverage on the `_toggleable_generic` function.
// (You should be able to remove the `TOGGLE` state variable altogether.)
//
// Confirm that your implementation correctly toggles the LED as in
// previous exercise.
//
// Commit your code (bare7_3)
//
// 4. Discussion:
//
// In this exercise you have gone from a very hardware specific implementation,
// to leveraging abstractions (batteries included).
//
// Your final code amounts to "configuration" rather than "coding".
//
// This reduces the risk of errors (as you let the libraries do the heavy lifting).
//
// This also improves code-re use. E.g., if you were to do something less
// trivial then merely toggling you can do that in a generic manner,
// breaking out functionality into "components" re-usable in other applications.
//
// Of course the example is trivial, you don't gain much here, but the principle
// is the same behind drivers for USART communication, USB, PMW3389 etc.
//
// 5. More details:
//
// Looking closer at the implementation:
// `led: &mut dyn OutputPin<Error = E>`
//
// You may ask what kind of mumbo jumbo is at play here.
//
// This is the way to express that we expect a mutable reference to a trait object
// that implements the `OutputPin`. Since we will change the underlying object
// (in this case an GPIOA pin 5) the reference needs to be mutable.
//
// Trait objects are further explained in the Rust book.
// The `dyn` keyword indicates dynamic dispatch (through a VTABLE).
// https://doc.rust-lang.org/std/keyword.dyn.html
//
// Notice: the Rust compiler (rustc + LLVM) is really smart. In many cases
// it can analyse the call chain, and conclude the exact trait object type at hand.
// In such cases the dynamic dispatch is turned into a static dispatch
// and the VTABLE is gone, and we have a zero-cost abstraction.
//
// If the trait object is stored for e.g., in an array along with other
// trait objects (of different concrete type), there is usually no telling
// the concrete type of each element, and we will have dynamic dispatch.
// Arguably, this is also a zero-cost abstraction, as there is no (obvious)
// way to implement it more efficiently. Remember, zero-cost is not without cost
// just that it is as good as it possibly gets (you can't make it better by hand).
//
// You can also force the compiler to deduce the type at compile time, by using
// `impl` instead of `dyn`, if you are sure you don't want the compiler to
// "fallback" to dynamic dispatch.
//
// You might find Rust to have long compile times. Yes you are right,
// and this type of deep analysis done in release mode is part of the story.
// On the other hand, the aggressive optimization allows us to code
// in a generic high level fashion and still have excellent performing binaries.
\ No newline at end of file
//! bare8.rs
//!
//! Serial
//!
//! What it covers:
//! - serial communication
//! - bad design
#![no_main]
#![no_std]
use panic_rtt_target as _;
use stm32f4xx_hal::{
gpio::{gpioa::PA, Output, PushPull},
prelude::*,
serial::{config::Config, Rx, Serial, Tx},
stm32::USART2,
nb::block,
};
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;
let mut received = 0;
let mut errors = 0;
loop {
match block!(rx.read()) {
Ok(byte) => {
rprintln!("Ok {:?}", byte);
tx.write(byte).unwrap();
received +=1;
}
Err(err) => {
rprintln!("Error {:?}", err);
let test:u8 = 13;
tx.write(test).unwrap();
errors +=1;
}
}
rprintln!("Numbers of received: {:?}", received);
rprintln!("Numbers of errors: {:?}", errors);
}
}
};
// 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`?
//
// I can't run moserial (Windows). But PuTTY seems to get a.
//
// What do you receive in the RTT terminal?
//
// OK 97
//
// Try sending: "abcd" as a single sequence, don't send the quotation marks, just abcd.
//
// What did you receive in `moserial`?
//
// ad (Running PuTTY. Not moserial)
//
// What do you receive in the RTT terminal?
//
// Ok 97
// Error Overrun
// Ok 100
//
// What do you believe to be the problem?
//
// Hint: Look at the code in `idle` what does it do?
//
// The buffer have not been read from and has not been cleared.
//
// Experiment a bit, what is the max length sequence you can receive without errors?
//
// 8 bits or 1 byte.
//
// 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?
//
// 1
//
// How did the added tracing/instrumentation affect the behavior?
//
// I now only receive a back.
//
// 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?
//
// Now I receive "ad" again
//
// 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.)
......@@ -98,7 +98,7 @@ const APP: () = {
rprintln!("toggle @ {:?}", Instant::now());
if *TOGGLE {
cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit());
cx.resources.GPIOA.bsrr.write(|w| w.bs5z().set_bit());
} else {
cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit());
}
......
......@@ -8,6 +8,7 @@
#![no_main]
#![no_std]
use panic_rtt_target as _;
use rtic::cyccnt::{Instant, U32Ext as _};
use rtt_target::{rprintln, rtt_init_print};
......@@ -17,7 +18,7 @@ use stm32f4xx_hal::{
gpio::{gpioa::PA5, Output, PushPull},
prelude::*,
};
;
use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
const OFFSET: u32 = 8_000_000;
......@@ -26,17 +27,19 @@ const OFFSET: u32 = 8_000_000;
const APP: () = {
struct Resources {
// late resources
GPIOA: stm32::GPIOA,
// led: PA5<Output<PushPull>>,
//GPIOA: stm32::GPIOA,
led: PA5<Output<PushPull>>,
}
#[init(schedule = [toggle])]
fn init(cx: init::Context) -> init::LateResources {
rtt_init_print!();
rprintln!("init");
let mut core = cx.core;
let device = cx.device;
// Initialize (enable) the monotonic timer (CYCCNT)
core.DCB.enable_trace();
core.DWT.enable_cycle_counter();
......@@ -46,16 +49,21 @@ const APP: () = {
let now = cx.start; // the start time of the system
// Schedule `toggle` to run 8e6 cycles (clock cycles) in the future
cx.schedule.toggle(now + OFFSET.cycles()).unwrap();
let number_of_toggles = 0;
cx.schedule.toggle(now + OFFSET.cycles(),number_of_toggles).unwrap();
// power on GPIOA, RM0368 6.3.11
device.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
// configure PA5 as output, RM0368 8.4.1
device.GPIOA.moder.modify(|_, w| w.moder5().bits(1));
let gpioa = device.GPIOA.split();
// pass on late resources
init::LateResources {
GPIOA: device.GPIOA,
//GPIOA: device.GPIOA,
led: gpioa.pa5.into_push_pull_output(),
}
}
......@@ -67,19 +75,25 @@ const APP: () = {
}
}
#[task(resources = [GPIOA], schedule = [toggle])]
fn toggle(cx: toggle::Context) {
#[task(resources = [led], schedule = [toggle])]
fn toggle(cx: toggle::Context, mut no_toggled: i32) {
static mut TOGGLE: bool = false;
rprintln!("toggle @ {:?}", Instant::now());
rprintln!("times I have toggled {:?}", no_toggled);
no_toggled +=1;
/*
if *TOGGLE {
cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit());
cx.resources.led.set_high();
} else {
cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit());
cx.resources.led.set_low();
}
*/
_toggleable_generic(cx.resources.led);
*TOGGLE = !*TOGGLE;
cx.schedule.toggle(cx.scheduled + OFFSET.cycles()).unwrap();
//*TOGGLE = !*TOGGLE;
cx.schedule.toggle(cx.scheduled + OFFSET.cycles(),no_toggled).unwrap();
}
extern "C" {
......
......@@ -11,13 +11,13 @@
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,
nb::block,
};
use rtic::app;
......@@ -69,17 +69,25 @@ const APP: () = {
fn idle(cx: idle::Context) -> ! {
let rx = cx.resources.RX;
let tx = cx.resources.TX;
let mut received = 0;
let mut errors = 0;
loop {
match block!(rx.read()) {
Ok(byte) => {
rprintln!("Ok {:?}", byte);
tx.write(byte).unwrap();
received +=1;
}
Err(err) => {
rprintln!("Error {:?}", err);
let test:u8 = 13;
tx.write(test).unwrap();
errors +=1;
}
}
rprintln!("Numbers of received: {:?}", received);
rprintln!("Numbers of errors: {:?}", errors);
}
}
};
......@@ -113,31 +121,33 @@ const APP: () = {
//
// What do you receive in `moserial`?
//
// ** your answer here **
// I can't run moserial (Windows). But PuTTY seems to get a.
//
// What do you receive in the RTT terminal?
//
// ** your answer here **
// OK 97
//
// Try sending: "abcd" as a single sequence, don't send the quotation marks, just abcd.
//
// What did you receive in `moserial`?
//
// ** your answer here **
// ad (Running PuTTY. Not moserial)
//
// What do you receive in the RTT terminal?
//
// ** your answer here **
// Ok 97
// Error Overrun
// Ok 100
//
// What do you believe to be the problem?
//
// Hint: Look at the code in `idle` what does it do?
//
// ** your answer here **
// The buffer have not been read from and has not been cleared.
//
// Experiment a bit, what is the max length sequence you can receive without errors?
//
// ** your answer here **
// 8 bits or 1 byte.
//
// Commit your answers (bare8_1)
//
......@@ -152,11 +162,11 @@ const APP: () = {
//
// 3. Experiment a bit, what is the max length sequence you can receive without errors?
//
// ** your answer here **
// 1
//
// How did the added tracing/instrumentation affect the behavior?
//
// ** your answer here **
// I now only receive a back.
//
// Commit your answer (bare8_3)
//
......@@ -168,7 +178,7 @@ const APP: () = {
//
// Experiment a bit, what is the max length sequence you can receive without errors?
//
// ** your answer here **
// Now I receive "ad" again
//
// Commit your answer (bare8_4)
//
......
......@@ -13,17 +13,23 @@ use stm32f4xx_hal::{
prelude::*,
serial::{config::Config, Event, Rx, Serial, Tx},
stm32::USART2,
nb::block,
};
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(0)]
fel: u32,
#[init(0)]
corr: u32,
}
// init runs in an interrupt free section
......@@ -71,23 +77,51 @@ const APP: () = {
}
// capacity sets the size of the input buffer (# outstanding messages)
#[task(resources = [TX], priority = 1, capacity = 128)]
#[task(resources = [TX], priority = 2, capacity = 128)]
fn rx(cx: rx::Context,data:u8) {
let tx = cx.resources.TX;
tx.write(data).unwrap();
}
#[task(priority = 1,resources = [fel,corr])]
fn trace(cx: trace::Context, worked: bool,data:u8,){
match worked{
true => {
*cx.resources.corr +=1;
rprintln!("Ok {:?}", data);
}
false =>{
*cx.resources.fel +=1;
rprintln!("some error");
}
}
rprintln!("correct {}", cx.resources.corr);
rprintln!("errors {}", cx.resources.fel);
rprintln!("data {}", data);
}
// Task bound to the USART2 interrupt.
#[task(binds = USART2, priority = 2, resources = [RX], spawn = [rx])]
#[task(binds = USART2, priority = 3, resources = [RX], spawn = [rx,trace])]
fn usart2(cx: usart2::Context) {
let rx = cx.resources.RX;
let data = rx.read().unwrap();
let data;
match (rx.read()) {
Ok(byte) => {
data = byte;
let result = cx.spawn.trace(true,byte);
}
Err(err) => {
data = 0;
rprintln!("Error {:?}", err);
cx.spawn.trace(false,data).unwrap();
}
}
cx.spawn.rx(data).unwrap();
}
extern "C" {
fn EXTI0();
fn USART1();
}
};
......@@ -148,7 +182,7 @@ const APP: () = {
//
// Were you able to crash it?
//
// ** your answer here **
// Yes
//
// Notice, the input tracing in `moserial` seems broken, and may loose data.
// So don't be alarmed if data is missing, its a GUI tool after all.
......
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_std]
#![no_main]
// pick a panicking behavior
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
// use panic_abort as _; // requires nightly
// pick a panicking behavior// use panic_abort as _; // requires nightly
// use panic_itm as _; // logs messages over ITM; requires ITM support
// use panic_semihosting as _; // logs messages to the host stderr; requires a debugger
use cortex_m::asm;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
asm::nop(); // To not have main optimize to abort in release mode, remove when you add code
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
use rtt_target::{rprintln, rtt_init_print};
use cortex_m::peripheral::DWT;
use stm32f4xx_hal::stm32;
//use cortex_m::asm;
//use cortex_m_rt::entry;
use rtic::cyccnt::{Instant, U32Ext as _};
#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
const APP: () = {
struct Resources {
// late resources
GPIOA: stm32::GPIOA,
GPIOC: stm32::GPIOC,
//button: <stm32::GPIOC as int>::PC13,
}
#[init(schedule = [toggle])]
fn init(cx: init::Context) -> init::LateResources {
rtt_init_print!();
rprintln!("init");
for i in 0..11 {
rprintln!("RTIC Says Hello, world {}!!", i);
}
let mut core = cx.core;
let device = cx.device;
// Initialize (enable) the monotonic timer (CYCCNT)
core.DCB.enable_trace();
// required on Cortex-M7 devices that software lock the DWT (e.g. STM32F7)
DWT::unlock();
core.DWT.enable_cycle_counter();
// semantically, the monotonic timer is frozen at time "zero" during `init`
// NOTE do *not* call `Instant::now` in this context; it will return a nonsense value
let now = cx.start; // the start time of the system
// Schedule `toggle` to run 8e6 cycles (clock cycles) in the future
cx.schedule.toggle(now + 8_000_000.cycles()).unwrap();
// power on GPIOA, RM0368 6.3.11
device.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
// configure PA5 as output, RM0368 8.4.1
device.GPIOA.moder.modify(|_, w| w.moder5().bits(1));
// Test button thingy. Think I put PC13 to input
device.GPIOC.moder.modify(|_, w| w.moder13().bits(0));
// device.GPIOC.pupdr.modify(|_, w| w.pupdr13().bits(0));
// pass on late resources
init::LateResources {
GPIOA: device.GPIOA,
GPIOC: device.GPIOC,
//button: device.button,
}
}
#[idle]
fn idle(_cx: idle::Context) -> ! {
rprintln!("lets get lazy");
loop {
// your code goes here
continue;
}
}
#[task(resources = [GPIOA,GPIOC], schedule = [toggle])]
fn toggle(cx: toggle::Context) {
static mut TOGGLE: bool = false;
rprintln!("toggle @ {:?}", Instant::now());
if *TOGGLE {
cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit());
} else {
cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit());
}
<<<<<<< HEAD
=======
//cx.resources.GPIOC.PullDown;
>>>>>>> 3104a68743e72194c1e8649cdee76a82240fc05e
*TOGGLE = !*TOGGLE;
cx.schedule
.toggle(cx.scheduled + 16_000_000.cycles())
.unwrap();
<<<<<<< HEAD
=======
>>>>>>> 3104a68743e72194c1e8649cdee76a82240fc05e
}
extern "C" {
fn EXTI0();
}
};