diff options
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/boot/application/nrf/build.rs | 3 | ||||
| -rw-r--r-- | examples/boot/application/nrf/src/bin/a.rs | 11 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_onewire.rs | 155 | ||||
| -rw-r--r-- | examples/rp23/src/bin/trng.rs | 64 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/eth_compliance_test.rs | 77 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/usb_serial.rs | 140 |
6 files changed, 450 insertions, 0 deletions
diff --git a/examples/boot/application/nrf/build.rs b/examples/boot/application/nrf/build.rs index cd1a264c4..e1da69328 100644 --- a/examples/boot/application/nrf/build.rs +++ b/examples/boot/application/nrf/build.rs | |||
| @@ -31,4 +31,7 @@ fn main() { | |||
| 31 | 31 | ||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); |
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); |
| 34 | if env::var("CARGO_FEATURE_DEFMT").is_ok() { | ||
| 35 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 36 | } | ||
| 34 | } | 37 | } |
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index 851a3d721..2c1d1a7bb 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs | |||
| @@ -2,6 +2,9 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![macro_use] | 3 | #![macro_use] |
| 4 | 4 | ||
| 5 | #[cfg(feature = "defmt")] | ||
| 6 | use defmt_rtt as _; | ||
| 7 | use embassy_boot::State; | ||
| 5 | use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; | 8 | use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; |
| 6 | use embassy_embedded_hal::adapter::BlockingAsync; | 9 | use embassy_embedded_hal::adapter::BlockingAsync; |
| 7 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
| @@ -22,6 +25,7 @@ async fn main(_spawner: Spawner) { | |||
| 22 | 25 | ||
| 23 | let mut button = Input::new(p.P0_11, Pull::Up); | 26 | let mut button = Input::new(p.P0_11, Pull::Up); |
| 24 | let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); | 27 | let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); |
| 28 | let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard); | ||
| 25 | 29 | ||
| 26 | //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); | 30 | //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); |
| 27 | //let mut button = Input::new(p.P1_02, Pull::Up); | 31 | //let mut button = Input::new(p.P1_02, Pull::Up); |
| @@ -53,6 +57,13 @@ async fn main(_spawner: Spawner) { | |||
| 53 | let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); | 57 | let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); |
| 54 | let mut magic = [0; 4]; | 58 | let mut magic = [0; 4]; |
| 55 | let mut updater = FirmwareUpdater::new(config, &mut magic); | 59 | let mut updater = FirmwareUpdater::new(config, &mut magic); |
| 60 | let state = updater.get_state().await.unwrap(); | ||
| 61 | if state == State::Revert { | ||
| 62 | led_reverted.set_low(); | ||
| 63 | } else { | ||
| 64 | led_reverted.set_high(); | ||
| 65 | } | ||
| 66 | |||
| 56 | loop { | 67 | loop { |
| 57 | led.set_low(); | 68 | led.set_low(); |
| 58 | button.wait_for_any_edge().await; | 69 | button.wait_for_any_edge().await; |
diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs new file mode 100644 index 000000000..5076101ec --- /dev/null +++ b/examples/rp/src/bin/pio_onewire.rs | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | //! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::bind_interrupts; | ||
| 8 | use embassy_rp::peripherals::PIO0; | ||
| 9 | use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 15 | }); | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async fn main(_spawner: Spawner) { | ||
| 19 | let p = embassy_rp::init(Default::default()); | ||
| 20 | let mut pio = Pio::new(p.PIO0, Irqs); | ||
| 21 | let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2); | ||
| 22 | |||
| 23 | loop { | ||
| 24 | sensor.start().await; // Start a new measurement | ||
| 25 | Timer::after_secs(1).await; // Allow 1s for the measurement to finish | ||
| 26 | match sensor.temperature().await { | ||
| 27 | Ok(temp) => info!("temp = {:?} deg C", temp), | ||
| 28 | _ => error!("sensor error"), | ||
| 29 | } | ||
| 30 | Timer::after_secs(1).await; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | /// DS18B20 temperature sensor driver | ||
| 35 | pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { | ||
| 36 | sm: StateMachine<'d, PIO, SM>, | ||
| 37 | } | ||
| 38 | |||
| 39 | impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { | ||
| 40 | /// Create a new instance the driver | ||
| 41 | pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self { | ||
| 42 | let prg = pio_proc::pio_asm!( | ||
| 43 | r#" | ||
| 44 | .wrap_target | ||
| 45 | again: | ||
| 46 | pull block | ||
| 47 | mov x, osr | ||
| 48 | jmp !x, read | ||
| 49 | write: | ||
| 50 | set pindirs, 1 | ||
| 51 | set pins, 0 | ||
| 52 | loop1: | ||
| 53 | jmp x--,loop1 | ||
| 54 | set pindirs, 0 [31] | ||
| 55 | wait 1 pin 0 [31] | ||
| 56 | pull block | ||
| 57 | mov x, osr | ||
| 58 | bytes1: | ||
| 59 | pull block | ||
| 60 | set y, 7 | ||
| 61 | set pindirs, 1 | ||
| 62 | bit1: | ||
| 63 | set pins, 0 [1] | ||
| 64 | out pins,1 [31] | ||
| 65 | set pins, 1 [20] | ||
| 66 | jmp y--,bit1 | ||
| 67 | jmp x--,bytes1 | ||
| 68 | set pindirs, 0 [31] | ||
| 69 | jmp again | ||
| 70 | read: | ||
| 71 | pull block | ||
| 72 | mov x, osr | ||
| 73 | bytes2: | ||
| 74 | set y, 7 | ||
| 75 | bit2: | ||
| 76 | set pindirs, 1 | ||
| 77 | set pins, 0 [1] | ||
| 78 | set pindirs, 0 [5] | ||
| 79 | in pins,1 [10] | ||
| 80 | jmp y--,bit2 | ||
| 81 | jmp x--,bytes2 | ||
| 82 | .wrap | ||
| 83 | "#, | ||
| 84 | ); | ||
| 85 | |||
| 86 | let pin = common.make_pio_pin(pin); | ||
| 87 | let mut cfg = Config::default(); | ||
| 88 | cfg.use_program(&common.load_program(&prg.program), &[]); | ||
| 89 | cfg.set_out_pins(&[&pin]); | ||
| 90 | cfg.set_in_pins(&[&pin]); | ||
| 91 | cfg.set_set_pins(&[&pin]); | ||
| 92 | cfg.shift_in = ShiftConfig { | ||
| 93 | auto_fill: true, | ||
| 94 | direction: ShiftDirection::Right, | ||
| 95 | threshold: 8, | ||
| 96 | }; | ||
| 97 | cfg.clock_divider = 255_u8.into(); | ||
| 98 | sm.set_config(&cfg); | ||
| 99 | sm.set_enable(true); | ||
| 100 | Self { sm } | ||
| 101 | } | ||
| 102 | |||
| 103 | /// Write bytes over the wire | ||
| 104 | async fn write_bytes(&mut self, bytes: &[u8]) { | ||
| 105 | self.sm.tx().wait_push(250).await; | ||
| 106 | self.sm.tx().wait_push(bytes.len() as u32 - 1).await; | ||
| 107 | for b in bytes { | ||
| 108 | self.sm.tx().wait_push(*b as u32).await; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Read bytes from the wire | ||
| 113 | async fn read_bytes(&mut self, bytes: &mut [u8]) { | ||
| 114 | self.sm.tx().wait_push(0).await; | ||
| 115 | self.sm.tx().wait_push(bytes.len() as u32 - 1).await; | ||
| 116 | for b in bytes.iter_mut() { | ||
| 117 | *b = (self.sm.rx().wait_pull().await >> 24) as u8; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | /// Calculate CRC8 of the data | ||
| 122 | fn crc8(data: &[u8]) -> u8 { | ||
| 123 | let mut temp; | ||
| 124 | let mut data_byte; | ||
| 125 | let mut crc = 0; | ||
| 126 | for b in data { | ||
| 127 | data_byte = *b; | ||
| 128 | for _ in 0..8 { | ||
| 129 | temp = (crc ^ data_byte) & 0x01; | ||
| 130 | crc >>= 1; | ||
| 131 | if temp != 0 { | ||
| 132 | crc ^= 0x8C; | ||
| 133 | } | ||
| 134 | data_byte >>= 1; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | crc | ||
| 138 | } | ||
| 139 | |||
| 140 | /// Start a new measurement. Allow at least 1000ms before getting `temperature`. | ||
| 141 | pub async fn start(&mut self) { | ||
| 142 | self.write_bytes(&[0xCC, 0x44]).await; | ||
| 143 | } | ||
| 144 | |||
| 145 | /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. | ||
| 146 | pub async fn temperature(&mut self) -> Result<f32, ()> { | ||
| 147 | self.write_bytes(&[0xCC, 0xBE]).await; | ||
| 148 | let mut data = [0; 9]; | ||
| 149 | self.read_bytes(&mut data).await; | ||
| 150 | match Self::crc8(&data) == 0 { | ||
| 151 | true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), | ||
| 152 | false => Err(()), | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
diff --git a/examples/rp23/src/bin/trng.rs b/examples/rp23/src/bin/trng.rs new file mode 100644 index 000000000..e146baa2e --- /dev/null +++ b/examples/rp23/src/bin/trng.rs | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | //! This example shows TRNG usage | ||
| 2 | |||
| 3 | #![no_std] | ||
| 4 | #![no_main] | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::bind_interrupts; | ||
| 9 | use embassy_rp::block::ImageDef; | ||
| 10 | use embassy_rp::gpio::{Level, Output}; | ||
| 11 | use embassy_rp::peripherals::TRNG; | ||
| 12 | use embassy_rp::trng::Trng; | ||
| 13 | use embassy_time::Timer; | ||
| 14 | use rand::RngCore; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[link_section = ".start_block"] | ||
| 18 | #[used] | ||
| 19 | pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); | ||
| 20 | |||
| 21 | // Program metadata for `picotool info` | ||
| 22 | #[link_section = ".bi_entries"] | ||
| 23 | #[used] | ||
| 24 | pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ | ||
| 25 | embassy_rp::binary_info::rp_program_name!(c"example"), | ||
| 26 | embassy_rp::binary_info::rp_cargo_version!(), | ||
| 27 | embassy_rp::binary_info::rp_program_description!(c"Blinky"), | ||
| 28 | embassy_rp::binary_info::rp_program_build_attribute!(), | ||
| 29 | ]; | ||
| 30 | |||
| 31 | bind_interrupts!(struct Irqs { | ||
| 32 | TRNG_IRQ => embassy_rp::trng::InterruptHandler<TRNG>; | ||
| 33 | }); | ||
| 34 | |||
| 35 | #[embassy_executor::main] | ||
| 36 | async fn main(_spawner: Spawner) { | ||
| 37 | let peripherals = embassy_rp::init(Default::default()); | ||
| 38 | |||
| 39 | // Initialize the TRNG with default configuration | ||
| 40 | let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default()); | ||
| 41 | // A buffer to collect random bytes in. | ||
| 42 | let mut randomness = [0u8; 58]; | ||
| 43 | |||
| 44 | let mut led = Output::new(peripherals.PIN_25, Level::Low); | ||
| 45 | |||
| 46 | loop { | ||
| 47 | trng.fill_bytes(&mut randomness).await; | ||
| 48 | info!("Random bytes async {}", &randomness); | ||
| 49 | trng.blocking_fill_bytes(&mut randomness); | ||
| 50 | info!("Random bytes blocking {}", &randomness); | ||
| 51 | let random_u32 = trng.next_u32(); | ||
| 52 | let random_u64 = trng.next_u64(); | ||
| 53 | info!("Random u32 {} u64 {}", random_u32, random_u64); | ||
| 54 | // Random number of blinks between 0 and 31 | ||
| 55 | let blinks = random_u32 % 32; | ||
| 56 | for _ in 0..blinks { | ||
| 57 | led.set_high(); | ||
| 58 | Timer::after_millis(20).await; | ||
| 59 | led.set_low(); | ||
| 60 | Timer::after_millis(20).await; | ||
| 61 | } | ||
| 62 | Timer::after_millis(1000).await; | ||
| 63 | } | ||
| 64 | } | ||
diff --git a/examples/stm32f4/src/bin/eth_compliance_test.rs b/examples/stm32f4/src/bin/eth_compliance_test.rs new file mode 100644 index 000000000..5946fed79 --- /dev/null +++ b/examples/stm32f4/src/bin/eth_compliance_test.rs | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::eth::generic_smi::GenericSMI; | ||
| 7 | use embassy_stm32::eth::{Ethernet, PacketQueue, StationManagement}; | ||
| 8 | use embassy_stm32::time::Hertz; | ||
| 9 | use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use static_cell::StaticCell; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | ETH => eth::InterruptHandler; | ||
| 16 | HASH_RNG => rng::InterruptHandler<peripherals::RNG>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(_spawner: Spawner) -> ! { | ||
| 21 | let mut config = Config::default(); | ||
| 22 | { | ||
| 23 | use embassy_stm32::rcc::*; | ||
| 24 | config.rcc.hse = Some(Hse { | ||
| 25 | freq: Hertz(8_000_000), | ||
| 26 | mode: HseMode::Bypass, | ||
| 27 | }); | ||
| 28 | config.rcc.pll_src = PllSource::HSE; | ||
| 29 | config.rcc.pll = Some(Pll { | ||
| 30 | prediv: PllPreDiv::DIV4, | ||
| 31 | mul: PllMul::MUL180, | ||
| 32 | divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. | ||
| 33 | divq: None, | ||
| 34 | divr: None, | ||
| 35 | }); | ||
| 36 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 37 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 38 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 39 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 40 | } | ||
| 41 | let p = embassy_stm32::init(config); | ||
| 42 | |||
| 43 | info!("Hello Compliance World!"); | ||
| 44 | |||
| 45 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | ||
| 46 | |||
| 47 | const PHY_ADDR: u8 = 0; | ||
| 48 | static PACKETS: StaticCell<PacketQueue<4, 4>> = StaticCell::new(); | ||
| 49 | let mut device = Ethernet::new( | ||
| 50 | PACKETS.init(PacketQueue::<4, 4>::new()), | ||
| 51 | p.ETH, | ||
| 52 | Irqs, | ||
| 53 | p.PA1, | ||
| 54 | p.PA2, | ||
| 55 | p.PC1, | ||
| 56 | p.PA7, | ||
| 57 | p.PC4, | ||
| 58 | p.PC5, | ||
| 59 | p.PG13, | ||
| 60 | p.PB13, | ||
| 61 | p.PG11, | ||
| 62 | GenericSMI::new(PHY_ADDR), | ||
| 63 | mac_addr, | ||
| 64 | ); | ||
| 65 | |||
| 66 | let sm = unsafe { device.station_management() }; | ||
| 67 | |||
| 68 | // Just an example. Exact register settings depend on the specific PHY and test. | ||
| 69 | sm.smi_write(PHY_ADDR, 0, 0x2100); | ||
| 70 | sm.smi_write(PHY_ADDR, 11, 0xA000); | ||
| 71 | |||
| 72 | // NB: Remember to reset the PHY after testing before starting the networking stack | ||
| 73 | |||
| 74 | loop { | ||
| 75 | Timer::after_secs(1).await; | ||
| 76 | } | ||
| 77 | } | ||
diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs new file mode 100644 index 000000000..6773f7843 --- /dev/null +++ b/examples/stm32h7rs/src/bin/usb_serial.rs | |||
| @@ -0,0 +1,140 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{panic, *}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_futures::join::join; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use embassy_stm32::usb::{Driver, Instance}; | ||
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | ||
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 11 | use embassy_usb::driver::EndpointError; | ||
| 12 | use embassy_usb::Builder; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | // If you are trying this and your USB device doesn't connect, the most | ||
| 20 | // common issues are the RCC config and vbus_detection | ||
| 21 | // | ||
| 22 | // See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure | ||
| 23 | // for more information. | ||
| 24 | #[embassy_executor::main] | ||
| 25 | async fn main(_spawner: Spawner) { | ||
| 26 | info!("Hello World!"); | ||
| 27 | |||
| 28 | let mut config = Config::default(); | ||
| 29 | |||
| 30 | { | ||
| 31 | use embassy_stm32::rcc::*; | ||
| 32 | config.rcc.hse = Some(Hse { | ||
| 33 | freq: Hertz(24_000_000), | ||
| 34 | mode: HseMode::Oscillator, | ||
| 35 | }); | ||
| 36 | config.rcc.pll1 = Some(Pll { | ||
| 37 | source: PllSource::HSE, | ||
| 38 | prediv: PllPreDiv::DIV12, | ||
| 39 | mul: PllMul::MUL300, | ||
| 40 | divp: Some(PllDiv::DIV1), //600 MHz | ||
| 41 | divq: Some(PllDiv::DIV2), // 300 MHz | ||
| 42 | divr: Some(PllDiv::DIV2), // 300 MHz | ||
| 43 | }); | ||
| 44 | config.rcc.sys = Sysclk::PLL1_P; // 600 MHz | ||
| 45 | config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz | ||
| 46 | config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 MHz | ||
| 47 | config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 MHz | ||
| 48 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 MHz | ||
| 49 | config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 MHz | ||
| 50 | config.rcc.voltage_scale = VoltageScale::HIGH; | ||
| 51 | config.rcc.mux.usbphycsel = mux::Usbphycsel::HSE; | ||
| 52 | } | ||
| 53 | |||
| 54 | let p = embassy_stm32::init(config); | ||
| 55 | |||
| 56 | // Create the driver, from the HAL. | ||
| 57 | let mut ep_out_buffer = [0u8; 256]; | ||
| 58 | let mut config = embassy_stm32::usb::Config::default(); | ||
| 59 | |||
| 60 | // Do not enable vbus_detection. This is a safe default that works in all boards. | ||
| 61 | // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need | ||
| 62 | // to enable vbus_detection to comply with the USB spec. If you enable it, the board | ||
| 63 | // has to support it or USB won't work at all. See docs on `vbus_detection` for details. | ||
| 64 | config.vbus_detection = false; | ||
| 65 | |||
| 66 | let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PM6, p.PM5, &mut ep_out_buffer, config); | ||
| 67 | |||
| 68 | // Create embassy-usb Config | ||
| 69 | let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||
| 70 | config.manufacturer = Some("Embassy"); | ||
| 71 | config.product = Some("USB-serial example"); | ||
| 72 | config.serial_number = Some("12345678"); | ||
| 73 | // Required for windows compatibility. | ||
| 74 | // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help | ||
| 75 | config.device_class = 0xEF; | ||
| 76 | config.device_sub_class = 0x02; | ||
| 77 | config.device_protocol = 0x01; | ||
| 78 | config.composite_with_iads = true; | ||
| 79 | |||
| 80 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 81 | // It needs some buffers for building the descriptors. | ||
| 82 | let mut config_descriptor = [0; 256]; | ||
| 83 | let mut bos_descriptor = [0; 256]; | ||
| 84 | let mut control_buf = [0; 64]; | ||
| 85 | |||
| 86 | let mut state = State::new(); | ||
| 87 | |||
| 88 | let mut builder = Builder::new( | ||
| 89 | driver, | ||
| 90 | config, | ||
| 91 | &mut config_descriptor, | ||
| 92 | &mut bos_descriptor, | ||
| 93 | &mut [], // no msos descriptors | ||
| 94 | &mut control_buf, | ||
| 95 | ); | ||
| 96 | |||
| 97 | // Create classes on the builder. | ||
| 98 | let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); | ||
| 99 | |||
| 100 | // Build the builder. | ||
| 101 | let mut usb = builder.build(); | ||
| 102 | |||
| 103 | // Run the USB device. | ||
| 104 | let usb_fut = usb.run(); | ||
| 105 | |||
| 106 | // Do stuff with the class! | ||
| 107 | let echo_fut = async { | ||
| 108 | loop { | ||
| 109 | class.wait_connection().await; | ||
| 110 | info!("Connected"); | ||
| 111 | let _ = echo(&mut class).await; | ||
| 112 | info!("Disconnected"); | ||
| 113 | } | ||
| 114 | }; | ||
| 115 | |||
| 116 | // Run everything concurrently. | ||
| 117 | // If we had made everything `'static` above instead, we could do this using separate tasks instead. | ||
| 118 | join(usb_fut, echo_fut).await; | ||
| 119 | } | ||
| 120 | |||
| 121 | struct Disconnected {} | ||
| 122 | |||
| 123 | impl From<EndpointError> for Disconnected { | ||
| 124 | fn from(val: EndpointError) -> Self { | ||
| 125 | match val { | ||
| 126 | EndpointError::BufferOverflow => panic!("Buffer overflow"), | ||
| 127 | EndpointError::Disabled => Disconnected {}, | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { | ||
| 133 | let mut buf = [0; 64]; | ||
| 134 | loop { | ||
| 135 | let n = class.read_packet(&mut buf).await?; | ||
| 136 | let data = &buf[..n]; | ||
| 137 | info!("data: {:x}", data); | ||
| 138 | class.write_packet(data).await?; | ||
| 139 | } | ||
| 140 | } | ||
