Skip to content

Commit 8e893ca

Browse files
olbackrichardeoin
authored andcommitted
add serial over usb with external phy using interrupts example
1 parent b7444b6 commit 8e893ca

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ required-features = ["rt", "usb_hs"]
210210
name = "usb_passthrough"
211211
required-features = ["usb_hs", "rm0399"]
212212

213+
[[example]]
214+
name = "usb_phy_serial_interrupt"
215+
required-features = ["rt", "usb_hs"]
216+
213217
[[example]]
214218
name = "rtc"
215219
required-features = ["rt", "rtc"]

examples/usb_phy_serial_interrupt.rs

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
//! CDC-ACM serial port example using an external phy and interrupts
2+
#![no_std]
3+
#![no_main]
4+
5+
use {
6+
core::cell::RefCell,
7+
cortex_m::interrupt::{free as interrupt_free, Mutex},
8+
stm32h7xx_hal::{
9+
hal::digital::v2::OutputPin,
10+
interrupt, pac,
11+
prelude::*,
12+
rcc::rec::UsbClkSel,
13+
stm32,
14+
usb_hs::{UsbBus, USB1_ULPI},
15+
},
16+
usb_device::prelude::*,
17+
usb_device::{bus::UsbBusAllocator, device::UsbDevice},
18+
usbd_serial::{DefaultBufferStore, SerialPort},
19+
};
20+
21+
#[macro_use]
22+
#[allow(unused)]
23+
mod utilities;
24+
25+
pub const VID: u16 = 0x2341;
26+
pub const PID: u16 = 0x025b;
27+
28+
pub static mut USB_MEMORY_1: [u32; 1024] = [0u32; 1024];
29+
pub static mut USB_BUS_ALLOCATOR: Option<UsbBusAllocator<UsbBus<USB1_ULPI>>> =
30+
None;
31+
pub static SERIAL_PORT: Mutex<
32+
RefCell<
33+
Option<
34+
SerialPort<
35+
UsbBus<USB1_ULPI>,
36+
DefaultBufferStore,
37+
DefaultBufferStore,
38+
>,
39+
>,
40+
>,
41+
> = Mutex::new(RefCell::new(None));
42+
pub static USB_DEVICE: Mutex<RefCell<Option<UsbDevice<UsbBus<USB1_ULPI>>>>> =
43+
Mutex::new(RefCell::new(None));
44+
45+
#[cortex_m_rt::entry]
46+
unsafe fn main() -> ! {
47+
let cp = cortex_m::Peripherals::take().unwrap();
48+
let dp = stm32::Peripherals::take().unwrap();
49+
50+
// Power
51+
let pwr = dp.PWR.constrain();
52+
let vos = example_power!(pwr).freeze();
53+
54+
// RCC
55+
let rcc = dp.RCC.constrain();
56+
let mut ccdr = rcc.sys_ck(80.mhz()).freeze(vos, &dp.SYSCFG);
57+
58+
// 48MHz CLOCK
59+
let _ = ccdr.clocks.hsi48_ck().expect("HSI48 must run");
60+
ccdr.peripheral.kernel_usb_clk_mux(UsbClkSel::HSI48);
61+
62+
// If your hardware uses the internal USB voltage regulator in ON mode, you
63+
// should uncomment this block.
64+
// unsafe {
65+
// let pwr = &*stm32::PWR::ptr();
66+
// pwr.cr3.modify(|_, w| w.usbregen().set_bit());
67+
// while pwr.cr3.read().usb33rdy().bit_is_clear() {}
68+
// }
69+
70+
// Get the delay provider.
71+
let mut delay = cp.SYST.delay(ccdr.clocks);
72+
73+
// GPIO
74+
let (
75+
gpioa,
76+
gpiob,
77+
gpioc,
78+
_gpiod,
79+
_gpioe,
80+
_gpiof,
81+
_gpiog,
82+
gpioh,
83+
gpioi,
84+
gpioj,
85+
_gpiok,
86+
) = {
87+
(
88+
dp.GPIOA.split(ccdr.peripheral.GPIOA),
89+
dp.GPIOB.split(ccdr.peripheral.GPIOB),
90+
dp.GPIOC.split(ccdr.peripheral.GPIOC),
91+
dp.GPIOD.split(ccdr.peripheral.GPIOD),
92+
dp.GPIOE.split(ccdr.peripheral.GPIOE),
93+
dp.GPIOF.split(ccdr.peripheral.GPIOF),
94+
dp.GPIOG.split(ccdr.peripheral.GPIOG),
95+
dp.GPIOH.split(ccdr.peripheral.GPIOH),
96+
dp.GPIOI.split(ccdr.peripheral.GPIOI),
97+
dp.GPIOJ.split(ccdr.peripheral.GPIOJ),
98+
dp.GPIOK.split(ccdr.peripheral.GPIOK),
99+
)
100+
};
101+
102+
// It is very likely that the board you're using has an external
103+
// clock source. Sometimes you have to enable them by yourself.
104+
// This is the case on the Arduino Portenta H7.
105+
let mut oscen = gpioh.ph1.into_push_pull_output();
106+
delay.delay_ms(10u32);
107+
oscen.set_high().unwrap();
108+
// Wait for osc to be stable
109+
delay.delay_ms(100u32);
110+
111+
// Set USB OTG pin floating
112+
let mut _usb_otg = gpioj.pj6.into_floating_input();
113+
114+
// Reset USB Phy
115+
let mut usb_phy_rst = gpioj.pj4.into_push_pull_output();
116+
usb_phy_rst.set_low().unwrap();
117+
delay.delay_ms(10u8);
118+
usb_phy_rst.set_high().unwrap();
119+
delay.delay_ms(10u8);
120+
121+
// Enable USB OTG_HS interrupt
122+
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OTG_HS);
123+
124+
let usb = USB1_ULPI::new(
125+
dp.OTG1_HS_GLOBAL,
126+
dp.OTG1_HS_DEVICE,
127+
dp.OTG1_HS_PWRCLK,
128+
gpioa.pa5.into_alternate_af10(),
129+
gpioi.pi11.into_alternate_af10(),
130+
gpioh.ph4.into_alternate_af10(),
131+
gpioc.pc0.into_alternate_af10(),
132+
gpioa.pa3.into_alternate_af10(),
133+
gpiob.pb0.into_alternate_af10(),
134+
gpiob.pb1.into_alternate_af10(),
135+
gpiob.pb10.into_alternate_af10(),
136+
gpiob.pb11.into_alternate_af10(),
137+
gpiob.pb12.into_alternate_af10(),
138+
gpiob.pb13.into_alternate_af10(),
139+
gpiob.pb5.into_alternate_af10(),
140+
ccdr.peripheral.USB1OTG,
141+
&ccdr.clocks,
142+
);
143+
144+
USB_BUS_ALLOCATOR = Some(UsbBus::new(usb, &mut USB_MEMORY_1));
145+
146+
let usb_serial =
147+
usbd_serial::SerialPort::new(USB_BUS_ALLOCATOR.as_ref().unwrap());
148+
149+
let usb_dev = UsbDeviceBuilder::new(
150+
USB_BUS_ALLOCATOR.as_ref().unwrap(),
151+
UsbVidPid(VID, PID),
152+
)
153+
.manufacturer("Fake company")
154+
.product("Serial port")
155+
.serial_number("TEST")
156+
.device_class(usbd_serial::USB_CLASS_CDC)
157+
.max_packet_size_0(64)
158+
.build();
159+
160+
interrupt_free(|cs| {
161+
USB_DEVICE.borrow(cs).replace(Some(usb_dev));
162+
SERIAL_PORT.borrow(cs).replace(Some(usb_serial));
163+
});
164+
165+
loop {
166+
cortex_m::asm::nop();
167+
}
168+
}
169+
170+
#[interrupt]
171+
fn OTG_HS() {
172+
interrupt_free(|cs| {
173+
if let (Some(port), Some(device)) = (
174+
SERIAL_PORT.borrow(cs).borrow_mut().as_mut(),
175+
USB_DEVICE.borrow(cs).borrow_mut().as_mut(),
176+
) {
177+
if device.poll(&mut [port]) {
178+
let mut buf = [0u8; 64];
179+
match port.read(&mut buf) {
180+
Ok(count) if count > 0 => {
181+
// Echo back in upper case
182+
for c in buf[0..count].iter_mut() {
183+
if 0x61 <= *c && *c <= 0x7a {
184+
*c &= !0x20;
185+
}
186+
}
187+
188+
let mut write_offset = 0;
189+
while write_offset < count {
190+
match port.write(&buf[write_offset..count]) {
191+
Ok(len) if len > 0 => {
192+
write_offset += len;
193+
}
194+
_ => {}
195+
}
196+
}
197+
}
198+
_ => {}
199+
}
200+
}
201+
}
202+
})
203+
}

0 commit comments

Comments
 (0)