diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index efc8cc9..de6553c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,9 +8,7 @@ on: jobs: - # Ensure Rust code formatting is consistent across all source code - # - # This checks the main library, and all examples. + # Ensure Rust code formatting is consistent across all source code. format: runs-on: ubuntu-latest steps: @@ -21,11 +19,6 @@ jobs: with: command: fmt args: --verbose --all -- --check - - name: Check examples/teensy4 formatting - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --manifest-path examples/teensy4/Cargo.toml --verbose --all -- --check # For each chip, build and lint the main library clippy: @@ -56,46 +49,6 @@ jobs: command: test args: --verbose - # Build & lint the teensy4 examples - teensy4-clippy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - components: clippy - target: thumbv7em-none-eabihf - override: true - profile: minimal - - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --manifest-path examples/teensy4/Cargo.toml --verbose --target thumbv7em-none-eabihf -- -D warnings - name: Lint the teensy4 examples - - # Ensure that the Teensy 4 examples build across all hosts - teensy4-xplat: - strategy: - matrix: - host: [ macos-latest, ubuntu-latest, windows-latest ] - runs-on: ${{ matrix.host }} - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - target: thumbv7em-none-eabihf - override: true - - name: Build examples/teensy4 for ${{ matrix.os }} - uses: actions-rs/cargo@v1 - env: - RUSTFLAGS: -C link-arg=-Tt4link.x - with: - command: build - args: --manifest-path examples/teensy4/Cargo.toml --verbose --target thumbv7em-none-eabihf - # Make sure documentation builds, and doclinks are valid doc: env: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f244c92..55cddec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,35 +34,20 @@ examples. These tests run on your host system. To **debug** the library, enable the internal `__log` feature. The feature enables the library's internal [`log`](https://crates.io/crates/log) hooks. -Then, initialize your logger of choice in your program. See the Teensy 4 -examples to see how you might use a UART logger to debug your program. You may -also need to configure the maximum log level as a feature on the `log` crate. +Then, initialize your logger of choice in your program. You may also need to +configure the maximum log level as a feature on the `log` crate. -To test on **hardware**, either +To test on **hardware**, refer to the hardware examples maintained in the +[imxrt-hal project](https://github.com/imxrt-rs/imxrt-hal). Those examples +work on multiple development boards. We welcome new USB example contributions +there. If the imxrt-hal project does not support your development board, open +an issue in the imxrt-hal issue tracker. -- use an existing example package, or -- contribute a new example package for your system +If you're testing imxrt-usbd changes with the imxrt-hal examples, you'll need +a way to integrate your patches into that project's build. [Consider using +patches to override dependencies][patch]. -To **test `usb-device` compatibility**, use [the `usb-device` test class][test-class] -program in each example. - -1. Build and flash the `test_class` example onto your hardware. See your - example's documentation for build and flash instructions. Keep your board - connected to your host. -2. Clone and enter [the `usb-device` repository][usb-device-repo] - - ``` - git clone https://github.com/mvirkkunen/usb-device.git && cd usb-device - ``` -3. Run `cargo test --features=test-class-high-speed` in the `usb-device` directory. - -[test-class]: https://docs.rs/usb-device/0.2.7/usb_device/test_class/index.html -[usb-device-repo]: https://github.com/mvirkkunen/usb-device - -By default, examples build a high-speed USB device. To force a low / full speed -device, disable the example's default features. If you're testing a low / full -speed device with the `test_class`, remove the `--features=test-class-high-speed` -in step 3, above, so that the test evaluates a low / full speed test class. +[patch]: https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html For **design** information, see the API docs. Most modules include a high-level blurb that talks about what's going on. There are also public-facing design diff --git a/Cargo.toml b/Cargo.toml index 581335f..1a6212c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ USB driver for NXP iMX RT processors """ exclude = [ ".github/*", - "examples/*", ".gitignore", ] @@ -34,11 +33,6 @@ __log = ["log"] [package.metadata.docs.rs] default-target = "thumbv7em-none-eabihf" -[workspace] -members = [ - "examples/teensy4" -] - [workspace.package] edition = "2021" diff --git a/README.md b/README.md index 09dbc4f..e3ff286 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ embedded Rust program. It should support all i.MX RT microcontrollers. [`usb-device`]: https://crates.io/crates/usb-device See the API docs for usage, features, and examples. To try examples on actual -hardware, see the [`examples` directory](./examples). +hardware, see the [imxrt-hal examples](https://github.com/imxrt-rs/imxrt-hal). License diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index ffe1d25..0000000 --- a/examples/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# imxrt-usbd examples - -The examples in this directory run on hardware. They demonstrate basic features -of the imxrt-usbd. See each directory's documentation for build and flashing -instructions. diff --git a/examples/teensy4/.cargo/config.toml b/examples/teensy4/.cargo/config.toml deleted file mode 100644 index daa996b..0000000 --- a/examples/teensy4/.cargo/config.toml +++ /dev/null @@ -1,7 +0,0 @@ -[build] -target = "thumbv7em-none-eabihf" - -[target.thumbv7em-none-eabihf] -rustflags = [ - "-C", "link-arg=-Tt4link.x", -] diff --git a/examples/teensy4/.gitignore b/examples/teensy4/.gitignore deleted file mode 100644 index 6e75cf1..0000000 --- a/examples/teensy4/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.hex -target/ \ No newline at end of file diff --git a/examples/teensy4/Cargo.toml b/examples/teensy4/Cargo.toml deleted file mode 100644 index cfc3046..0000000 --- a/examples/teensy4/Cargo.toml +++ /dev/null @@ -1,89 +0,0 @@ -[package] -name = "imxrt-usbd-examples-teensy4" -version = "0.1.0" -authors = ["Ian McIntyre "] -edition.workspace = true -publish = false # This is an example package - -[features] -default = ["high-speed"] -# If this is enabled, the usb_device tests need to be compiled with -# the 'test-class-high-speed' feature. Note that high-speed is -# enabled by default. -high-speed = ["usb-device/test-class-high-speed"] - -# The library we're demonstrating -[dependencies.imxrt-usbd] -path = "../../" -features = [ - # "__log" # Only for driver development and debugging -] - -# Supporting other hardware access, start-up -[dependencies.teensy4-bsp] -version = "0.2" -default-features = false # Disable the BSP's USB driver -features = ["rt"] - -# Runtime support -[dependencies.cortex-m-rt] -features = ["device"] -version = "0.6.13" - -# Simple panic handler -[dependencies.teensy4-panic] -version = "0.2" -default-features = false - -# USB device -[dependencies.usb-device] -version = "0.2" - -# USB CDC class -[dependencies.usbd-serial] -version = "0.1" - -# USB HID class -[dependencies.usbd-hid] -version = "0.5" - -# Logging over UART -[dependencies.imxrt-uart-log] -version = "0.2" - -# Logging configuration, and logging within the -# examples -[dependencies.log] -version = "0.4" -features = ["release_max_level_info"] - -[dependencies.cortex-m] -version = "0.7" - -[[bin]] -name = "configured" -path = "src/configured.rs" - -[[bin]] -name = "gpt" -path = "src/gpt.rs" - -[[bin]] -name = "mouse" -path = "src/mouse.rs" - -[[bin]] -name = "serial" -path = "src/serial.rs" - -[lib] -name = "support" -path = "src/support.rs" - -[[bin]] -name = "test_class" -path = "src/test_class.rs" - -[[bin]] -name = "usb_keypress" -path = "src/usb_keypress.rs" diff --git a/examples/teensy4/README.md b/examples/teensy4/README.md deleted file mode 100644 index 4830cce..0000000 --- a/examples/teensy4/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# imxrt-usbd examples for the Teensy 4 - -The programs in this package run on a Teensy 4 (4.0 and 4.1), and demonstrate -how to use `imxrt-usbd` on an embedded system. - -## Dependencies - -You'll need all of the dependencies for the `imxrt-usbd` project. See the -project documentation for more details. - -You'll also need - -- A capable `objcopy` for transforming Rust binaries into hex files. The -documentation and tooling in the guide uses the LLVM `objcopy` provided by -[`cargo binutils`]. Install [`cargo binutils`] if you want to precisely follow -this documentation. - -[`cargo binutils`]: https://github.com/rust-embedded/cargo-binutils - -- To download programs to your Teensy 4, you'll need either a build of -[`teensy_loader_cli`](https://github.com/PaulStoffregen/teensy_loader_cli), or -the [Teensy Loader Application](https://www.pjrc.com/teensy/loader.html). The -latter is available with the Teensyduino add-ons. - -## Building and running examples - -From this directory, use `cargo objcopy` to build a release binary, and output -a hex file: - -``` -cargo objcopy --bin serial --target thumbv7em-none-eabihf --release -- -O ihex main.hex -``` - -Flash the hex file to your Teensy 4! diff --git a/examples/teensy4/src/configured.rs b/examples/teensy4/src/configured.rs deleted file mode 100644 index 0a41a83..0000000 --- a/examples/teensy4/src/configured.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! The example demonstrates how a USB device can reached -//! the 'configured' state. Build the example, and run it -//! on your Teensy 4. You should observe -//! -//! - the LED turns on -//! - a USB device, product string "imxrt-usbd," connected to -//! your system -//! -//! This example also instruments lightweight logging on UART2, -//! pins 14 and 15. Use this example if you need to debug -//! driver initialization. - -#![no_std] -#![no_main] - -use usb_device::prelude::*; - -const UART_BAUD: u32 = 115_200; - -#[cortex_m_rt::entry] -fn main() -> ! { - let support::Peripherals { - mut led, mut ccm, .. - } = support::setup(core::time::Duration::from_millis(500), UART_BAUD); - - let (ccm, ccm_analog) = ccm.raw(); - support::ccm::initialize(ccm, ccm_analog); - - let bus_adapter = support::new_bus_adapter(); - - let bus = usb_device::bus::UsbBusAllocator::new(bus_adapter); - let mut device = UsbDeviceBuilder::new(&bus, UsbVidPid(0x5824, 0x27dd)) - .product("imxrt-usbd") - .max_packet_size_0(64) - .build(); - - loop { - support::poll_logger(); - if !device.poll(&mut []) { - continue; - } - let state = device.state(); - if state == usb_device::device::UsbDeviceState::Configured { - led.set(); - } - } -} diff --git a/examples/teensy4/src/gpt.rs b/examples/teensy4/src/gpt.rs deleted file mode 100644 index b221f2d..0000000 --- a/examples/teensy4/src/gpt.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! Demonstrates a USB GPT. -//! -//! This example doesn't perform any USB I/O. It simply toggles an LED on a configurable. -//! interval. - -#![no_std] -#![no_main] - -use hal::ral::interrupt; -use imxrt_usbd::gpt; -use support::hal; -use teensy4_bsp::t40; - -// -// Change these constants to test various -// GPT settings. -// - -/// How frequently the LED toggles (microseconds). -const LED_PERIOD_US: u32 = 500_000; - -// -// The GPT settings below should result in an example -// that appears unchanged. Vary these for quick smoke -// tests. -// - -/// The GPT instance we're using. -/// -/// This shouldn't matter. -const GPT_INSTANCE: gpt::Instance = gpt::Instance::Gpt1; -/// The GPT mode. -/// -/// If set to one-shot, the example will implement the behaviors -/// of repeat mode in software (call `reset()`). -const GPT_MODE: gpt::Mode = gpt::Mode::Repeat; -/// Use an interrupt (`true`) or polling (`false`). -const GPT_INTERRUPT: bool = true; - -#[cortex_m_rt::entry] -fn main() -> ! { - let hal::Peripherals { - iomuxc, mut ccm, .. - } = hal::Peripherals::take().unwrap(); - let pins = t40::into_pins(iomuxc); - let led = teensy4_bsp::configure_led(pins.p13); - - let (ccm, ccm_analog) = ccm.handle.raw(); - support::ccm::initialize(ccm, ccm_analog); - - let bus_adapter = support::new_bus_adapter(); - bus_adapter.gpt_mut(GPT_INSTANCE, |gpt| { - gpt.stop(); - gpt.clear_elapsed(); - gpt.set_interrupt_enabled(GPT_INTERRUPT); - gpt.set_mode(GPT_MODE); - gpt.set_load(LED_PERIOD_US); - gpt.reset(); - }); - - if GPT_INTERRUPT { - example_interrupt(led, bus_adapter) - } else { - example_polling(led, bus_adapter) - } -} - -/// The endless loop when interrupts are enabled. -fn example_interrupt(led: teensy4_bsp::LED, bus_adapter: imxrt_usbd::BusAdapter) -> ! { - static mut BUS_ADAPTER: Option = None; - static mut LED: Option = None; - - cortex_m::interrupt::free(|_| unsafe { - BUS_ADAPTER = Some(bus_adapter); - LED = Some(led); - cortex_m::peripheral::NVIC::unmask(interrupt::USB_OTG1); - }); - - #[cortex_m_rt::interrupt] - fn USB_OTG1() { - let bus_adapter = unsafe { BUS_ADAPTER.as_mut().unwrap() }; - let led = unsafe { LED.as_mut().unwrap() }; - - // Note: gpt_mut takes a critical section. - bus_adapter.gpt_mut(GPT_INSTANCE, |gpt| { - if !gpt.is_running() { - gpt.run(); - } - - if gpt.is_elapsed() { - gpt.clear_elapsed(); - led.toggle(); - - if GPT_MODE != gpt::Mode::Repeat { - gpt.reset(); - } - } - }); - } - - cortex_m::peripheral::NVIC::pend(interrupt::USB_OTG1); - loop { - cortex_m::asm::wfi() - } -} - -/// The endless loop when interrupts are disabled, and we're polling the -/// GPT timer for completion. -fn example_polling(mut led: teensy4_bsp::LED, bus_adapter: imxrt_usbd::BusAdapter) -> ! { - // Note: gpt_mut takes a critical section. - bus_adapter.gpt_mut(GPT_INSTANCE, |gpt| { - gpt.run(); - loop { - if gpt.is_elapsed() { - gpt.clear_elapsed(); - led.toggle(); - - if GPT_MODE != gpt::Mode::Repeat { - gpt.reset(); - } - } - } - }) -} diff --git a/examples/teensy4/src/mouse.rs b/examples/teensy4/src/mouse.rs deleted file mode 100644 index dd4aa62..0000000 --- a/examples/teensy4/src/mouse.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! Demonstrate a mouse (USB HID). -//! -//! Flash your Teensy 4 with this example. You should observe -//! your mouse slowly inching in one direction every time the -//! LED blinks. -//! -//! This example also supports debug logs over UART2, using pins -//! 14 and 15. - -#![no_std] -#![no_main] - -use usb_device::prelude::*; -use usbd_hid::descriptor::generator_prelude::*; - -const UART_BAUD: u32 = 115_200; -const BLINK_PERIOD: core::time::Duration = core::time::Duration::from_millis(500); - -#[cortex_m_rt::entry] -fn main() -> ! { - let support::Peripherals { - mut led, - mut gpt1, - mut ccm, - } = support::setup(BLINK_PERIOD, UART_BAUD); - - let (ccm, ccm_analog) = ccm.raw(); - support::ccm::initialize(ccm, ccm_analog); - - let bus_adapter = support::new_bus_adapter(); - let bus = usb_device::bus::UsbBusAllocator::new(bus_adapter); - - let mut hid = - usbd_hid::hid_class::HIDClass::new(&bus, usbd_hid::descriptor::MouseReport::desc(), 10); - let mut device = UsbDeviceBuilder::new(&bus, UsbVidPid(0x5824, 0x27dd)) - .product("imxrt-usbd") - .max_packet_size_0(64) - .build(); - - gpt1.set_enable(true); - loop { - support::poll_logger(); - if !device.poll(&mut [&mut hid]) { - continue; - } - let state = device.state(); - if state == usb_device::device::UsbDeviceState::Configured { - break; - } - } - - device.bus().configure(); - led.set(); - - loop { - support::time_elapse(&mut gpt1, || { - led.toggle(); - hid.push_input(&usbd_hid::descriptor::MouseReport { - x: 4, - y: 4, - buttons: 0, - pan: 0, - wheel: 0, - }) - .unwrap(); - }); - support::poll_logger(); - if !device.poll(&mut [&mut hid]) { - continue; - } - } -} diff --git a/examples/teensy4/src/serial.rs b/examples/teensy4/src/serial.rs deleted file mode 100644 index a7f3841..0000000 --- a/examples/teensy4/src/serial.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Demonstrate a USB serial device -//! -//! Flash your Teensy 4 with this example. Then, connect a serial -//! interface to the USB device. You should see all inputs echoed -//! back to you. -//! -//! This example also supports debug logs over UART2, using pins -//! 14 and 15. - -#![no_std] -#![no_main] - -use usb_device::prelude::*; - -const UART_BAUD: u32 = 115_200; -const BLINK_PERIOD: core::time::Duration = core::time::Duration::from_millis(500); - -#[cortex_m_rt::entry] -fn main() -> ! { - let support::Peripherals { - mut led, - mut gpt1, - mut ccm, - } = support::setup(BLINK_PERIOD, UART_BAUD); - - let (ccm, ccm_analog) = ccm.raw(); - support::ccm::initialize(ccm, ccm_analog); - - let bus_adapter = support::new_bus_adapter(); - let bus = usb_device::bus::UsbBusAllocator::new(bus_adapter); - - let mut serial = usbd_serial::SerialPort::new(&bus); - let mut device = UsbDeviceBuilder::new(&bus, UsbVidPid(0x5824, 0x27dd)) - .product("imxrt-usbd") - .device_class(usbd_serial::USB_CLASS_CDC) - .max_packet_size_0(64) - .build(); - - gpt1.set_enable(true); - loop { - support::poll_logger(); - if !device.poll(&mut [&mut serial]) { - continue; - } - let state = device.state(); - if state == usb_device::device::UsbDeviceState::Configured { - break; - } - } - - device.bus().configure(); - led.set(); - - loop { - support::time_elapse(&mut gpt1, || led.toggle()); - support::poll_logger(); - if !device.poll(&mut [&mut serial]) { - continue; - } - - let mut buf = [0u8; 64]; - - match serial.read(&mut buf[..]) { - Ok(count) => { - let s = core::str::from_utf8(&buf).unwrap(); - log::info!("{}", s); - serial.write(&buf[..count]).ok(); - } - Err(UsbError::WouldBlock) => log::warn!("WOULDBLOCK"), - Err(_err) => panic!(), - }; - } -} diff --git a/examples/teensy4/src/support.rs b/examples/teensy4/src/support.rs deleted file mode 100644 index e3d0ba9..0000000 --- a/examples/teensy4/src/support.rs +++ /dev/null @@ -1,211 +0,0 @@ -//! Support library (qualified as `support`) for all examples. - -#![no_std] - -pub use bsp::hal; -pub use hal::ral; -pub use teensy4_bsp as bsp; - -const SPEED: imxrt_usbd::Speed = { - #[cfg(feature = "high-speed")] - { - imxrt_usbd::Speed::High - } - #[cfg(not(feature = "high-speed"))] - { - imxrt_usbd::Speed::LowFull - } -}; - -/// Allocates a `BusAdapter` -/// -/// # Panics -/// -/// Panics if any of the `imxrt-ral` USB instances are already -/// taken. -pub fn new_bus_adapter() -> imxrt_usbd::BusAdapter { - // If we're here, we have exclusive access to ENDPOINT_MEMORY - static EP_MEMORY: imxrt_usbd::EndpointMemory<4096> = imxrt_usbd::EndpointMemory::new(); - static EP_STATE: imxrt_usbd::EndpointState = imxrt_usbd::EndpointState::max_endpoints(); - - imxrt_usbd::BusAdapter::with_speed(UsbPeripherals::usb1(), &EP_MEMORY, &EP_STATE, SPEED) -} - -#[panic_handler] -fn panic(info: &core::panic::PanicInfo) -> ! { - log::error!("{}", info); - for _ in 0..10_000 { - imxrt_uart_log::dma::poll(); - } - teensy4_panic::sos() -} - -// -// Keep in sync with the imxrt_usbd::Peripherals example! -// - -struct UsbPeripherals { - usb: ral::usb::Instance, - phy: ral::usbphy::Instance, - _nc: ral::usbnc::Instance, - _analog: ral::usb_analog::Instance, -} - -impl UsbPeripherals { - /// Panics if the instances are already taken - fn usb1() -> UsbPeripherals { - Self { - usb: ral::usb::USB1::take().unwrap(), - phy: ral::usbphy::USBPHY1::take().unwrap(), - _nc: ral::usbnc::USBNC1::take().unwrap(), - _analog: ral::usb_analog::USB_ANALOG::take().unwrap(), - } - } -} - -unsafe impl imxrt_usbd::Peripherals for UsbPeripherals { - fn usb(&self) -> *const () { - let rb: &ral::usb::RegisterBlock = &self.usb; - (rb as *const ral::usb::RegisterBlock).cast() - } - fn usbphy(&self) -> *const () { - let rb: &ral::usbphy::RegisterBlock = &self.phy; - (rb as *const ral::usbphy::RegisterBlock).cast() - } -} - -pub mod ccm { - use super::ral; - - /// Initialize CCM clocks for USB1 - pub fn initialize(ccm: &ral::ccm::Instance, ccm_analog: &ral::ccm_analog::Instance) { - // Enable the PLL... - loop { - if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, ENABLE == 0) { - ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_USB1_SET, ENABLE: 1); - continue; - } - if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, POWER == 0) { - ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_USB1_SET, POWER: 1); - continue; - } - if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, LOCK == 0) { - continue; - } - if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, BYPASS == 1) { - ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_USB1_CLR, BYPASS: 1); - continue; - } - if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, EN_USB_CLKS == 0) { - ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_USB1_SET, EN_USB_CLKS: 1); - continue; - } - break; - } - - // Enable the clock gates... - ral::modify_reg!(ral::ccm, ccm, CCGR6, CG0: 0b11); - } -} - -/// Extra peripherals to support the examples. -pub struct Peripherals { - /// The LED on pin 13. - pub led: bsp::LED, - /// A separate timer. - /// - /// The time is **disabled** when it's - /// returned from `setup()`. - pub gpt1: hal::gpt::GPT, - /// The CCM handle for USB clocking. - pub ccm: hal::ccm::Handle, -} - -/// Drive the logging implementation. -pub fn poll_logger() { - imxrt_uart_log::dma::poll(); -} - -/// Required for proper function of `time_elapse`. -const GPT_OCR: hal::gpt::OutputCompareRegister = hal::gpt::OutputCompareRegister::One; - -/// Set up other system functions that support these examples. -/// -/// The `duration` affects the GPT period. The `logging_baud` -/// affects the UART baud. -/// -/// See the implementation to understand what peripherals are -/// taken, and how the system is configured. Note that you may -/// be responsible for polling the logging implementation. -/// -/// # Panics -/// -/// Panics if any of the HAL or BSP peripherals are already taken, -/// or if the logging system fails to initialize. -pub fn setup(duration: core::time::Duration, logging_baud: u32) -> Peripherals { - let hal::Peripherals { - iomuxc, - mut ccm, - dma, - uart, - mut dcdc, - gpt1, - .. - } = hal::Peripherals::take().unwrap(); - let pins = bsp::t40::into_pins(iomuxc); - let led = bsp::configure_led(pins.p13); - - // Set the ARM core to run at 600MHz. IPG clock runs at 25% - // of that speed. - let (_, ipg_hz) = ccm - .pll1 - .set_arm_clock(hal::ccm::PLL1::ARM_HZ, &mut ccm.handle, &mut dcdc); - - // 150MHz / 3 = 50MHz for PERCLK. - let mut cfg = ccm.perclk.configure( - &mut ccm.handle, - hal::ccm::perclk::PODF::DIVIDE_3, - hal::ccm::perclk::CLKSEL::IPG(ipg_hz), - ); - - // GPT runs on PERCLK. - let mut gpt1 = gpt1.clock(&mut cfg); - gpt1.set_wait_mode_enable(true); - // Once OCR1 compares, reset the counter. - gpt1.set_mode(hal::gpt::Mode::Reset); - - gpt1.set_output_compare_duration(GPT_OCR, duration); - - // DMA initialization (for logging) - let mut dma_channels = dma.clock(&mut ccm.handle); - let mut channel = dma_channels[7].take().unwrap(); - channel.set_interrupt_on_completion(false); // We'll poll the logger ourselves... - - // - // UART initialization (for logging) - // - let uarts = uart.clock( - &mut ccm.handle, - hal::ccm::uart::ClockSelect::OSC, - hal::ccm::uart::PrescalarSelect::DIVIDE_1, - ); - let uart = uarts.uart2.init(pins.p14, pins.p15, logging_baud).unwrap(); - - let (tx, _) = uart.split(); - imxrt_uart_log::dma::init(tx, channel, Default::default()).unwrap(); - - Peripherals { - led, - gpt1, - ccm: ccm.handle, - } -} - -/// Once the GPT has elapsed, invoke `func`. -pub fn time_elapse(gpt: &mut hal::gpt::GPT, func: impl FnOnce()) { - let mut status = gpt.output_compare_status(GPT_OCR); - if status.is_set() { - status.clear(); - func(); - } -} diff --git a/examples/teensy4/src/test_class.rs b/examples/teensy4/src/test_class.rs deleted file mode 100644 index 0a57ebf..0000000 --- a/examples/teensy4/src/test_class.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! usb-device test -//! -//! This example turns the Teensy 4 into a USB device that can be tested -//! from the usb-device host-side test framework. See the usb-device -//! documentation for more information on the test, and see the CONTRIBUTING -//! guide for how to use the test framework. -//! -//! This example also shows how you may use an ISR to poll your USB device. - -#![no_std] -#![no_main] - -use support::hal; - -const UART_BAUD: u32 = 115_200; -const TESTING_BLINK_PERIOD: core::time::Duration = core::time::Duration::from_millis(200); - -#[cortex_m_rt::entry] -fn main() -> ! { - let support::Peripherals { - mut led, - mut gpt1, - mut ccm, - } = support::setup(TESTING_BLINK_PERIOD, UART_BAUD); - - let (ccm, ccm_analog) = ccm.raw(); - support::ccm::initialize(ccm, ccm_analog); - - let bus_adapter = support::new_bus_adapter(); - bus_adapter.set_interrupts(true); - - unsafe { - let bus = usb_device::bus::UsbBusAllocator::new(bus_adapter); - BUS = Some(bus); - let bus = BUS.as_ref().unwrap(); - - let test_class = usb_device::test_class::TestClass::new(bus); - CLASS = Some(test_class); - let test_class = CLASS.as_ref().unwrap(); - - let device = test_class - .make_device_builder(bus) - .max_packet_size_0(64) - .build(); - - DEVICE = Some(device); - - core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst); - cortex_m::peripheral::NVIC::unmask(interrupt::USB_OTG1); - } - - gpt1.set_enable(true); - led.set(); - loop { - support::poll_logger(); - support::time_elapse(&mut gpt1, || led.toggle()); - cortex_m::asm::wfi(); - } -} - -type Bus = imxrt_usbd::BusAdapter; -type Class = usb_device::test_class::TestClass<'static, Bus>; -static mut CLASS: Option = None; -static mut BUS: Option> = None; -static mut DEVICE: Option> = None; - -use hal::ral::interrupt; - -#[cortex_m_rt::interrupt] -fn USB_OTG1() { - // Must track when the device transitions into / out of configuration, - // so that we can call configure... - static mut IS_CONFIGURED: bool = false; - - // Safety: we only unmask the interrupt once all three static mut variables - // are initialized. We're the only ones to use those variables after they're - // set. - let device = unsafe { DEVICE.as_mut().unwrap() }; - let class = unsafe { CLASS.as_mut().unwrap() }; - - if device.poll(&mut [class]) { - if device.state() == usb_device::device::UsbDeviceState::Configured { - if !*IS_CONFIGURED { - device.bus().configure(); - } - *IS_CONFIGURED = true; - - class.poll(); - } else { - *IS_CONFIGURED = false; - } - } -} diff --git a/examples/teensy4/src/usb_keypress.rs b/examples/teensy4/src/usb_keypress.rs deleted file mode 100644 index ff2da49..0000000 --- a/examples/teensy4/src/usb_keypress.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! Demonstrates how to send keystrokes via USB -//! This will spam your keyboard with eldritch slogans until you unplug it or press the reprogram button. - -#![no_std] -#![no_main] - -use teensy4_panic as _; - -use imxrt_usbd::BusAdapter; -use teensy4_bsp::LED; -use usb_device::device::UsbDevice; -use usb_device::prelude::{UsbDeviceBuilder, UsbVidPid}; -use usbd_hid::descriptor::KeyboardReport; -use usbd_hid::descriptor::SerializedDescriptor; -use usbd_hid::hid_class::HIDClass; - -#[cortex_m_rt::entry] -fn main() -> ! { - let support::Peripherals { - mut led, - mut gpt1, - mut ccm, - } = support::setup(core::time::Duration::from_millis(500), 115_200); - - let (ccm, ccm_analog) = ccm.raw(); - support::ccm::initialize(ccm, ccm_analog); - - let bus_adapter = support::new_bus_adapter(); - let bus = usb_device::bus::UsbBusAllocator::new(bus_adapter); - - let mut hid = usbd_hid::hid_class::HIDClass::new(&bus, KeyboardReport::desc(), 10); - let mut device = UsbDeviceBuilder::new(&bus, UsbVidPid(0x5824, 0x27dd)) - .product("imxrt-usbd") - .max_packet_size_0(64) - .build(); - - gpt1.set_enable(true); - loop { - support::poll_logger(); - if !device.poll(&mut [&mut hid]) { - continue; - } - let state = device.state(); - if state == usb_device::device::UsbDeviceState::Configured { - break; - } - } - - device.bus().configure(); - led.set(); - - keyboard_mission3(led, &mut hid, &mut device) -} - -// https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2 -fn keyboard_mission3( - mut led: LED, - hid: &mut HIDClass, - device: &mut UsbDevice, -) -> ! { - let mut msg = b"Ia! Ia! Cthulhu fhtagn! " - .iter() - // Repeate once we hit the end. - // This means we never return None. - .cycle() - // &u8 -> u8 - .copied() - // u8 -> KeyboardReport - .map(translate_char) - // Check the next keyboard report, - // and only pop if we could send - // the event. - .peekable(); - - loop { - let cmd = msg.peek().unwrap(); - - // this would be simpler if we could ask hid if it were full, or if we could give it a callback to invoke if it is not full. - let would_block = match hid.push_input(cmd) { - Ok(_x) => { - msg.next().unwrap(); - false - } - Err(_usb_error) => { - // probably buffer full, try again later - true - } - }; - - if would_block { - led.set(); - } else { - led.clear(); - } - - if !device.poll(&mut [hid]) { - continue; - } - } -} - -fn simple_kr(modifier: u8, keycodes: [u8; 6]) -> KeyboardReport { - KeyboardReport { - modifier, - reserved: 0, - leds: 0, - keycodes, - } -} - -fn translate_char(ch: u8) -> KeyboardReport { - match ch { - b'a'..=b'z' => { - let code = ch - b'a' + 4; - simple_kr(0, [code, 0, 0, 0, 0, 0]) - } - b'A'..=b'Z' => { - let code = ch - b'A' + 4; - simple_kr(2, [code, 0, 0, 0, 0, 0]) - } - b'!'..=b')' => { - let code = ch - b'!' + 0x1e; - simple_kr(2, [code, 0, 0, 0, 0, 0]) - } - b' ' => simple_kr(0, [0x2c, 0, 0, 0, 0, 0]), - // lots of stuff is missing, and I'm sure there are keyboard layouts that this is incorrect for. - _ => panic!("Unsupported character '{}'", ch), - } -}