diff options
| author | chemicstry <[email protected]> | 2023-01-18 02:37:02 +0200 |
|---|---|---|
| committer | chemicstry <[email protected]> | 2023-01-18 02:37:02 +0200 |
| commit | 7d34f4f538f88d84d499173e15f63e676d4af9c0 (patch) | |
| tree | 19a236408a27115d63cfaaa85592c5e364bf0dfb | |
| parent | f07e59b24a2fff6dfbfd52ac5f55fb2667dae0d8 (diff) | |
stm32/usb_otg: Add F4 usb_ethernet example
| -rw-r--r-- | examples/stm32f4/Cargo.toml | 6 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_ethernet.rs | 169 |
2 files changed, 174 insertions, 1 deletions
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 252d60855..e2b17bfcb 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml | |||
| @@ -4,13 +4,13 @@ name = "embassy-stm32f4-examples" | |||
| 4 | version = "0.1.0" | 4 | version = "0.1.0" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | |||
| 8 | [dependencies] | 7 | [dependencies] |
| 9 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } |
| 11 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } |
| 12 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 13 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"], optional = true } | ||
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.4" | 16 | defmt-rtt = "0.4" |
| @@ -27,5 +27,9 @@ embedded-storage = "0.3.0" | |||
| 27 | micromath = "2.0.0" | 27 | micromath = "2.0.0" |
| 28 | static_cell = "1.0" | 28 | static_cell = "1.0" |
| 29 | 29 | ||
| 30 | [[bin]] | ||
| 31 | name = "usb_ethernet" | ||
| 32 | required-features = ["embassy-net"] | ||
| 33 | |||
| 30 | [profile.release] | 34 | [profile.release] |
| 31 | debug = 2 | 35 | debug = 2 |
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs new file mode 100644 index 000000000..cf2885ae5 --- /dev/null +++ b/examples/stm32f4/src/bin/usb_ethernet.rs | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_net::tcp::TcpSocket; | ||
| 8 | use embassy_net::{Stack, StackResources}; | ||
| 9 | use embassy_stm32::rng::Rng; | ||
| 10 | use embassy_stm32::time::mhz; | ||
| 11 | use embassy_stm32::usb_otg::Driver; | ||
| 12 | use embassy_stm32::{interrupt, Config}; | ||
| 13 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; | ||
| 14 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | ||
| 15 | use embassy_usb::{Builder, UsbDevice}; | ||
| 16 | use embedded_io::asynch::Write; | ||
| 17 | use static_cell::StaticCell; | ||
| 18 | use {defmt_rtt as _, panic_probe as _}; | ||
| 19 | |||
| 20 | type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>; | ||
| 21 | |||
| 22 | macro_rules! singleton { | ||
| 23 | ($val:expr) => {{ | ||
| 24 | type T = impl Sized; | ||
| 25 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 26 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 27 | x | ||
| 28 | }}; | ||
| 29 | } | ||
| 30 | |||
| 31 | const MTU: usize = 1514; | ||
| 32 | |||
| 33 | #[embassy_executor::task] | ||
| 34 | async fn usb_task(mut device: UsbDevice<'static, UsbDriver>) -> ! { | ||
| 35 | device.run().await | ||
| 36 | } | ||
| 37 | |||
| 38 | #[embassy_executor::task] | ||
| 39 | async fn usb_ncm_task(class: Runner<'static, UsbDriver, MTU>) -> ! { | ||
| 40 | class.run().await | ||
| 41 | } | ||
| 42 | |||
| 43 | #[embassy_executor::task] | ||
| 44 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | ||
| 45 | stack.run().await | ||
| 46 | } | ||
| 47 | |||
| 48 | #[embassy_executor::main] | ||
| 49 | async fn main(spawner: Spawner) { | ||
| 50 | info!("Hello World!"); | ||
| 51 | |||
| 52 | let mut config = Config::default(); | ||
| 53 | config.rcc.pll48 = true; | ||
| 54 | config.rcc.sys_ck = Some(mhz(48)); | ||
| 55 | |||
| 56 | let p = embassy_stm32::init(config); | ||
| 57 | |||
| 58 | // Create the driver, from the HAL. | ||
| 59 | let irq = interrupt::take!(OTG_FS); | ||
| 60 | let ep_out_buffer = &mut singleton!([0; 256])[..]; | ||
| 61 | let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, ep_out_buffer); | ||
| 62 | |||
| 63 | // Create embassy-usb Config | ||
| 64 | let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||
| 65 | config.manufacturer = Some("Embassy"); | ||
| 66 | config.product = Some("USB-Ethernet example"); | ||
| 67 | config.serial_number = Some("12345678"); | ||
| 68 | config.max_power = 100; | ||
| 69 | config.max_packet_size_0 = 64; | ||
| 70 | |||
| 71 | // Required for Windows support. | ||
| 72 | config.composite_with_iads = true; | ||
| 73 | config.device_class = 0xEF; | ||
| 74 | config.device_sub_class = 0x02; | ||
| 75 | config.device_protocol = 0x01; | ||
| 76 | |||
| 77 | // Create embassy-usb DeviceBuilder using the driver and config. | ||
| 78 | let mut builder = Builder::new( | ||
| 79 | driver, | ||
| 80 | config, | ||
| 81 | &mut singleton!([0; 256])[..], | ||
| 82 | &mut singleton!([0; 256])[..], | ||
| 83 | &mut singleton!([0; 256])[..], | ||
| 84 | &mut singleton!([0; 128])[..], | ||
| 85 | None, | ||
| 86 | ); | ||
| 87 | |||
| 88 | // Our MAC addr. | ||
| 89 | let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]; | ||
| 90 | // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has. | ||
| 91 | let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; | ||
| 92 | |||
| 93 | // Create classes on the builder. | ||
| 94 | let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64); | ||
| 95 | |||
| 96 | // Build the builder. | ||
| 97 | let usb = builder.build(); | ||
| 98 | |||
| 99 | unwrap!(spawner.spawn(usb_task(usb))); | ||
| 100 | |||
| 101 | let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); | ||
| 102 | unwrap!(spawner.spawn(usb_ncm_task(runner))); | ||
| 103 | |||
| 104 | let config = embassy_net::ConfigStrategy::Dhcp; | ||
| 105 | //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { | ||
| 106 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | ||
| 107 | // dns_servers: Vec::new(), | ||
| 108 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | ||
| 109 | //}); | ||
| 110 | |||
| 111 | // Generate random seed | ||
| 112 | let mut rng = Rng::new(p.RNG); | ||
| 113 | let mut seed = [0; 8]; | ||
| 114 | unwrap!(rng.async_fill_bytes(&mut seed).await); | ||
| 115 | let seed = u64::from_le_bytes(seed); | ||
| 116 | |||
| 117 | // Init network stack | ||
| 118 | let stack = &*singleton!(Stack::new( | ||
| 119 | device, | ||
| 120 | config, | ||
| 121 | singleton!(StackResources::<1, 2, 8>::new()), | ||
| 122 | seed | ||
| 123 | )); | ||
| 124 | |||
| 125 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 126 | |||
| 127 | // And now we can use it! | ||
| 128 | |||
| 129 | let mut rx_buffer = [0; 4096]; | ||
| 130 | let mut tx_buffer = [0; 4096]; | ||
| 131 | let mut buf = [0; 4096]; | ||
| 132 | |||
| 133 | loop { | ||
| 134 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 135 | socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); | ||
| 136 | |||
| 137 | info!("Listening on TCP:1234..."); | ||
| 138 | if let Err(e) = socket.accept(1234).await { | ||
| 139 | warn!("accept error: {:?}", e); | ||
| 140 | continue; | ||
| 141 | } | ||
| 142 | |||
| 143 | info!("Received connection from {:?}", socket.remote_endpoint()); | ||
| 144 | |||
| 145 | loop { | ||
| 146 | let n = match socket.read(&mut buf).await { | ||
| 147 | Ok(0) => { | ||
| 148 | warn!("read EOF"); | ||
| 149 | break; | ||
| 150 | } | ||
| 151 | Ok(n) => n, | ||
| 152 | Err(e) => { | ||
| 153 | warn!("read error: {:?}", e); | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | }; | ||
| 157 | |||
| 158 | info!("rxd {:02x}", &buf[..n]); | ||
| 159 | |||
| 160 | match socket.write_all(&buf[..n]).await { | ||
| 161 | Ok(()) => {} | ||
| 162 | Err(e) => { | ||
| 163 | warn!("write error: {:?}", e); | ||
| 164 | break; | ||
| 165 | } | ||
| 166 | }; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | } | ||
