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