Skip to content

Commit 24a8887

Browse files
authored
Merge pull request #355 from stm32-rs/serial_9b
Add 9-bits word length mode for serial (new)
2 parents 12594be + 0a8b2e2 commit 24a8887

File tree

4 files changed

+488
-75
lines changed

4 files changed

+488
-75
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- Added the ability to specify the word size (8 or 9 bits) for `Serial` (USART). When using parity, the parity bit is included in the number of bits of the word.
13+
- `blocking::serial::Write` for `Tx` and `Serial`. `core::fmt::Write` for `Serial`
1214
- `Instance` for Timer's, rtic-monotonic fugit impl
1315
- Serial can now be reconfigured, allowing to change e.g. the baud rate after initialisation.
1416

@@ -58,6 +60,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
5860
- Fix SPI3 alternate function remapping
5961
- Do not enable UART DMA flags unconditionally
6062
- Fix flash erase verification always failing
63+
- Fix invalid 8-bit access to USART registers.
6164

6265
### Changed
6366

examples/serial_9bits.rs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//! Testing 9 bits USART word length mode.
2+
//!
3+
//! This example demonstrates the use of the MSB bit (bit 8) to mark the beginning of a packet.
4+
//! The first byte of the packet contains the address of the slave device.
5+
//! The second byte of the packet contains the length of the message.
6+
//! The remaining bytes of the packet contain the message itself.
7+
8+
//#![deny(unsafe_code)]
9+
#![no_main]
10+
#![no_std]
11+
12+
use cortex_m_rt::entry;
13+
use nb::block;
14+
use panic_halt as _;
15+
use stm32f1xx_hal::{
16+
pac,
17+
prelude::*,
18+
serial::{Config, Rx3_16, Serial, Tx3_16},
19+
};
20+
21+
// The address of the slave device.
22+
const SLAVE_ADDR: u8 = 123;
23+
24+
// Maximum possible message length.
25+
const MSG_MAX_LEN: usize = u8::MAX as usize;
26+
27+
// Receives a message addressed to the slave device. Returns the size of the received message.
28+
fn receive_msg(serial_rx: &mut Rx3_16, buf: &mut [u8; MSG_MAX_LEN]) -> usize {
29+
enum RxPhase {
30+
Start,
31+
Length,
32+
Data { len: usize, idx: usize },
33+
}
34+
35+
let mut rx_phase = RxPhase::Start;
36+
37+
loop {
38+
// Read the word that was just sent. Blocks until the read is complete.
39+
let received = block!(serial_rx.read()).unwrap();
40+
41+
// If the beginning of the packet.
42+
if (received & 0x100) != 0 {
43+
rx_phase = if received as u8 == SLAVE_ADDR {
44+
RxPhase::Length
45+
} else {
46+
RxPhase::Start
47+
}
48+
} else {
49+
match rx_phase {
50+
RxPhase::Start => {}
51+
52+
RxPhase::Length => {
53+
if received == 0 {
54+
return 0;
55+
}
56+
rx_phase = RxPhase::Data {
57+
len: received as usize,
58+
idx: 0,
59+
};
60+
}
61+
62+
RxPhase::Data { len, ref mut idx } => {
63+
buf[*idx] = received as u8;
64+
*idx += 1;
65+
if *idx == len {
66+
return len;
67+
}
68+
}
69+
}
70+
}
71+
}
72+
}
73+
74+
// Send message.
75+
fn send_msg(mut serial_tx: Tx3_16, msg: &[u8]) -> Tx3_16 {
76+
// Send address.
77+
block!(serial_tx.write(SLAVE_ADDR as u16 | 0x100)).ok();
78+
79+
// Switching from u16 to u8 data.
80+
let mut serial_tx = serial_tx.with_u8_data();
81+
82+
// Send message len.
83+
assert!(msg.len() <= MSG_MAX_LEN);
84+
block!(serial_tx.write(msg.len() as u8)).ok();
85+
86+
// Send message.
87+
for &b in msg {
88+
block!(serial_tx.write(b)).ok();
89+
}
90+
91+
// Switching back from u8 to u16 data.
92+
serial_tx.with_u16_data()
93+
}
94+
95+
#[entry]
96+
fn main() -> ! {
97+
// Get access to the device specific peripherals from the peripheral access crate.
98+
let p = pac::Peripherals::take().unwrap();
99+
100+
// Take ownership over the raw flash and rcc devices and convert them into the corresponding
101+
// HAL structs.
102+
let mut flash = p.FLASH.constrain();
103+
let rcc = p.RCC.constrain();
104+
105+
// Freeze the configuration of all the clocks in the system and store the frozen frequencies in
106+
// `clocks`.
107+
let clocks = rcc.cfgr.freeze(&mut flash.acr);
108+
109+
// Prepare the alternate function I/O registers.
110+
let mut afio = p.AFIO.constrain();
111+
112+
// Prepare the GPIOB peripheral.
113+
let mut gpiob = p.GPIOB.split();
114+
115+
let tx_pin = gpiob.pb10.into_alternate_push_pull(&mut gpiob.crh);
116+
let rx_pin = gpiob.pb11;
117+
118+
// Set up the usart device. Taks ownership over the USART register and tx/rx pins. The rest of
119+
// the registers are used to enable and configure the device.
120+
let serial = Serial::usart3(
121+
p.USART3,
122+
(tx_pin, rx_pin),
123+
&mut afio.mapr,
124+
Config::default().baudrate(9600.bps()).wordlength_9(),
125+
clocks,
126+
)
127+
// Switching the 'Word' type parameter for the 'Read' and 'Write' traits from u8 to u16.
128+
.with_u16_data();
129+
130+
// Split the serial struct into a transmitting and a receiving part.
131+
let (mut serial_tx, mut serial_rx) = serial.split();
132+
133+
let mut buf = [0u8; MSG_MAX_LEN];
134+
135+
// loopback
136+
loop {
137+
// Receive message from master device.
138+
let received_msg_len = receive_msg(&mut serial_rx, &mut buf);
139+
// Send the received message back.
140+
serial_tx = send_msg(serial_tx, &buf[..received_msg_len]);
141+
}
142+
}

examples/serial_config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ fn main() -> ! {
6565
serial::Config::default()
6666
.baudrate(9600.bps())
6767
.stopbits(serial::StopBits::STOP2)
68+
.wordlength_9()
6869
.parity_odd(),
6970
clocks,
7071
);

0 commit comments

Comments
 (0)