Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

USB support #295

Merged
merged 39 commits into from
Jul 7, 2021
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0fbc358
wip
jonas-schievink Feb 20, 2020
86e84a8
errata: use volatile operations
japaric May 4, 2020
261eeae
4 byte align bulk/interrupt endpoint buffers
japaric May 4, 2020
faf0cb3
don't return PollResult::Data when there's no data
japaric May 7, 2020
2c3693b
EP0: shoehorn status stage
japaric May 7, 2020
b9e0eb4
make bulk reads works
japaric May 7, 2020
714b4f8
demand a Clocks token
japaric May 7, 2020
788ff0f
remove stray print statement
japaric May 7, 2020
b84300b
make the example compile again
japaric May 7, 2020
d1d70b4
remove patch
japaric May 11, 2020
7fb2998
rebase fixes
japaric May 11, 2020
5b216e2
Rebase #144, formerly #133 to pull in USB for nrf52480
wez Feb 14, 2021
1c87602
fixup CI for newly add usb test
wez Feb 14, 2021
f36a7e0
Reset shorts on SETUP to prevent spurious status stages
Disasm Feb 17, 2021
fa4011e
Introduce EP0State
Disasm Feb 17, 2021
c6d6aeb
Rewrite read/write logic
Disasm Feb 17, 2021
b938651
Add hack to detect interrupted IN transfers
Disasm Feb 17, 2021
1b3e38b
Inhibit SetAddress response
Disasm Feb 17, 2021
e78f3d0
Apply suggestions from code review
Disasm Feb 17, 2021
a7a7e84
Replace unsafe borrow with get() and set()
Disasm Feb 18, 2021
84ccc05
Issue a status stage when the transfer data is fully written
Disasm Feb 21, 2021
5d0c0eb
Don't prepare DMA transfer in read_control_setup
Disasm Feb 21, 2021
048e51d
Don't prepare DMA transfers in reset
Disasm Feb 21, 2021
7ad844a
Remove backing buffers
Disasm Feb 21, 2021
48b50e6
Track IN endpoint state
Disasm Feb 26, 2021
6ffd9e1
Remove redundant clear operation
Disasm Jun 4, 2021
922ced5
Check EPDATASTATUS inside write()
Disasm Jun 4, 2021
07b01ec
Merge remote-tracking branch 'upstream/master' into usb
Disasm Jun 4, 2021
4f33ab8
Cleanup
Disasm Jun 5, 2021
2e469df
Implement is_stalled()
Disasm Jun 5, 2021
f55b541
Add serial and test_class examples
Disasm Jun 5, 2021
d93fc5e
Fix warning
Disasm Jun 5, 2021
74b797e
Cleanup examples
Disasm Jun 12, 2021
9ce50b5
Fix USB demo
Jul 6, 2021
6ede424
Clean up Cargo features, support nRF52833
Jul 6, 2021
dbe0b5a
Add a 1ms delay to `force_reset`
Jul 6, 2021
844b782
Use nrf-usbd
jonas-schievink Jul 6, 2021
3ea49b7
Use crates.io version of nrf-usbd
jonas-schievink Jul 7, 2021
9185196
Address review comments
jonas-schievink Jul 7, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions examples/usb/.gdbinit
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# disable "are you sure you want to quit?"
define hook-quit
set confirm off
end

target remote :3333

# print demangled symbols by default
set print asm-demangle on

monitor arm semihosting enable
load
cont
17 changes: 17 additions & 0 deletions examples/usb/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "usb"
version = "0.1.0"
authors = ["Jonas Schievink <[email protected]>"]
edition = "2018"

[dependencies]
cortex-m-rt = "0.6.12"
panic-semihosting = "0.5.3"
nrf52840-pac = "0.9.0"
usb-device = "0.2.7"
usbd-serial = "0.1.0"

[dependencies.nrf52840-hal]
version = "0.12.0"
path = "../../nrf52840-hal"

63 changes: 63 additions & 0 deletions examples/usb/Embed.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
[default.probe]
# USB vendor ID
# usb_vid = "1337"
# USB product ID
# usb_pid = "1337"
# Serial number
# serial = "12345678"
# The protocol to be used for communicating with the target.
protocol = "Swd"
# The speed in kHz of the data link to the target.
# speed = 1337

[default.flashing]
# Whether or not the target should be flashed.
enabled = true
# Whether or not the target should be halted after reset.
# DEPRECATED, moved to reset section
halt_afterwards = false
# Whether or not bytes erased but not rewritten with data from the ELF
# should be restored with their contents before erasing.
restore_unwritten_bytes = false
# The path where an SVG of the assembled flash layout should be written to.
# flash_layout_output_path = "out.svg"

[default.reset]
# Whether or not the target should be reset.
# When flashing is enabled as well, the target will be reset after flashing.
enabled = true
# Whether or not the target should be halted after reset.
halt_afterwards = false

[default.general]
# The chip name of the chip to be debugged.
chip = "nRF52840"
# A list of chip descriptions to be loaded during runtime.
chip_descriptions = []
# The default log level to be used. Possible values are one of:
# "OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"
log_level = "WARN"

[default.rtt]
# Whether or not an RTTUI should be opened after flashing.
# This is exclusive and cannot be used with GDB at the moment.
enabled = true
# A list of channel associations to be displayed. If left empty, all channels are displayed.
channels = [
# { up = 0, down = 0, name = "name", format = "String" }
]
# The duration in ms for which the logger should retry to attach to RTT.
timeout = 3000
# Whether timestamps in the RTTUI are enabled
show_timestamps = true
# Whether to save rtt history buffer on exit.
log_enabled = false
# Where to save rtt history buffer relative to manifest path.
log_path = "./logs"

[default.gdb]
# Whether or not a GDB server should be opened after flashing.
# This is exclusive and cannot be used with RTT at the moment.
enabled = false
# The connection string in host:port format wher the GDB server will open a socket.
# gdb_connection_string
6 changes: 6 additions & 0 deletions examples/usb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# USB examples

This demo provides two binaries:

- `serial`: a USB serial "echo" example.
- `test_class`: exposes the test device from the `usb-device` crate.
59 changes: 59 additions & 0 deletions examples/usb/src/bin/serial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#![no_std]
#![no_main]

use panic_semihosting as _;

use cortex_m_rt::entry;
use nrf52840_hal::clocks::Clocks;
use nrf52840_hal::usbd::{UsbPeripheral, Usbd};
use nrf52840_pac::Peripherals;
use usb_device::device::{UsbDeviceBuilder, UsbVidPid};
use usbd_serial::{SerialPort, USB_CLASS_CDC};

#[entry]
fn main() -> ! {
let periph = Peripherals::take().unwrap();
let clocks = Clocks::new(periph.CLOCK);
let clocks = clocks.enable_ext_hfosc();

let usb_bus = Usbd::new(UsbPeripheral::new(periph.USBD, &clocks));
let mut serial = SerialPort::new(&usb_bus);

let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
.manufacturer("Fake company")
.product("Serial port")
.serial_number("TEST")
.device_class(USB_CLASS_CDC)
.max_packet_size_0(64) // (makes control transfers 8x faster)
.build();

loop {
if !usb_dev.poll(&mut [&mut serial]) {
continue;
}

let mut buf = [0u8; 64];

match serial.read(&mut buf) {
Ok(count) if count > 0 => {
// Echo back in upper case
for c in buf[0..count].iter_mut() {
if 0x61 <= *c && *c <= 0x7a {
*c &= !0x20;
}
}

let mut write_offset = 0;
while write_offset < count {
match serial.write(&buf[write_offset..count]) {
Ok(len) if len > 0 => {
write_offset += len;
}
_ => {}
}
}
}
_ => {}
}
}
}
29 changes: 29 additions & 0 deletions examples/usb/src/bin/test_class.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#![no_std]
#![no_main]

use panic_semihosting as _;

use cortex_m_rt::entry;
use nrf52840_hal::clocks::Clocks;
use nrf52840_hal::usbd::{UsbPeripheral, Usbd};
use nrf52840_pac::Peripherals;
use usb_device::test_class::TestClass;

#[entry]
fn main() -> ! {
let periph = Peripherals::take().unwrap();
let clocks = Clocks::new(periph.CLOCK);
let clocks = clocks.enable_ext_hfosc();

let usb_bus = Usbd::new(UsbPeripheral::new(periph.USBD, &clocks));

let mut test = TestClass::new(&usb_bus);

let mut usb_dev = { test.make_device(&usb_bus) };

loop {
if usb_dev.poll(&mut [&mut test]) {
test.poll();
}
}
}
8 changes: 6 additions & 2 deletions nrf-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ version = "0.9.0"
optional = true
version = "0.2.1"

[dependencies.nrf-usbd]
version = "0.1.0"
optional = true

[dependencies.embedded-hal]
features = ["unproven"]
version = "0.2.4"
Expand All @@ -73,6 +77,6 @@ doc = []
52810 = ["nrf52810-pac"]
52811 = ["nrf52811-pac"]
52832 = ["nrf52832-pac"]
52833 = ["nrf52833-pac"]
52840 = ["nrf52840-pac"]
52833 = ["nrf52833-pac", "nrf-usbd"]
52840 = ["nrf52840-pac", "nrf-usbd"]
9160 = ["nrf9160-pac"]
2 changes: 2 additions & 0 deletions nrf-hal-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ pub mod uart;
pub mod uarte;
#[cfg(not(feature = "9160"))]
pub mod uicr;
#[cfg(feature = "nrf-usbd")]
pub mod usbd;
pub mod wdt;

pub mod prelude {
Expand Down
21 changes: 21 additions & 0 deletions nrf-hal-common/src/usbd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use crate::clocks::ExternalOscillator;
use crate::pac::USBD;
use crate::Clocks;

pub use nrf_usbd::Usbd;

#[allow(dead_code)] // fields are unused and only hold ownership
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor nit: I think if you name the field _clocks the warning goes away

pub struct UsbPeripheral<'a> {
usbd: USBD,
clocks: &'a (),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&() is not ZST even if () is. Maybe use PhantomData<&'a ()>?

}

impl<'a> UsbPeripheral<'a> {
pub fn new<L, LSTAT>(usbd: USBD, _clocks: &'a Clocks<ExternalOscillator, L, LSTAT>) -> Self {
Self { usbd, clocks: &() }
}
}

unsafe impl<'a> nrf_usbd::UsbPeripheral for UsbPeripheral<'a> {
const REGISTERS: *const () = USBD::ptr() as *const _;
}
1 change: 1 addition & 0 deletions xtask/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub static EXAMPLES: &[(&str, &[&str])] = &[
("twim-demo", &[]),
("twis-demo", &[]),
("twis-dma-demo", &[]),
("usb", &[]),
("wdt-demo", &[]),
];

Expand Down