Skip to content

Commit

Permalink
Merge #354
Browse files Browse the repository at this point in the history
354: Fix and clean up 11-usart by bumping dependencies r=adamgreig a=sirhcel

This is an alternate version of #267 which fixes the panic by bumping dependencies. It also addresses the previously unsafe access to the USARTs transmit and receive data registers (TDR and RDR, stm32-rs/stm32-rs#558) by bumping the BSP to the brand spanking new release 0.7.0 which comes with a fixed PAC and HAL. Thank you very much @adamgreig, @Sh3Rm4n, and @rubberduck203 for your patience and support along this journey!

This PR also bumps non-critical dependencies to their actual releases. For example `heapless`, which makes use of const generics nowadays.

I did not succeed in getting `mdbook test` to actually check the example code. I moved it over to the `examples` directory and included it in the Markdown files so that it can be checked with `cargo build --target thumbv7em-none-eabihf --examples`.

Co-authored-by: Christian Meusel <christian.meusel@posteo.de>
  • Loading branch information
bors[bot] and sirhcel committed Jun 21, 2021
2 parents 74aa554 + 9655eef commit 2b73ce6
Show file tree
Hide file tree
Showing 18 changed files with 299 additions and 234 deletions.
3 changes: 2 additions & 1 deletion src/03-setup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Checkout the github issues like [this][gh-issue-274].
We'll use all the tools listed below. Where a minimum version is not specified, any recent version
should work but we have listed the version we have tested.

- Rust 1.31 or a newer toolchain.
- Rust 1.31 or a newer toolchain. Chapter [USART](../11-usart/index.html)
requires 1.51 or newer.

- [`itmdump`] >=0.3.1 (`cargo install itm`). Tested versions: 0.3.1.

Expand Down
2 changes: 1 addition & 1 deletion src/11-usart/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ path = "auxiliary"

[dependencies.heapless]
default-features = false
version = "0.3.7"
version = "0.7.1"
8 changes: 4 additions & 4 deletions src/11-usart/auxiliary/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ name = "aux11"
version = "0.1.0"

[dependencies]
cortex-m = "0.6.3"
cortex-m-rt = "0.6.3"
panic-itm = "0.4.0"
stm32f3-discovery = "0.6.0"
cortex-m = "0.7.2"
cortex-m-rt = "0.6.14"
panic-itm = "0.4.2"
stm32f3-discovery = "0.7.0"

[features]
adapter = []
20 changes: 11 additions & 9 deletions src/11-usart/auxiliary/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ extern crate panic_itm; // panic handler

pub use cortex_m::{asm::bkpt, iprint, iprintln, peripheral::ITM};
pub use cortex_m_rt::entry;
pub use stm32f3_discovery::stm32f3xx_hal::stm32::usart1;
pub use stm32f3_discovery::stm32f3xx_hal::pac::usart1;

pub mod monotimer;

use stm32f3_discovery::stm32f3xx_hal::{
prelude::*,
serial::Serial,
stm32::{self, USART1},
time::MonoTimer,
pac::{self, USART1},
};
use monotimer::MonoTimer;

pub fn init() -> (&'static mut usart1::RegisterBlock, MonoTimer, ITM) {
let cp = cortex_m::Peripherals::take().unwrap();
let dp = stm32::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();

let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
Expand All @@ -30,23 +32,23 @@ pub fn init() -> (&'static mut usart1::RegisterBlock, MonoTimer, ITM) {
() => {
let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);

let tx = gpioa.pa9.into_af7(&mut gpioa.moder, &mut gpioa.afrh);
let rx = gpioa.pa10.into_af7(&mut gpioa.moder, &mut gpioa.afrh);
let tx = gpioa.pa9.into_af7_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh);
let rx = gpioa.pa10.into_af7_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh);

(tx, rx)
}
#[cfg(not(feature = "adapter"))]
() => {
let mut gpioc = dp.GPIOC.split(&mut rcc.ahb);

let tx = gpioc.pc4.into_af7(&mut gpioc.moder, &mut gpioc.afrl);
let rx = gpioc.pc5.into_af7(&mut gpioc.moder, &mut gpioc.afrl);
let tx = gpioc.pc4.into_af7_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrl);
let rx = gpioc.pc5.into_af7_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrl);

(tx, rx)
}
};

Serial::usart1(dp.USART1, (tx, rx), 115_200.bps(), clocks, &mut rcc.apb2);
Serial::new(dp.USART1, (tx, rx), 115_200.Bd(), clocks, &mut rcc.apb2);
// If you are having trouble sending/receiving data to/from the
// HC-05 bluetooth module, try this configuration instead:
// Serial::usart1(dp.USART1, (tx, rx), 9600.bps(), clocks, &mut rcc.apb2);
Expand Down
54 changes: 54 additions & 0 deletions src/11-usart/auxiliary/src/monotimer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use stm32f3_discovery::stm32f3xx_hal as hal;

use cortex_m::peripheral::DWT;
use hal::{
rcc::Clocks,
time::rate::Hertz,
};

/// A monotonic nondecreasing timer. This is a resurrection of MonoTimer from
/// the stm32f3xx-hal where it got removed after 0.6.1.
#[derive(Clone, Copy)]
pub struct MonoTimer {
frequency: Hertz,
}

// TODO: What about a refactoring to implement Clock from embedded-time?
impl MonoTimer {
/// Creates a new `Monotonic` timer
pub fn new(mut dwt: DWT, clocks: Clocks) -> Self {
dwt.enable_cycle_counter();

// now the CYCCNT counter can't be stopped or resetted
drop(dwt);

MonoTimer {
frequency: clocks.hclk(),
}
}

/// Returns the frequency at which the monotonic timer is operating at
pub fn frequency(self) -> Hertz {
self.frequency
}

/// Returns an `Instant` corresponding to "now"
pub fn now(self) -> Instant {
Instant {
now: DWT::get_cycle_count(),
}
}
}

/// A measurement of a monotonically nondecreasing clock
#[derive(Clone, Copy)]
pub struct Instant {
now: u32,
}

impl Instant {
/// Ticks elapsed since the `Instant` was created
pub fn elapsed(self) -> u32 {
DWT::get_cycle_count().wrapping_sub(self.now)
}
}
80 changes: 3 additions & 77 deletions src/11-usart/buffer-overrun.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,7 @@
If you wrote your program like this:

``` rust
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -> ! {
let (usart1, mono_timer, itm) = aux11::init();

// Send a string
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
usart1
.tdr
.write(|w| unsafe { w.tdr().bits(u16::from(*byte)) });
}

loop {}
}
{{#include examples/buffer-overrun.rs}}
```

You probably received something like this on your computer when you executed the program compiled in
Expand Down Expand Up @@ -60,33 +42,7 @@ We can actually time how long it takes to execute the `for` loop. `aux11::init()
`std::time`.

``` rust
#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -> ! {
let (usart1, mono_timer, mut itm) = aux11::init();

let instant = mono_timer.now();
// Send a string
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
usart1.tdr.write(|w| w.tdr().bits(u16::from(*byte)));
}
let elapsed = instant.elapsed(); // in ticks

iprintln!(
&mut itm.stim[0],
"`for` loop took {} ticks ({} us)",
elapsed,
elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
);

loop {}
}
{{#include examples/buffer-overrun-timed.rs}}
```

In debug mode, I get:
Expand All @@ -109,37 +65,7 @@ to write to the `TDR` register without incurring in data loss.
Let's use that to slowdown the processor.

``` rust
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -> ! {
let (usart1, mono_timer, mut itm) = aux11::init();

let instant = mono_timer.now();
// Send a string
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
// wait until it's safe to write to TDR
while usart1.isr.read().txe().bit_is_clear() {} // <- NEW!

usart1
.tdr
.write(|w| unsafe { w.tdr().bits(u16::from(*byte)) });
}
let elapsed = instant.elapsed(); // in ticks

iprintln!(
&mut itm.stim[0],
"`for` loop took {} ticks ({} us)",
elapsed,
elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
);

loop {}
}
{{#include examples/buffer-overrun-txe.rs}}
```

This time, running the program in debug or release mode should result in a complete string on the
Expand Down
27 changes: 27 additions & 0 deletions src/11-usart/examples/buffer-overrun-timed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -> ! {
let (usart1, mono_timer, mut itm) = aux11::init();

let instant = mono_timer.now();
// Send a string
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
usart1.tdr.write(|w| w.tdr().bits(u16::from(*byte)));
}
let elapsed = instant.elapsed(); // in ticks

iprintln!(
&mut itm.stim[0],
"`for` loop took {} ticks ({} us)",
elapsed,
elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
);

loop {}
}
31 changes: 31 additions & 0 deletions src/11-usart/examples/buffer-overrun-txe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -> ! {
let (usart1, mono_timer, mut itm) = aux11::init();

let instant = mono_timer.now();
// Send a string
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
// wait until it's safe to write to TDR
while usart1.isr.read().txe().bit_is_clear() {} // <- NEW!

usart1
.tdr
.write(|w| w.tdr().bits(u16::from(*byte)));
}
let elapsed = instant.elapsed(); // in ticks

iprintln!(
&mut itm.stim[0],
"`for` loop took {} ticks ({} us)",
elapsed,
elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
);

loop {}
}
19 changes: 19 additions & 0 deletions src/11-usart/examples/buffer-overrun.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -> ! {
let (usart1, _mono_timer, _itm) = aux11::init();

// Send a string
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
usart1
.tdr
.write(|w| w.tdr().bits(u16::from(*byte)));
}

loop {}
}
48 changes: 48 additions & 0 deletions src/11-usart/examples/echo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};
use heapless::Vec;

#[entry]
fn main() -> ! {
let (usart1, _mono_timer, _itm) = aux11::init();

// A buffer with 32 bytes of capacity
let mut buffer: Vec<u8, 32> = Vec::new();

loop {
buffer.clear();

loop {
while usart1.isr.read().rxne().bit_is_clear() {}
let byte = usart1.rdr.read().rdr().bits() as u8;

if buffer.push(byte).is_err() {
// buffer full
for byte in b"error: buffer full\n\r" {
while usart1.isr.read().txe().bit_is_clear() {}
usart1
.tdr
.write(|w| w.tdr().bits(u16::from(*byte)));
}

break;
}

// Carriage return
if byte == 13 {
// Respond
for byte in buffer.iter().rev().chain(&[b'\n', b'\r']) {
while usart1.isr.read().txe().bit_is_clear() {}
usart1
.tdr
.write(|w| w.tdr().bits(u16::from(*byte)));
}

break;
}
}
}
}
21 changes: 21 additions & 0 deletions src/11-usart/examples/receive-a-single-byte.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -> ! {
let (usart1, _mono_timer, _itm) = aux11::init();

loop {
// Wait until there's data available
while usart1.isr.read().rxne().bit_is_clear() {}

// Retrieve the data
let _byte = usart1.rdr.read().rdr().bits() as u8;

aux11::bkpt();
}
}

0 comments on commit 2b73ce6

Please sign in to comment.