Skip to content

Commit 663db13

Browse files
committed
Adds Half-Duplex capability to Serial.
1 parent 3533f78 commit 663db13

File tree

2 files changed

+118
-1
lines changed

2 files changed

+118
-1
lines changed

examples/serial_half_duplex.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//! Test the serial interface in Half-Duplex mode.
2+
//!
3+
//! This example requires you to hook-up a pullup resistor on the TX pin. RX pin is not used.
4+
//! Resistor value depends on the baurate and line caracteristics, 1KOhms works well in most cases.
5+
//! Half-Duplex mode internally connect TX to RX, meaning that bytes sent will also be received.
6+
#![deny(unsafe_code)]
7+
#![deny(warnings)]
8+
#![no_main]
9+
#![no_std]
10+
11+
extern crate cortex_m;
12+
#[macro_use(entry, exception)]
13+
extern crate cortex_m_rt as rt;
14+
#[macro_use(block)]
15+
extern crate nb;
16+
extern crate panic_semihosting;
17+
18+
extern crate stm32l4xx_hal as hal;
19+
// #[macro_use(block)]
20+
// extern crate nb;
21+
22+
use crate::hal::prelude::*;
23+
use crate::hal::serial::{Config, Serial};
24+
use crate::rt::ExceptionFrame;
25+
use cortex_m::asm;
26+
27+
#[entry]
28+
fn main() -> ! {
29+
let p = hal::stm32::Peripherals::take().unwrap();
30+
31+
let mut flash = p.FLASH.constrain();
32+
let mut rcc = p.RCC.constrain();
33+
let mut pwr = p.PWR.constrain(&mut rcc.apb1r1);
34+
35+
let mut gpioa = p.GPIOA.split(&mut rcc.ahb2);
36+
// let mut gpiob = p.GPIOB.split(&mut rcc.ahb2);
37+
38+
// clock configuration using the default settings (all clocks run at 8 MHz)
39+
// let clocks = rcc.cfgr.freeze(&mut flash.acr);
40+
// TRY this alternate clock configuration (clocks run at nearly the maximum frequency)
41+
let clocks = rcc
42+
.cfgr
43+
.sysclk(80.mhz())
44+
.pclk1(80.mhz())
45+
.pclk2(80.mhz())
46+
.freeze(&mut flash.acr, &mut pwr);
47+
48+
// The Serial API is highly generic
49+
// TRY the commented out, different pin configurations
50+
// let tx = gpioa.pa9.into_af7(&mut gpioa.moder, &mut gpioa.afrh).set_open_drain();
51+
let tx = gpioa
52+
.pa2
53+
.into_af7(&mut gpioa.moder, &mut gpioa.afrl)
54+
.set_open_drain();
55+
// let tx = gpiob.pb6.into_af7(&mut gpiob.moder, &mut gpiob.afrl).set_open_drain();
56+
57+
// TRY using a different USART peripheral here
58+
let serial = Serial::usart2(
59+
p.USART2,
60+
(tx,),
61+
Config::default().baudrate(9_600.bps()),
62+
clocks,
63+
&mut rcc.apb1r1,
64+
);
65+
let (mut tx, mut rx) = serial.split();
66+
67+
let sent = b'X';
68+
69+
// The `block!` macro makes an operation block until it finishes
70+
// NOTE the error type is `!`
71+
72+
block!(tx.write(sent)).ok();
73+
74+
let received = block!(rx.read()).unwrap();
75+
76+
assert_eq!(received, sent);
77+
78+
// if all goes well you should reach this breakpoint
79+
asm::bkpt();
80+
81+
loop {}
82+
}
83+
84+
#[exception]
85+
fn HardFault(ef: &ExceptionFrame) -> ! {
86+
panic!("{:#?}", ef);
87+
}

src/serial.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use stable_deref_trait::StableDeref;
1515
use crate::hal::serial::{self, Write};
1616

1717
use crate::dma::{dma1, CircBuffer, DMAFrame, FrameReader, FrameSender};
18-
use crate::gpio::{self, Alternate, Floating, Input};
18+
use crate::gpio::{self, Alternate, AlternateOD, Floating, Input};
1919
use crate::pac;
2020
use crate::rcc::{Clocks, APB1R1, APB2};
2121
use crate::time::{Bps, U32Ext};
@@ -289,6 +289,11 @@ macro_rules! hal {
289289
w.ovrdis().set_bit();
290290
}
291291

292+
// configure Half Duplex
293+
if PINS::HALF_DUPLEX {
294+
w.hdsel().set_bit();
295+
}
296+
292297
w
293298
});
294299

@@ -777,6 +782,9 @@ where
777782
/// Marks pins as being as being TX pins for the given USART instance
778783
pub trait TxPin<Instance>: private::SealedTx {}
779784

785+
/// Marks pins as being TX Half Duplex pins for the given USART instance
786+
pub trait TxHalfDuplexPin<Instance>: private::SealedTxHalfDuplex {}
787+
780788
/// Marks pins as being as being RX pins for the given USART instance
781789
pub trait RxPin<Instance>: private::SealedRx {}
782790

@@ -810,6 +818,13 @@ macro_rules! impl_pin_traits {
810818
gpio::$tx<Alternate<gpio::$af, Input<Floating>>> {}
811819
)*
812820

821+
$(
822+
impl private::SealedTxHalfDuplex for
823+
gpio::$tx<AlternateOD<gpio::$af, Input<Floating>>> {}
824+
impl TxHalfDuplexPin<pac::$instance> for
825+
gpio::$tx<AlternateOD<gpio::$af, Input<Floating>>> {}
826+
)*
827+
813828
$(
814829
impl private::SealedRx for
815830
gpio::$rx<Alternate<gpio::$af, Input<Floating>>> {}
@@ -901,6 +916,7 @@ impl_pin_traits! {
901916
pub trait Pins<USART> {
902917
const FLOWCTL: bool;
903918
const DEM: bool;
919+
const HALF_DUPLEX: bool;
904920
}
905921

906922
// No flow control, just Rx+Tx
@@ -911,6 +927,17 @@ where
911927
{
912928
const FLOWCTL: bool = false;
913929
const DEM: bool = false;
930+
const HALF_DUPLEX: bool = false;
931+
}
932+
933+
// No flow control Half_duplex, just Tx
934+
impl<Instance, Tx> Pins<Instance> for (Tx,)
935+
where
936+
Tx: TxHalfDuplexPin<Instance>,
937+
{
938+
const FLOWCTL: bool = false;
939+
const DEM: bool = false;
940+
const HALF_DUPLEX: bool = true;
914941
}
915942

916943
// Hardware flow control, Rx+Tx+Rts+Cts
@@ -923,6 +950,7 @@ where
923950
{
924951
const FLOWCTL: bool = true;
925952
const DEM: bool = false;
953+
const HALF_DUPLEX: bool = false;
926954
}
927955

928956
// DEM for RS485 mode
@@ -934,11 +962,13 @@ where
934962
{
935963
const FLOWCTL: bool = false;
936964
const DEM: bool = true;
965+
const HALF_DUPLEX: bool = false;
937966
}
938967

939968
/// Contains supertraits used to restrict which traits users can implement
940969
mod private {
941970
pub trait SealedTx {}
971+
pub trait SealedTxHalfDuplex {}
942972
pub trait SealedRx {}
943973
pub trait SealedRtsDe {}
944974
pub trait SealedCts {}

0 commit comments

Comments
 (0)