aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/ltdc.rs3
-rw-r--r--examples/stm32u5/.cargo/config.toml4
-rw-r--r--examples/stm32u5/Cargo.toml6
-rw-r--r--examples/stm32u5/src/bin/ferris.bmpbin0 -> 6794 bytes
-rw-r--r--examples/stm32u5/src/bin/i2c.rs2
-rw-r--r--examples/stm32u5/src/bin/ltdc.rs461
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs4
7 files changed, 473 insertions, 7 deletions
diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs
index 4c5239971..e25c4f3fb 100644
--- a/embassy-stm32/src/ltdc.rs
+++ b/embassy-stm32/src/ltdc.rs
@@ -395,7 +395,10 @@ impl<'d, T: Instance> Ltdc<'d, T> {
395 // framebuffer pitch and line length 395 // framebuffer pitch and line length
396 layer.cfblr().modify(|w| { 396 layer.cfblr().modify(|w| {
397 w.set_cfbp(width * bytes_per_pixel); 397 w.set_cfbp(width * bytes_per_pixel);
398 #[cfg(not(stm32u5))]
398 w.set_cfbll(width * bytes_per_pixel + 7); 399 w.set_cfbll(width * bytes_per_pixel + 7);
400 #[cfg(stm32u5)]
401 w.set_cfbll(width * bytes_per_pixel + 3);
399 }); 402 });
400 403
401 // framebuffer line number 404 // framebuffer line number
diff --git a/examples/stm32u5/.cargo/config.toml b/examples/stm32u5/.cargo/config.toml
index 36c5b63a6..bdbd86354 100644
--- a/examples/stm32u5/.cargo/config.toml
+++ b/examples/stm32u5/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32U585AIIx with your chip as listed in `probe-rs chip list` 2# replace STM32U5G9ZJTxQ with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32U585AIIx" 3runner = "probe-rs run --chip STM32U5G9ZJTxQ"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index ad7db4c32..8b576425c 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -5,8 +5,8 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32u585ai to your chip name, if necessary. 8# Change stm32u5g9zj to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
@@ -21,6 +21,8 @@ cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
23heapless = { version = "0.8", default-features = false } 23heapless = { version = "0.8", default-features = false }
24embedded-graphics = { version = "0.8.1" }
25tinybmp = { version = "0.6.0" }
24 26
25micromath = "2.0.0" 27micromath = "2.0.0"
26 28
diff --git a/examples/stm32u5/src/bin/ferris.bmp b/examples/stm32u5/src/bin/ferris.bmp
new file mode 100644
index 000000000..7a222ab84
--- /dev/null
+++ b/examples/stm32u5/src/bin/ferris.bmp
Binary files differ
diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs
index 19a78eac9..d5f5d6f60 100644
--- a/examples/stm32u5/src/bin/i2c.rs
+++ b/examples/stm32u5/src/bin/i2c.rs
@@ -13,7 +13,7 @@ const WHOAMI: u8 = 0x0F;
13#[embassy_executor::main] 13#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
16 let mut i2c = I2c::new_blocking(p.I2C2, p.PH4, p.PH5, Hertz(100_000), Default::default()); 16 let mut i2c = I2c::new_blocking(p.I2C2, p.PF1, p.PF0, Hertz(100_000), Default::default());
17 17
18 let mut data = [0u8; 1]; 18 let mut data = [0u8; 1];
19 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data)); 19 unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data));
diff --git a/examples/stm32u5/src/bin/ltdc.rs b/examples/stm32u5/src/bin/ltdc.rs
new file mode 100644
index 000000000..bd59a9148
--- /dev/null
+++ b/examples/stm32u5/src/bin/ltdc.rs
@@ -0,0 +1,461 @@
1#![no_std]
2#![no_main]
3#![macro_use]
4#![allow(static_mut_refs)]
5
6/// This example was derived from examples\stm32h735\src\bin\ltdc.rs
7/// It demonstrates the LTDC lcd display peripheral and was tested on an STM32U5G9J-DK2 demo board (embassy-stm32 feature "stm32u5g9zj" and probe-rs chip "STM32U5G9ZJTxQ")
8///
9use bouncy_box::BouncyBox;
10use defmt::{info, unwrap};
11use embassy_executor::Spawner;
12use embassy_stm32::gpio::{Level, Output, Speed};
13use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge};
14use embassy_stm32::{bind_interrupts, peripherals};
15use embassy_time::{Duration, Timer};
16use embedded_graphics::draw_target::DrawTarget;
17use embedded_graphics::geometry::{OriginDimensions, Point, Size};
18use embedded_graphics::image::Image;
19use embedded_graphics::pixelcolor::raw::RawU24;
20use embedded_graphics::pixelcolor::Rgb888;
21use embedded_graphics::prelude::*;
22use embedded_graphics::primitives::Rectangle;
23use embedded_graphics::Pixel;
24use heapless::{Entry, FnvIndexMap};
25use tinybmp::Bmp;
26use {defmt_rtt as _, panic_probe as _};
27
28const DISPLAY_WIDTH: usize = 800;
29const DISPLAY_HEIGHT: usize = 480;
30const MY_TASK_POOL_SIZE: usize = 2;
31
32// the following two display buffers consume 261120 bytes that just about fits into axis ram found on the mcu
33pub static mut FB1: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT];
34pub static mut FB2: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT];
35
36bind_interrupts!(struct Irqs {
37 LTDC => ltdc::InterruptHandler<peripherals::LTDC>;
38});
39
40const NUM_COLORS: usize = 256;
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = rcc_setup::stm32u5g9zj_init();
45
46 // enable ICACHE
47 embassy_stm32::pac::ICACHE.cr().write(|w| {
48 w.set_en(true);
49 });
50
51 // blink the led on another task
52 let led = Output::new(p.PD2, Level::High, Speed::Low);
53 unwrap!(spawner.spawn(led_task(led)));
54
55 // numbers from STM32U5G9J-DK2.ioc
56 const RK050HR18H_HSYNC: u16 = 5; // Horizontal synchronization
57 const RK050HR18H_HBP: u16 = 8; // Horizontal back porch
58 const RK050HR18H_HFP: u16 = 8; // Horizontal front porch
59 const RK050HR18H_VSYNC: u16 = 5; // Vertical synchronization
60 const RK050HR18H_VBP: u16 = 8; // Vertical back porch
61 const RK050HR18H_VFP: u16 = 8; // Vertical front porch
62
63 // NOTE: all polarities have to be reversed with respect to the STM32U5G9J-DK2 CubeMX parametrization
64 let ltdc_config = LtdcConfiguration {
65 active_width: DISPLAY_WIDTH as _,
66 active_height: DISPLAY_HEIGHT as _,
67 h_back_porch: RK050HR18H_HBP,
68 h_front_porch: RK050HR18H_HFP,
69 v_back_porch: RK050HR18H_VBP,
70 v_front_porch: RK050HR18H_VFP,
71 h_sync: RK050HR18H_HSYNC,
72 v_sync: RK050HR18H_VSYNC,
73 h_sync_polarity: PolarityActive::ActiveHigh,
74 v_sync_polarity: PolarityActive::ActiveHigh,
75 data_enable_polarity: PolarityActive::ActiveHigh,
76 pixel_clock_polarity: PolarityEdge::RisingEdge,
77 };
78
79 info!("init ltdc");
80 let mut ltdc_de = Output::new(p.PD6, Level::Low, Speed::High);
81 let mut ltdc_disp_ctrl = Output::new(p.PE4, Level::Low, Speed::High);
82 let mut ltdc_bl_ctrl = Output::new(p.PE6, Level::Low, Speed::High);
83 let mut ltdc = Ltdc::new_with_pins(
84 p.LTDC, // PERIPHERAL
85 Irqs, // IRQS
86 p.PD3, // CLK
87 p.PE0, // HSYNC
88 p.PD13, // VSYNC
89 p.PB9, // B0
90 p.PB2, // B1
91 p.PD14, // B2
92 p.PD15, // B3
93 p.PD0, // B4
94 p.PD1, // B5
95 p.PE7, // B6
96 p.PE8, // B7
97 p.PC8, // G0
98 p.PC9, // G1
99 p.PE9, // G2
100 p.PE10, // G3
101 p.PE11, // G4
102 p.PE12, // G5
103 p.PE13, // G6
104 p.PE14, // G7
105 p.PC6, // R0
106 p.PC7, // R1
107 p.PE15, // R2
108 p.PD8, // R3
109 p.PD9, // R4
110 p.PD10, // R5
111 p.PD11, // R6
112 p.PD12, // R7
113 );
114 ltdc.init(&ltdc_config);
115 ltdc_de.set_low();
116 ltdc_bl_ctrl.set_high();
117 ltdc_disp_ctrl.set_high();
118
119 // we only need to draw on one layer for this example (not to be confused with the double buffer)
120 info!("enable bottom layer");
121 let layer_config = LtdcLayerConfig {
122 pixel_format: ltdc::PixelFormat::L8, // 1 byte per pixel
123 layer: LtdcLayer::Layer1,
124 window_x0: 0,
125 window_x1: DISPLAY_WIDTH as _,
126 window_y0: 0,
127 window_y1: DISPLAY_HEIGHT as _,
128 };
129
130 let ferris_bmp: Bmp<Rgb888> = Bmp::from_slice(include_bytes!("./ferris.bmp")).unwrap();
131 let color_map = build_color_lookup_map(&ferris_bmp);
132 let clut = build_clut(&color_map);
133
134 // enable the bottom layer with a 256 color lookup table
135 ltdc.init_layer(&layer_config, Some(&clut));
136
137 // Safety: the DoubleBuffer controls access to the statically allocated frame buffers
138 // and it is the only thing that mutates their content
139 let mut double_buffer = DoubleBuffer::new(
140 unsafe { FB1.as_mut() },
141 unsafe { FB2.as_mut() },
142 layer_config,
143 color_map,
144 );
145
146 // this allows us to perform some simple animation for every frame
147 let mut bouncy_box = BouncyBox::new(
148 ferris_bmp.bounding_box(),
149 Rectangle::new(Point::zero(), Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32)),
150 2,
151 );
152
153 loop {
154 // cpu intensive drawing to the buffer that is NOT currently being copied to the LCD screen
155 double_buffer.clear();
156 let position = bouncy_box.next_point();
157 let ferris = Image::new(&ferris_bmp, position);
158 unwrap!(ferris.draw(&mut double_buffer));
159
160 // perform async dma data transfer to the lcd screen
161 unwrap!(double_buffer.swap(&mut ltdc).await);
162 }
163}
164
165/// builds the color look-up table from all unique colors found in the bitmap. This should be a 256 color indexed bitmap to work.
166fn build_color_lookup_map(bmp: &Bmp<Rgb888>) -> FnvIndexMap<u32, u8, NUM_COLORS> {
167 let mut color_map: FnvIndexMap<u32, u8, NUM_COLORS> = heapless::FnvIndexMap::new();
168 let mut counter: u8 = 0;
169
170 // add black to position 0
171 color_map.insert(Rgb888::new(0, 0, 0).into_storage(), counter).unwrap();
172 counter += 1;
173
174 for Pixel(_point, color) in bmp.pixels() {
175 let raw = color.into_storage();
176 if let Entry::Vacant(v) = color_map.entry(raw) {
177 v.insert(counter).expect("more than 256 colors detected");
178 counter += 1;
179 }
180 }
181 color_map
182}
183
184/// builds the color look-up table from the color map provided
185fn build_clut(color_map: &FnvIndexMap<u32, u8, NUM_COLORS>) -> [ltdc::RgbColor; NUM_COLORS] {
186 let mut clut = [ltdc::RgbColor::default(); NUM_COLORS];
187 for (color, index) in color_map.iter() {
188 let color = Rgb888::from(RawU24::new(*color));
189 clut[*index as usize] = ltdc::RgbColor {
190 red: color.r(),
191 green: color.g(),
192 blue: color.b(),
193 };
194 }
195
196 clut
197}
198
199#[embassy_executor::task(pool_size = MY_TASK_POOL_SIZE)]
200async fn led_task(mut led: Output<'static>) {
201 let mut counter = 0;
202 loop {
203 info!("blink: {}", counter);
204 counter += 1;
205
206 // on
207 led.set_low();
208 Timer::after(Duration::from_millis(50)).await;
209
210 // off
211 led.set_high();
212 Timer::after(Duration::from_millis(450)).await;
213 }
214}
215
216pub type TargetPixelType = u8;
217
218// A simple double buffer
219pub struct DoubleBuffer {
220 buf0: &'static mut [TargetPixelType],
221 buf1: &'static mut [TargetPixelType],
222 is_buf0: bool,
223 layer_config: LtdcLayerConfig,
224 color_map: FnvIndexMap<u32, u8, NUM_COLORS>,
225}
226
227impl DoubleBuffer {
228 pub fn new(
229 buf0: &'static mut [TargetPixelType],
230 buf1: &'static mut [TargetPixelType],
231 layer_config: LtdcLayerConfig,
232 color_map: FnvIndexMap<u32, u8, NUM_COLORS>,
233 ) -> Self {
234 Self {
235 buf0,
236 buf1,
237 is_buf0: true,
238 layer_config,
239 color_map,
240 }
241 }
242
243 pub fn current(&mut self) -> (&FnvIndexMap<u32, u8, NUM_COLORS>, &mut [TargetPixelType]) {
244 if self.is_buf0 {
245 (&self.color_map, self.buf0)
246 } else {
247 (&self.color_map, self.buf1)
248 }
249 }
250
251 pub async fn swap<T: ltdc::Instance>(&mut self, ltdc: &mut Ltdc<'_, T>) -> Result<(), ltdc::Error> {
252 let (_, buf) = self.current();
253 let frame_buffer = buf.as_ptr();
254 self.is_buf0 = !self.is_buf0;
255 ltdc.set_buffer(self.layer_config.layer, frame_buffer as *const _).await
256 }
257
258 /// Clears the buffer
259 pub fn clear(&mut self) {
260 let (color_map, buf) = self.current();
261 let black = Rgb888::new(0, 0, 0).into_storage();
262 let color_index = color_map.get(&black).expect("no black found in the color map");
263
264 for a in buf.iter_mut() {
265 *a = *color_index; // solid black
266 }
267 }
268}
269
270// Implement DrawTarget for
271impl DrawTarget for DoubleBuffer {
272 type Color = Rgb888;
273 type Error = ();
274
275 /// Draw a pixel
276 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
277 where
278 I: IntoIterator<Item = Pixel<Self::Color>>,
279 {
280 let size = self.size();
281 let width = size.width as i32;
282 let height = size.height as i32;
283 let (color_map, buf) = self.current();
284
285 for pixel in pixels {
286 let Pixel(point, color) = pixel;
287
288 if point.x >= 0 && point.y >= 0 && point.x < width && point.y < height {
289 let index = point.y * width + point.x;
290 let raw_color = color.into_storage();
291
292 match color_map.get(&raw_color) {
293 Some(x) => {
294 buf[index as usize] = *x;
295 }
296 None => panic!("color not found in color map: {}", raw_color),
297 };
298 } else {
299 // Ignore invalid points
300 }
301 }
302
303 Ok(())
304 }
305}
306
307impl OriginDimensions for DoubleBuffer {
308 /// Return the size of the display
309 fn size(&self) -> Size {
310 Size::new(
311 (self.layer_config.window_x1 - self.layer_config.window_x0) as _,
312 (self.layer_config.window_y1 - self.layer_config.window_y0) as _,
313 )
314 }
315}
316
317mod rcc_setup {
318
319 use embassy_stm32::time::Hertz;
320 use embassy_stm32::{rcc, Config, Peripherals};
321
322 /// Sets up clocks for the stm32u5g9zj mcu
323 /// change this if you plan to use a different microcontroller
324 pub fn stm32u5g9zj_init() -> Peripherals {
325 // setup power and clocks for an STM32U5G9J-DK2 run from an external 16 Mhz external oscillator
326 let mut config = Config::default();
327 config.rcc.hse = Some(rcc::Hse {
328 freq: Hertz(16_000_000),
329 mode: rcc::HseMode::Oscillator,
330 });
331 config.rcc.pll1 = Some(rcc::Pll {
332 source: rcc::PllSource::HSE,
333 prediv: rcc::PllPreDiv::DIV1,
334 mul: rcc::PllMul::MUL10,
335 divp: None,
336 divq: None,
337 divr: Some(rcc::PllDiv::DIV1),
338 });
339 config.rcc.sys = rcc::Sysclk::PLL1_R; // 160 Mhz
340 config.rcc.pll3 = Some(rcc::Pll {
341 source: rcc::PllSource::HSE,
342 prediv: rcc::PllPreDiv::DIV4, // PLL_M
343 mul: rcc::PllMul::MUL125, // PLL_N
344 divp: None,
345 divq: None,
346 divr: Some(rcc::PllDiv::DIV20),
347 });
348 config.rcc.mux.ltdcsel = rcc::mux::Ltdcsel::PLL3_R; // 25 MHz
349 embassy_stm32::init(config)
350 }
351}
352
353mod bouncy_box {
354 use embedded_graphics::geometry::Point;
355 use embedded_graphics::primitives::Rectangle;
356
357 enum Direction {
358 DownLeft,
359 DownRight,
360 UpLeft,
361 UpRight,
362 }
363
364 pub struct BouncyBox {
365 direction: Direction,
366 child_rect: Rectangle,
367 parent_rect: Rectangle,
368 current_point: Point,
369 move_by: usize,
370 }
371
372 // This calculates the coordinates of a chile rectangle bounced around inside a parent bounded box
373 impl BouncyBox {
374 pub fn new(child_rect: Rectangle, parent_rect: Rectangle, move_by: usize) -> Self {
375 let center_box = parent_rect.center();
376 let center_img = child_rect.center();
377 let current_point = Point::new(center_box.x - center_img.x / 2, center_box.y - center_img.y / 2);
378 Self {
379 direction: Direction::DownRight,
380 child_rect,
381 parent_rect,
382 current_point,
383 move_by,
384 }
385 }
386
387 pub fn next_point(&mut self) -> Point {
388 let direction = &self.direction;
389 let img_height = self.child_rect.size.height as i32;
390 let box_height = self.parent_rect.size.height as i32;
391 let img_width = self.child_rect.size.width as i32;
392 let box_width = self.parent_rect.size.width as i32;
393 let move_by = self.move_by as i32;
394
395 match direction {
396 Direction::DownLeft => {
397 self.current_point.x -= move_by;
398 self.current_point.y += move_by;
399
400 let x_out_of_bounds = self.current_point.x < 0;
401 let y_out_of_bounds = (self.current_point.y + img_height) > box_height;
402
403 if x_out_of_bounds && y_out_of_bounds {
404 self.direction = Direction::UpRight
405 } else if x_out_of_bounds && !y_out_of_bounds {
406 self.direction = Direction::DownRight
407 } else if !x_out_of_bounds && y_out_of_bounds {
408 self.direction = Direction::UpLeft
409 }
410 }
411 Direction::DownRight => {
412 self.current_point.x += move_by;
413 self.current_point.y += move_by;
414
415 let x_out_of_bounds = (self.current_point.x + img_width) > box_width;
416 let y_out_of_bounds = (self.current_point.y + img_height) > box_height;
417
418 if x_out_of_bounds && y_out_of_bounds {
419 self.direction = Direction::UpLeft
420 } else if x_out_of_bounds && !y_out_of_bounds {
421 self.direction = Direction::DownLeft
422 } else if !x_out_of_bounds && y_out_of_bounds {
423 self.direction = Direction::UpRight
424 }
425 }
426 Direction::UpLeft => {
427 self.current_point.x -= move_by;
428 self.current_point.y -= move_by;
429
430 let x_out_of_bounds = self.current_point.x < 0;
431 let y_out_of_bounds = self.current_point.y < 0;
432
433 if x_out_of_bounds && y_out_of_bounds {
434 self.direction = Direction::DownRight
435 } else if x_out_of_bounds && !y_out_of_bounds {
436 self.direction = Direction::UpRight
437 } else if !x_out_of_bounds && y_out_of_bounds {
438 self.direction = Direction::DownLeft
439 }
440 }
441 Direction::UpRight => {
442 self.current_point.x += move_by;
443 self.current_point.y -= move_by;
444
445 let x_out_of_bounds = (self.current_point.x + img_width) > box_width;
446 let y_out_of_bounds = self.current_point.y < 0;
447
448 if x_out_of_bounds && y_out_of_bounds {
449 self.direction = Direction::DownLeft
450 } else if x_out_of_bounds && !y_out_of_bounds {
451 self.direction = Direction::UpLeft
452 } else if !x_out_of_bounds && y_out_of_bounds {
453 self.direction = Direction::DownRight
454 }
455 }
456 }
457
458 self.current_point
459 }
460 }
461}
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index 4d56395da..4bb1a6079 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -13,7 +13,7 @@ use embassy_usb::Builder;
13use panic_probe as _; 13use panic_probe as _;
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 OTG_FS => usb::InterruptHandler<peripherals::USB_OTG_FS>; 16 OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
17}); 17});
18 18
19#[embassy_executor::main] 19#[embassy_executor::main]
@@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) {
48 // to enable vbus_detection to comply with the USB spec. If you enable it, the board 48 // to enable vbus_detection to comply with the USB spec. If you enable it, the board
49 // has to support it or USB won't work at all. See docs on `vbus_detection` for details. 49 // has to support it or USB won't work at all. See docs on `vbus_detection` for details.
50 config.vbus_detection = false; 50 config.vbus_detection = false;
51 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 51 let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
52 52
53 // Create embassy-usb Config 53 // Create embassy-usb Config
54 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 54 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);