diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index dae9f26a..b04d44b0 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -59,6 +59,8 @@ rand_core = "0.6.3" fixed = "1.10.0" embedded-storage = "0.2.0" cfg-if = "1.0.0" +nrf-usbd = "0.1.0" +usb-device = "0.2.8" nrf52805-pac = { version = "0.10.1", optional = true, features = [ "rt" ] } nrf52810-pac = { version = "0.10.1", optional = true, features = [ "rt" ] } diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 5a73b87e..95e3b3e7 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -73,6 +73,22 @@ pub(crate) use chip::pac; pub use chip::{peripherals, Peripherals}; +use nrf_usbd::{UsbPeripheral, Usbd}; +use usb_device::bus::UsbBusAllocator; + +pub struct UsbBus; +unsafe impl UsbPeripheral for UsbBus { + const REGISTERS: *const () = pac::USBD::ptr() as *const (); +} + +impl UsbBus { + pub fn new() -> UsbBusAllocator> { + Usbd::new(UsbBus) + } +} + +unsafe impl embassy_hal_common::usb::USBInterrupt for interrupt::USBD {} + pub mod interrupt { pub use crate::chip::irqs::*; pub use cortex_m::interrupt::{CriticalSection, Mutex}; diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index 5c58541a..646ba496 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml @@ -9,6 +9,7 @@ version = "0.1.0" embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } +embassy-hal-common = { version = "0.1.0", path = "../../embassy-hal-common" } defmt = "0.3" defmt-rtt = "0.3" @@ -20,3 +21,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } rand = { version = "0.8.4", default-features = false } embedded-storage = "0.2.0" + +usb-device = "0.2" +usbd-serial = "0.1.1" +nrf-usbd = "0.1.0" diff --git a/examples/nrf/src/bin/usb_uart.rs b/examples/nrf/src/bin/usb_uart.rs new file mode 100644 index 00000000..b81fd5ee --- /dev/null +++ b/examples/nrf/src/bin/usb_uart.rs @@ -0,0 +1,94 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; + +use defmt::{info, unwrap}; +use defmt_rtt as _; +use embassy::interrupt::InterruptExt; +use futures::future::{select, Either}; +use futures::pin_mut; +// global logger +use panic_probe as _; // print out panic messages + +use embassy::executor::Spawner; +use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; +use embassy::time::{Duration, Timer}; +use embassy_hal_common::usb::{State, Usb, UsbSerial}; +use embassy_nrf::UsbBus; +use embassy_nrf::{interrupt, Peripherals}; +use usb_device::device::{UsbDeviceBuilder, UsbVidPid}; + +#[embassy::main] +async fn main(_spawner: Spawner, _p: Peripherals) { + let mut tx_buffer = [0u8; 1024]; + let mut rx_buffer = [0u8; 640]; + + let usb_bus = UsbBus::new(); + + let serial = UsbSerial::new(&usb_bus, &mut rx_buffer, &mut tx_buffer); + + let device = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST") + .device_class(0x02) + .build(); + + let irq = interrupt::take!(USBD); + irq.set_priority(interrupt::Priority::P3); + + let mut state = State::new(); + + let usb = unsafe { Usb::new(&mut state, device, serial, irq) }; + pin_mut!(usb); + // usb.start(); + + let (mut read_interface, mut write_interface) = usb.as_ref().take_serial_0(); + + unwrap!(write_interface.write_all(b"\r\nSend something\r\n").await); + + info!("usb initialized!"); + + let mut buf = [0u8; 64]; + loop { + let mut n = 0; + let left = { + let recv_fut = async { + loop { + let byte = unwrap!(read_interface.read_byte().await); + unwrap!(write_interface.write_byte(byte).await); + buf[n] = byte; + + n += 1; + if byte == b'\n' || byte == b'\r' || n == buf.len() { + break; + } + } + }; + pin_mut!(recv_fut); + + let timeout = Timer::after(Duration::from_ticks(32768 * 10)); + + match select(recv_fut, timeout).await { + Either::Left(_) => true, + Either::Right(_) => false, + } + }; + + if left { + for c in buf[..n].iter_mut() { + if 0x61 <= *c && *c <= 0x7a { + *c &= !0x20; + } + } + unwrap!(write_interface.write_byte(b'\n').await); + unwrap!(write_interface.write_all(&buf[..n]).await); + unwrap!(write_interface.write_byte(b'\n').await); + } else { + unwrap!(write_interface.write_all(b"\r\nSend something\r\n").await); + } + } +}