Skip to content

Commit 2b73ce6

Browse files
bors[bot]sirhcel
andauthored
Merge #354
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>
2 parents 74aa554 + 9655eef commit 2b73ce6

18 files changed

+299
-234
lines changed

src/03-setup/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ Checkout the github issues like [this][gh-issue-274].
3636
We'll use all the tools listed below. Where a minimum version is not specified, any recent version
3737
should work but we have listed the version we have tested.
3838

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

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

src/11-usart/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ path = "auxiliary"
1111

1212
[dependencies.heapless]
1313
default-features = false
14-
version = "0.3.7"
14+
version = "0.7.1"

src/11-usart/auxiliary/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ name = "aux11"
55
version = "0.1.0"
66

77
[dependencies]
8-
cortex-m = "0.6.3"
9-
cortex-m-rt = "0.6.3"
10-
panic-itm = "0.4.0"
11-
stm32f3-discovery = "0.6.0"
8+
cortex-m = "0.7.2"
9+
cortex-m-rt = "0.6.14"
10+
panic-itm = "0.4.2"
11+
stm32f3-discovery = "0.7.0"
1212

1313
[features]
1414
adapter = []

src/11-usart/auxiliary/src/lib.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@ extern crate panic_itm; // panic handler
77

88
pub use cortex_m::{asm::bkpt, iprint, iprintln, peripheral::ITM};
99
pub use cortex_m_rt::entry;
10-
pub use stm32f3_discovery::stm32f3xx_hal::stm32::usart1;
10+
pub use stm32f3_discovery::stm32f3xx_hal::pac::usart1;
11+
12+
pub mod monotimer;
1113

1214
use stm32f3_discovery::stm32f3xx_hal::{
1315
prelude::*,
1416
serial::Serial,
15-
stm32::{self, USART1},
16-
time::MonoTimer,
17+
pac::{self, USART1},
1718
};
19+
use monotimer::MonoTimer;
1820

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

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

33-
let tx = gpioa.pa9.into_af7(&mut gpioa.moder, &mut gpioa.afrh);
34-
let rx = gpioa.pa10.into_af7(&mut gpioa.moder, &mut gpioa.afrh);
35+
let tx = gpioa.pa9.into_af7_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh);
36+
let rx = gpioa.pa10.into_af7_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh);
3537

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

42-
let tx = gpioc.pc4.into_af7(&mut gpioc.moder, &mut gpioc.afrl);
43-
let rx = gpioc.pc5.into_af7(&mut gpioc.moder, &mut gpioc.afrl);
44+
let tx = gpioc.pc4.into_af7_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrl);
45+
let rx = gpioc.pc5.into_af7_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrl);
4446

4547
(tx, rx)
4648
}
4749
};
4850

49-
Serial::usart1(dp.USART1, (tx, rx), 115_200.bps(), clocks, &mut rcc.apb2);
51+
Serial::new(dp.USART1, (tx, rx), 115_200.Bd(), clocks, &mut rcc.apb2);
5052
// If you are having trouble sending/receiving data to/from the
5153
// HC-05 bluetooth module, try this configuration instead:
5254
// Serial::usart1(dp.USART1, (tx, rx), 9600.bps(), clocks, &mut rcc.apb2);
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use stm32f3_discovery::stm32f3xx_hal as hal;
2+
3+
use cortex_m::peripheral::DWT;
4+
use hal::{
5+
rcc::Clocks,
6+
time::rate::Hertz,
7+
};
8+
9+
/// A monotonic nondecreasing timer. This is a resurrection of MonoTimer from
10+
/// the stm32f3xx-hal where it got removed after 0.6.1.
11+
#[derive(Clone, Copy)]
12+
pub struct MonoTimer {
13+
frequency: Hertz,
14+
}
15+
16+
// TODO: What about a refactoring to implement Clock from embedded-time?
17+
impl MonoTimer {
18+
/// Creates a new `Monotonic` timer
19+
pub fn new(mut dwt: DWT, clocks: Clocks) -> Self {
20+
dwt.enable_cycle_counter();
21+
22+
// now the CYCCNT counter can't be stopped or resetted
23+
drop(dwt);
24+
25+
MonoTimer {
26+
frequency: clocks.hclk(),
27+
}
28+
}
29+
30+
/// Returns the frequency at which the monotonic timer is operating at
31+
pub fn frequency(self) -> Hertz {
32+
self.frequency
33+
}
34+
35+
/// Returns an `Instant` corresponding to "now"
36+
pub fn now(self) -> Instant {
37+
Instant {
38+
now: DWT::get_cycle_count(),
39+
}
40+
}
41+
}
42+
43+
/// A measurement of a monotonically nondecreasing clock
44+
#[derive(Clone, Copy)]
45+
pub struct Instant {
46+
now: u32,
47+
}
48+
49+
impl Instant {
50+
/// Ticks elapsed since the `Instant` was created
51+
pub fn elapsed(self) -> u32 {
52+
DWT::get_cycle_count().wrapping_sub(self.now)
53+
}
54+
}

src/11-usart/buffer-overrun.md

Lines changed: 3 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,7 @@
33
If you wrote your program like this:
44

55
``` rust
6-
#![no_main]
7-
#![no_std]
8-
9-
#[allow(unused_imports)]
10-
use aux11::{entry, iprint, iprintln};
11-
12-
#[entry]
13-
fn main() -> ! {
14-
let (usart1, mono_timer, itm) = aux11::init();
15-
16-
// Send a string
17-
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
18-
usart1
19-
.tdr
20-
.write(|w| unsafe { w.tdr().bits(u16::from(*byte)) });
21-
}
22-
23-
loop {}
24-
}
6+
{{#include examples/buffer-overrun.rs}}
257
```
268

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

6244
``` rust
63-
#![deny(unsafe_code)]
64-
#![no_main]
65-
#![no_std]
66-
67-
#[allow(unused_imports)]
68-
use aux11::{entry, iprint, iprintln};
69-
70-
#[entry]
71-
fn main() -> ! {
72-
let (usart1, mono_timer, mut itm) = aux11::init();
73-
74-
let instant = mono_timer.now();
75-
// Send a string
76-
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
77-
usart1.tdr.write(|w| w.tdr().bits(u16::from(*byte)));
78-
}
79-
let elapsed = instant.elapsed(); // in ticks
80-
81-
iprintln!(
82-
&mut itm.stim[0],
83-
"`for` loop took {} ticks ({} us)",
84-
elapsed,
85-
elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
86-
);
87-
88-
loop {}
89-
}
45+
{{#include examples/buffer-overrun-timed.rs}}
9046
```
9147

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

11167
``` rust
112-
#![no_main]
113-
#![no_std]
114-
115-
#[allow(unused_imports)]
116-
use aux11::{entry, iprint, iprintln};
117-
118-
#[entry]
119-
fn main() -> ! {
120-
let (usart1, mono_timer, mut itm) = aux11::init();
121-
122-
let instant = mono_timer.now();
123-
// Send a string
124-
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
125-
// wait until it's safe to write to TDR
126-
while usart1.isr.read().txe().bit_is_clear() {} // <- NEW!
127-
128-
usart1
129-
.tdr
130-
.write(|w| unsafe { w.tdr().bits(u16::from(*byte)) });
131-
}
132-
let elapsed = instant.elapsed(); // in ticks
133-
134-
iprintln!(
135-
&mut itm.stim[0],
136-
"`for` loop took {} ticks ({} us)",
137-
elapsed,
138-
elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
139-
);
140-
141-
loop {}
142-
}
68+
{{#include examples/buffer-overrun-txe.rs}}
14369
```
14470

14571
This time, running the program in debug or release mode should result in a complete string on the
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![deny(unsafe_code)]
2+
#![no_main]
3+
#![no_std]
4+
5+
#[allow(unused_imports)]
6+
use aux11::{entry, iprint, iprintln};
7+
8+
#[entry]
9+
fn main() -> ! {
10+
let (usart1, mono_timer, mut itm) = aux11::init();
11+
12+
let instant = mono_timer.now();
13+
// Send a string
14+
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
15+
usart1.tdr.write(|w| w.tdr().bits(u16::from(*byte)));
16+
}
17+
let elapsed = instant.elapsed(); // in ticks
18+
19+
iprintln!(
20+
&mut itm.stim[0],
21+
"`for` loop took {} ticks ({} us)",
22+
elapsed,
23+
elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
24+
);
25+
26+
loop {}
27+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
#[allow(unused_imports)]
5+
use aux11::{entry, iprint, iprintln};
6+
7+
#[entry]
8+
fn main() -> ! {
9+
let (usart1, mono_timer, mut itm) = aux11::init();
10+
11+
let instant = mono_timer.now();
12+
// Send a string
13+
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
14+
// wait until it's safe to write to TDR
15+
while usart1.isr.read().txe().bit_is_clear() {} // <- NEW!
16+
17+
usart1
18+
.tdr
19+
.write(|w| w.tdr().bits(u16::from(*byte)));
20+
}
21+
let elapsed = instant.elapsed(); // in ticks
22+
23+
iprintln!(
24+
&mut itm.stim[0],
25+
"`for` loop took {} ticks ({} us)",
26+
elapsed,
27+
elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
28+
);
29+
30+
loop {}
31+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
#[allow(unused_imports)]
5+
use aux11::{entry, iprint, iprintln};
6+
7+
#[entry]
8+
fn main() -> ! {
9+
let (usart1, _mono_timer, _itm) = aux11::init();
10+
11+
// Send a string
12+
for byte in b"The quick brown fox jumps over the lazy dog.".iter() {
13+
usart1
14+
.tdr
15+
.write(|w| w.tdr().bits(u16::from(*byte)));
16+
}
17+
18+
loop {}
19+
}

src/11-usart/examples/echo.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
#[allow(unused_imports)]
5+
use aux11::{entry, iprint, iprintln};
6+
use heapless::Vec;
7+
8+
#[entry]
9+
fn main() -> ! {
10+
let (usart1, _mono_timer, _itm) = aux11::init();
11+
12+
// A buffer with 32 bytes of capacity
13+
let mut buffer: Vec<u8, 32> = Vec::new();
14+
15+
loop {
16+
buffer.clear();
17+
18+
loop {
19+
while usart1.isr.read().rxne().bit_is_clear() {}
20+
let byte = usart1.rdr.read().rdr().bits() as u8;
21+
22+
if buffer.push(byte).is_err() {
23+
// buffer full
24+
for byte in b"error: buffer full\n\r" {
25+
while usart1.isr.read().txe().bit_is_clear() {}
26+
usart1
27+
.tdr
28+
.write(|w| w.tdr().bits(u16::from(*byte)));
29+
}
30+
31+
break;
32+
}
33+
34+
// Carriage return
35+
if byte == 13 {
36+
// Respond
37+
for byte in buffer.iter().rev().chain(&[b'\n', b'\r']) {
38+
while usart1.isr.read().txe().bit_is_clear() {}
39+
usart1
40+
.tdr
41+
.write(|w| w.tdr().bits(u16::from(*byte)));
42+
}
43+
44+
break;
45+
}
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)