aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchemicstry <[email protected]>2023-01-18 02:37:02 +0200
committerchemicstry <[email protected]>2023-01-18 02:37:02 +0200
commit7d34f4f538f88d84d499173e15f63e676d4af9c0 (patch)
tree19a236408a27115d63cfaaa85592c5e364bf0dfb
parentf07e59b24a2fff6dfbfd52ac5f55fb2667dae0d8 (diff)
stm32/usb_otg: Add F4 usb_ethernet example
-rw-r--r--examples/stm32f4/Cargo.toml6
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs169
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"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7
8[dependencies] 7[dependencies]
9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"], optional = true }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.4" 16defmt-rtt = "0.4"
@@ -27,5 +27,9 @@ embedded-storage = "0.3.0"
27micromath = "2.0.0" 27micromath = "2.0.0"
28static_cell = "1.0" 28static_cell = "1.0"
29 29
30[[bin]]
31name = "usb_ethernet"
32required-features = ["embassy-net"]
33
30[profile.release] 34[profile.release]
31debug = 2 35debug = 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
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Stack, StackResources};
9use embassy_stm32::rng::Rng;
10use embassy_stm32::time::mhz;
11use embassy_stm32::usb_otg::Driver;
12use embassy_stm32::{interrupt, Config};
13use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
14use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
15use embassy_usb::{Builder, UsbDevice};
16use embedded_io::asynch::Write;
17use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _};
19
20type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>;
21
22macro_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
31const MTU: usize = 1514;
32
33#[embassy_executor::task]
34async fn usb_task(mut device: UsbDevice<'static, UsbDriver>) -> ! {
35 device.run().await
36}
37
38#[embassy_executor::task]
39async fn usb_ncm_task(class: Runner<'static, UsbDriver, MTU>) -> ! {
40 class.run().await
41}
42
43#[embassy_executor::task]
44async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
45 stack.run().await
46}
47
48#[embassy_executor::main]
49async 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}