Skip to content

Commit 84b6e6a

Browse files
committed
Fix half-complete-flag overrun condition for dma::CircBuffer and adjust serial_dma example to also test overrun detection capabilities
1 parent 78ca050 commit 84b6e6a

File tree

2 files changed

+70
-16
lines changed

2 files changed

+70
-16
lines changed

examples/serial_dma.rs

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,25 +59,66 @@ fn main() -> ! {
5959
);
6060
let (mut tx, rx) = serial.split();
6161

62-
let sent = b'X';
63-
64-
// The `block!` macro makes an operation block until it finishes
65-
// NOTE the error type is `!`
66-
67-
block!(tx.write(sent)).ok();
68-
69-
let buf = singleton!(: [u8; 8] = [0; 8]).unwrap();
70-
62+
let buf = singleton!(: [u8; 9] = [0; 9]).unwrap();
7163
let mut circ_buffer = rx.with_dma(channels.5).circ_read(buf);
64+
let mut rx_buf = [0; 9];
7265

73-
let mut rx_buf = [0; 8];
66+
// single byte send/receive
67+
send(&mut tx, b"x");
7468
let rx_len = circ_buffer.read(&mut rx_buf).unwrap();
69+
assert_eq!(rx_len, 1);
70+
assert_eq!(&rx_buf[..1], b"x");
71+
72+
// multi byte send/receive
73+
send(&mut tx, b"12345678");
74+
let rx_len = circ_buffer.read(&mut rx_buf).unwrap();
75+
assert_eq!(rx_len, 8);
76+
assert_eq!(&rx_buf[..8], b"12345678");
77+
78+
// Checking three types of overflow detection
79+
// 1. write pointer passes read pointer
80+
send(&mut tx, b"12345678"); // write-pointer -> 8
81+
let rx_len = circ_buffer.read(&mut rx_buf[..1]).unwrap(); // read-pointer -> 1
82+
assert_eq!(rx_len, 1);
83+
send(&mut tx, b"12"); // write-pointer -> 1 (catches up with read-pointer)
84+
let rx_res = circ_buffer.read(&mut rx_buf[..1]);
85+
if let Err(hal::dma::Error::Overrun) = rx_res {
86+
} else {
87+
panic!("An overrun should have been detected");
88+
}
7589

76-
let _received = &rx_buf[..rx_len];
90+
// 2. transfer complete flag set but it looks like the write-pointer did not pass 0
91+
send(&mut tx, b"123456789"); // write-pointer stays 1, transfer complete flag set
92+
send(&mut tx, b"1234"); // write-pointer -> 5
93+
let rx_res = circ_buffer.read(&mut rx_buf[..]);
94+
if let Err(hal::dma::Error::Overrun) = rx_res {
95+
} else {
96+
panic!("An overrun should have been detected");
97+
}
7798

78-
// let received = block!(rx.read()).unwrap();
99+
// 3a. half complete flag set but it looks like the write-ptr did not pass ceil(capacity/2) = 5
100+
send(&mut tx, b"123456789"); // write-pointer stays 5, all flags set
101+
send(&mut tx, b"12345678"); // write-pointer -> 4
102+
let rx_res = circ_buffer.read(&mut rx_buf[..]);
103+
if let Err(hal::dma::Error::Overrun) = rx_res {
104+
} else {
105+
panic!("An overrun should have been detected");
106+
}
79107

80-
// assert_eq!(received, sent);
108+
// 3b. check that the half complete flag is not yet set at write-pointer = floor(capacity/2) = 4
109+
send(&mut tx, b"1234"); // write-pointer -> 0
110+
circ_buffer.read(&mut rx_buf[..]).unwrap(); // read something to prevent overrun
111+
send(&mut tx, b"12345"); // write-pointer -> 4
112+
circ_buffer
113+
.read(&mut rx_buf[..])
114+
.expect("No overrun should be detected here");
115+
116+
// Undetectable overrun
117+
send(&mut tx, b"123456789");
118+
send(&mut tx, b"abcdefgh"); // overrun but it looks like only 8 bytes have been written
119+
let rx_len = circ_buffer.read(&mut rx_buf[..]).unwrap();
120+
assert_eq!(rx_len, 8);
121+
assert_eq!(&rx_buf[..8], b"abcdefgh");
81122

82123
// if all goes well you should reach this breakpoint
83124
asm::bkpt();
@@ -87,6 +128,19 @@ fn main() -> ! {
87128
}
88129
}
89130

131+
fn send(tx: &mut impl embedded_hal::serial::Write<u8>, data: &[u8]) {
132+
for byte in data {
133+
if let Err(_) = block!(tx.write(*byte)) {
134+
panic!("serial tx failed");
135+
}
136+
}
137+
138+
// waste some time so that the data will be received completely
139+
for i in 0..10000 {
140+
cortex_m::asm::nop();
141+
}
142+
}
143+
90144
#[exception]
91145
fn HardFault(ef: &ExceptionFrame) -> ! {
92146
panic!("{:#?}", ef);

src/dma.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -948,12 +948,12 @@ macro_rules! dma {
948948
// For checking the overrun conditions, it is important that we use the
949949
// old read_index so do not increment it yet but check overrun
950950
// conditions first.
951-
// TODO When is the half-complete flag written exactly? Especially for
952-
// odd buffer capacities.
951+
// For odd buffer sizes, the half-complete flag is set at
952+
// ceil(capacity/2).
953953
let overrun =
954954
self.passed_mark(self.write_previous, write_current, self.read_index, capacity)
955955
|| (transfer_complete_flag && !self.passed_mark(self.write_previous, write_current, 0, capacity))
956-
|| (half_complete_flag && !self.passed_mark(self.write_previous, write_current, capacity/2, capacity));
956+
|| (half_complete_flag && !self.passed_mark(self.write_previous, write_current, (capacity+1)/2, capacity));
957957
self.write_previous = write_current;
958958
if overrun {
959959
self.read_index = write_current;

0 commit comments

Comments
 (0)