Skip to content

Commit 157670a

Browse files
authored
Merge pull request #56 from Disasm/usb
Add USB driver and example
2 parents 1aed4b2 + 9cd0192 commit 157670a

File tree

5 files changed

+122
-30
lines changed

5 files changed

+122
-30
lines changed

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ rust:
55
- nightly
66
env:
77
- MCU=stm32l0x1
8-
- MCU=stm32l0x2
9-
- MCU=stm32l0x3
8+
- MCU=stm32l0x2 FEATURES=stm32-usbd
9+
- MCU=stm32l0x3 FEATURES=stm32-usbd
1010
matrix:
1111
allow_failures:
1212
- rust: nightly
@@ -47,4 +47,4 @@ matrix:
4747
before_script:
4848
- rustup target add thumbv6m-none-eabi
4949
script:
50-
- RUSTFLAGS="-D warnings" cargo build --release --examples --features="rt $MCU $PACKAGE"
50+
- RUSTFLAGS="-D warnings" cargo build --release --examples --features="rt $MCU $PACKAGE $FEATURES"

Cargo.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ repository = "https://github.com/stm32-rs/stm32l0xx-hal"
2424
version = "0.4.0"
2525

2626
[package.metadata.docs.rs]
27-
features = ["stm32l0x1", "rt"]
27+
features = ["stm32l0x2", "rt", "stm32-usbd"]
2828

2929
[dependencies]
3030
as-slice = "0.1.0"
@@ -35,6 +35,7 @@ cortex-m-semihosting = "0.3.2"
3535
void = { version = "1.0.2", default-features = false }
3636
cast = { version = "0.2.2", default-features = false }
3737
nb = "0.1.2"
38+
stm32-usbd = { version = "0.5.0", features = ["ram_access_2x16"], optional = true }
3839

3940
[dependencies.stm32l0]
4041
version = "0.8.0"
@@ -45,6 +46,8 @@ heapless = "0.5.0"
4546
panic-halt = "0.2.0"
4647
panic-semihosting = "0.5.1"
4748
cortex-m-rtfm = "0.4.3"
49+
usb-device = "0.2.3"
50+
usbd-serial = "0.1.0"
4851

4952
[features]
5053
# Miscellaneaous features
@@ -141,3 +144,7 @@ required-features = ["rt"]
141144
[[example]]
142145
name = "adc_pwm"
143146
required-features = ["stm32l0x1"]
147+
148+
[[example]]
149+
name = "usb_serial"
150+
required-features = ["rt", "stm32l0x2", "stm32-usbd"]

examples/usb_serial.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//! CDC-ACM serial port example using polling in a busy loop.
2+
#![no_std]
3+
#![no_main]
4+
5+
extern crate panic_semihosting;
6+
7+
use cortex_m_rt::entry;
8+
use stm32l0xx_hal::usb::{Peripheral, UsbBus};
9+
use stm32l0xx_hal::{pac, prelude::*, rcc, syscfg::SYSCFG};
10+
use usb_device::prelude::*;
11+
use usbd_serial::{SerialPort, USB_CLASS_CDC};
12+
13+
#[entry]
14+
fn main() -> ! {
15+
let dp = pac::Peripherals::take().unwrap();
16+
17+
let mut rcc = dp.RCC.freeze(rcc::Config::hsi16());
18+
let mut syscfg = SYSCFG::new(dp.SYSCFG_COMP, &mut rcc);
19+
rcc.enable_hsi48(&mut syscfg, dp.CRS);
20+
21+
let gpioa = dp.GPIOA.split(&mut rcc);
22+
23+
let usb = Peripheral {
24+
usb: dp.USB,
25+
pin_dm: gpioa.pa11,
26+
pin_dp: gpioa.pa12,
27+
};
28+
let usb_bus = UsbBus::new(usb);
29+
30+
let mut serial = SerialPort::new(&usb_bus);
31+
32+
let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
33+
.manufacturer("Fake company")
34+
.product("Serial port")
35+
.serial_number("TEST")
36+
.device_class(USB_CLASS_CDC)
37+
.build();
38+
39+
loop {
40+
if !usb_dev.poll(&mut [&mut serial]) {
41+
continue;
42+
}
43+
44+
let mut buf = [0u8; 64];
45+
46+
match serial.read(&mut buf) {
47+
Ok(count) if count > 0 => {
48+
// Echo back in upper case
49+
for c in buf[0..count].iter_mut() {
50+
if 0x61 <= *c && *c <= 0x7a {
51+
*c &= !0x20;
52+
}
53+
}
54+
55+
let mut write_offset = 0;
56+
while write_offset < count {
57+
match serial.write(&buf[write_offset..count]) {
58+
Ok(len) if len > 0 => {
59+
write_offset += len;
60+
}
61+
_ => {}
62+
}
63+
}
64+
}
65+
_ => {}
66+
}
67+
}
68+
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ pub mod spi;
4141
pub mod syscfg;
4242
pub mod time;
4343
pub mod timer;
44-
#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
44+
#[cfg(all(feature = "stm32-usbd", any(feature = "stm32l0x2", feature = "stm32l0x3")))]
4545
pub mod usb;
4646
pub mod watchdog;

src/usb.rs

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,56 @@
1-
//! Support code for working with the USB peripheral
1+
//! Interface to the USB peripheral
22
//!
3-
//! This module is different from the other peripheral APIs, in the sense that
4-
//! it isn't really a peripheral API, just some support code to make working
5-
//! with the USB peripheral possible. This is due to the existing STM32
6-
//! ecosystem support for USB.
3+
//! Requires the `stm32-usbd` feature.
74
//!
85
//! As USB seems to work mostly the same across all STM32 MCUs, there is a
9-
//! single crates that supports USB for these MCUs:
6+
//! single crate that supports USB for these MCUs:
107
//! [`stm32-usbd`](https://crates.io/crates/stm32-usbd)
118
//!
12-
//! Since `stm32-usbd` depends on the HAL libraries for each STM32 family it
13-
//! supports, we can't exactly depend on it to provide everything you need here.
14-
//! Instead, we just provide some code that takes care of the platform-specific
15-
//! bits, which you can call before using `stm32-usbd` for the rest.
9+
//! This module implements some bits needed for `stm32-usbd` to work and exports
10+
//! `UsbBus` from `stm32-usbd`.
1611
//!
1712
//! Please check out the USB examples in the `examples/` directory to see how it
1813
//! fits together.
1914
15+
use crate::stm32::{RCC, USB};
16+
use stm32_usbd::UsbPeripheral;
2017

21-
use crate::rcc::{
22-
HSI48,
23-
Rcc,
24-
};
18+
use crate::gpio::gpioa::{PA11, PA12};
19+
use crate::gpio::{Floating, Input};
20+
pub use stm32_usbd::UsbBus;
2521

22+
pub struct Peripheral {
23+
pub usb: USB,
24+
pub pin_dm: PA11<Input<Floating>>,
25+
pub pin_dp: PA12<Input<Floating>>,
26+
}
27+
28+
unsafe impl Sync for Peripheral {}
29+
30+
unsafe impl UsbPeripheral for Peripheral {
31+
const REGISTERS: *const () = USB::ptr() as *const ();
32+
const DP_PULL_UP_FEATURE: bool = true;
33+
const EP_MEMORY: *const () = 0x4000_6000 as _;
34+
const EP_MEMORY_SIZE: usize = 1024;
2635

27-
/// Initializes the USB peripheral
28-
///
29-
/// This method takes care of the platform-specific bits of the USB
30-
/// initialization. After calling this method, you need `stm32-usbd` to actually
31-
/// do anything useful with the USB peripheral.
32-
pub fn init(rcc: &mut Rcc, _: HSI48) {
33-
// Reset USB peripheral
34-
rcc.rb.apb1rstr.modify(|_, w| w.usbrst().set_bit());
35-
rcc.rb.apb1rstr.modify(|_, w| w.usbrst().clear_bit());
36+
fn enable() {
37+
let rcc = unsafe { (&*RCC::ptr()) };
3638

37-
// We don't need to enable the USB peripheral, as stm32-usbd takes care of
38-
// that.
39+
cortex_m::interrupt::free(|_| {
40+
// Enable USB peripheral
41+
rcc.apb1enr.modify(|_, w| w.usben().set_bit());
42+
43+
// Reset USB peripheral
44+
rcc.apb1rstr.modify(|_, w| w.usbrst().set_bit());
45+
rcc.apb1rstr.modify(|_, w| w.usbrst().clear_bit());
46+
});
47+
}
48+
49+
fn startup_delay() {
50+
// There is a chip specific startup delay. For STM32L0x2/x3 it's 1µs and this should wait for
51+
// at least that long.
52+
cortex_m::asm::delay(32);
53+
}
3954
}
55+
56+
pub type UsbBusType = UsbBus<Peripheral>;

0 commit comments

Comments
 (0)