From 46b3813be5b2cfe00672a9b6083ff798db855331 Mon Sep 17 00:00:00 2001 From: K Date: Sat, 4 Feb 2023 23:21:13 +0500 Subject: [PATCH 1/5] Update dependencies --- Cargo.toml | 8 ++++---- src/stdout.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f5a0321..f8e0ce6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,14 +16,14 @@ default-target = "x86_64-unknown-linux-gnu" [dependencies] gd32vf103xx-hal = "0.5.0" -embedded-hal = "0.2.6" +embedded-hal = "0.2.7" nb = "1.0.0" -riscv = "0.6.0" +riscv = { version = "0.10.1", features = ["critical-section-single-hart"] } st7735-lcd = { version = "0.8.1", optional = true } -embedded-sdmmc = { version = "0.3.0", optional = true } +embedded-sdmmc = { version = "0.4.0", optional = true } [dev-dependencies] -riscv-rt = "0.8.0" +riscv-rt = "0.11.0" panic-halt = "0.2.0" embedded-graphics = "0.7.1" ushell = "0.3.5" diff --git a/src/stdout.rs b/src/stdout.rs index 45f6f77..affc8c7 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -57,7 +57,7 @@ pub fn configure( let serial = Serial::new(uart, (tx, rx), config, afio, rcu); let (tx, _) = serial.split(); - interrupt::free(|_| { + interrupt::free(|| { unsafe { STDOUT.replace(SerialWrapper(tx)); } @@ -66,7 +66,7 @@ pub fn configure( /// Writes string to stdout pub fn write_str(s: &str) { - interrupt::free(|_| unsafe { + interrupt::free(|| unsafe { if let Some(stdout) = STDOUT.as_mut() { let _ = stdout.write_str(s); } @@ -75,7 +75,7 @@ pub fn write_str(s: &str) { /// Writes formatted string to stdout pub fn write_fmt(args: fmt::Arguments) { - interrupt::free(|_| unsafe { + interrupt::free(|| unsafe { if let Some(stdout) = STDOUT.as_mut() { let _ = stdout.write_fmt(args); } From 8805d882d12168440a1c944cc2109cc2a5954182 Mon Sep 17 00:00:00 2001 From: K Date: Sat, 4 Feb 2023 23:21:34 +0500 Subject: [PATCH 2/5] Use fork of HAL --- Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f8e0ce6..0c11e56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,13 +15,16 @@ rustdoc-args = ["--cfg", "docsrs"] default-target = "x86_64-unknown-linux-gnu" [dependencies] -gd32vf103xx-hal = "0.5.0" embedded-hal = "0.2.7" nb = "1.0.0" riscv = { version = "0.10.1", features = ["critical-section-single-hart"] } st7735-lcd = { version = "0.8.1", optional = true } embedded-sdmmc = { version = "0.4.0", optional = true } +[dependencies.gd32vf103xx-hal] +git = "https://github.com/katyo/gd32vf103xx-hal" +branch = "upcoming" + [dev-dependencies] riscv-rt = "0.11.0" panic-halt = "0.2.0" From 2c50a6736b111b0c0afff14e1c3fe0ea1f62e199 Mon Sep 17 00:00:00 2001 From: K Date: Sat, 4 Feb 2023 23:22:22 +0500 Subject: [PATCH 3/5] Add USB OTG FS support --- Cargo.toml | 15 +++- examples/led_shell_usb.rs | 168 ++++++++++++++++++++++++++++++++++++++ examples/serial_usb.rs | 84 +++++++++++++++++++ src/lib.rs | 3 + src/usb.rs | 34 ++++++++ 5 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 examples/led_shell_usb.rs create mode 100644 examples/serial_usb.rs create mode 100644 src/usb.rs diff --git a/Cargo.toml b/Cargo.toml index 0c11e56..839e919 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ nb = "1.0.0" riscv = { version = "0.10.1", features = ["critical-section-single-hart"] } st7735-lcd = { version = "0.8.1", optional = true } embedded-sdmmc = { version = "0.4.0", optional = true } +usb-device = { version = "0.2.9", optional = true } [dependencies.gd32vf103xx-hal] git = "https://github.com/katyo/gd32vf103xx-hal" @@ -29,11 +30,16 @@ branch = "upcoming" riscv-rt = "0.11.0" panic-halt = "0.2.0" embedded-graphics = "0.7.1" -ushell = "0.3.5" +usbd-serial = "0.1.1" + +[dev-dependencies.ushell] +git = "https://github.com/katyo/ushell" +branch = "upcoming" [features] lcd = ["st7735-lcd"] sdcard = ["embedded-sdmmc"] +usb = ["gd32vf103xx-hal/usb_fs", "usb-device"] [[example]] name = "display" @@ -47,3 +53,10 @@ required-features = ["lcd"] name = "sdcard_test" required-features = ["sdcard"] +[[example]] +name = "led_shell_usb" +required-features = ["usb"] + +[[example]] +name = "serial_usb" +required-features = ["usb"] diff --git a/examples/led_shell_usb.rs b/examples/led_shell_usb.rs new file mode 100644 index 0000000..6707fe9 --- /dev/null +++ b/examples/led_shell_usb.rs @@ -0,0 +1,168 @@ +#![no_std] +#![no_main] + +use panic_halt as _; + +use core::fmt::Write; +use longan_nano::{ + hal::{pac, prelude::*}, + led::{rgb, Led, BLUE, GREEN, RED}, + usb::{usb, UsbBusType}, +}; +use riscv_rt::entry; +use ushell::{autocomplete::*, history::*, *}; +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +#[entry] +fn main() -> ! { + let dp = pac::Peripherals::take().unwrap(); + + // Configure clocks + let mut rcu = dp + .RCU + .configure() + .ext_hf_clock(8.mhz()) + .sysclk(96.mhz()) + .freeze(); + + assert!(rcu.clocks.usbclk_valid()); + + let gpioa = dp.GPIOA.split(&mut rcu); + let gpioc = dp.GPIOC.split(&mut rcu); + + let (mut red, mut green, mut blue) = rgb(gpioc.pc13, gpioa.pa1, gpioa.pa2); + red.off(); + green.off(); + blue.off(); + + static mut EP_MEMORY: [u32; 1024] = [0; 1024]; + + let usb_bus = usb( + dp.USBFS_GLOBAL, dp.USBFS_DEVICE, dp.USBFS_PWRCLK, + gpioa.pa11, gpioa.pa12, &rcu, + unsafe { &mut EP_MEMORY }, + ); + + let serial = SerialPort::new(&usb_bus); + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) + .manufacturer("Longan Nano") + .product("Led Shell") + .serial_number("1234") + .device_class(USB_CLASS_CDC) + .build(); + + let autocomplete = StaticAutocomplete(["clear", "help", "status", "off ", "on "]); + let mut shell = UShell::new(serial, autocomplete, LRUHistory::default()); + let mut env = Env { red, green, blue }; + + loop { + if !usb_dev.poll(&mut [shell.as_mut()]) { + continue; + } + + shell.spin(&mut env).ok(); + } +} + +const CMD_LEN: usize = 16; +const HISTORY_SIZE: usize = 4; +const COMMANDS: usize = 5; + +type Serial<'s> = SerialPort<'s, UsbBusType>; +type Autocomplete = StaticAutocomplete<{ COMMANDS }>; +type History = LRUHistory<{ CMD_LEN }, { HISTORY_SIZE }>; +type Shell<'s> = UShell, Autocomplete, History, { CMD_LEN }>; + +struct Env { + red: RED, + green: GREEN, + blue: BLUE, +} + +type EnvResult<'s> = SpinResult, ()>; + +impl<'s> Env { + fn on_cmd(&mut self, shell: &mut Shell<'s>, args: &str) -> EnvResult<'s> { + match args { + "r" | "red" => self.red.on(), + "g" | "green" => self.green.on(), + "b" | "blue" => self.blue.on(), + "a" | "all" => { + self.red.on(); + self.green.on(); + self.blue.on(); + } + _ => { + write!(shell, "{0:}unsupported color channel", CR).ok(); + } + } + shell.write_str(CR)?; + Ok(()) + } + + fn off_cmd(&mut self, shell: &mut Shell<'s>, args: &str) -> EnvResult<'s> { + match args { + "r" | "red" => self.red.off(), + "g" | "green" => self.green.off(), + "b" | "blue" => self.blue.off(), + "a" | "all" => { + self.red.off(); + self.green.off(); + self.blue.off(); + } + _ => { + write!(shell, "{0:}unsupported color channel", CR).ok(); + } + } + shell.write_str(CR)?; + Ok(()) + } + + fn status_cmd(&mut self, shell: &mut Shell<'s>, _args: &str) -> EnvResult<'s> { + let red = if self.red.is_on() { "On" } else { "Off" }; + let green = if self.green.is_on() { "On" } else { "Off" }; + let blue = if self.blue.is_on() { "On" } else { "Off" }; + write!( + shell, + "{0:}Red: {1:}{0:}Green: {2:}{0:}Blue: {3:}{0:}", + CR, red, green, blue, + )?; + + Ok(()) + } +} + +impl<'s> Environment, Autocomplete, History, (), { CMD_LEN }> for Env { + fn command(&mut self, shell: &mut Shell<'s>, cmd: &str, args: &str) -> EnvResult<'s> { + match cmd { + "clear" => shell.clear()?, + "help" => shell.write_str(HELP)?, + "status" => self.status_cmd(shell, args)?, + "on" => self.on_cmd(shell, args)?, + "off" => self.off_cmd(shell, args)?, + "" => shell.write_str(CR)?, + _ => write!(shell, "{0:}unsupported command: \"{1:}\"{0:}", CR, cmd)?, + } + shell.write_str(SHELL_PROMPT)?; + Ok(()) + } + + fn control(&mut self, _shell: &mut Shell<'s>, _code: u8) -> EnvResult<'s> { + Ok(()) + } +} + +const SHELL_PROMPT: &str = "#> "; +const CR: &str = "\r\n"; +const HELP: &str = "\r\n\ +\x1b[31mL\x1b[32mE\x1b[34mD\x1b[33m Shell\x1b[0m\r\n\r\n\ +USAGE:\r\n\ +\x20 command [arg]\r\n\r\n\ +COMMANDS:\r\n\ +\x20 on Switch led channel on [r,g,b,a]\r\n\ +\x20 off Switch led channel off [r,g,b,a]\r\n\ +\x20 status Get leds status\r\n\ +\x20 clear Clear screen\r\n\ +\x20 help Print this message\r\n +"; diff --git a/examples/serial_usb.rs b/examples/serial_usb.rs new file mode 100644 index 0000000..1597413 --- /dev/null +++ b/examples/serial_usb.rs @@ -0,0 +1,84 @@ +#![no_std] +#![no_main] + +use panic_halt as _; + +use gd32vf103xx_hal::pac; +use gd32vf103xx_hal::prelude::*; +use riscv_rt::entry; + +use longan_nano::usb::usb; +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +use embedded_hal::digital::v2::OutputPin; + +#[entry] +fn main() -> ! { + let dp = pac::Peripherals::take().unwrap(); + + // Configure clocks + let mut rcu = dp + .RCU + .configure() + .ext_hf_clock(8.mhz()) + .sysclk(96.mhz()) + .freeze(); + + assert!(rcu.clocks.usbclk_valid()); + + let gpioc = dp.GPIOC.split(&mut rcu); + let mut led = gpioc.pc13.into_push_pull_output(); + led.set_high().unwrap(); // Turn off + + let gpioa = dp.GPIOA.split(&mut rcu); + + static mut EP_MEMORY: [u32; 1024] = [0; 1024]; + let usb_bus = usb( + dp.USBFS_GLOBAL, dp.USBFS_DEVICE, dp.USBFS_PWRCLK, + gpioa.pa11, gpioa.pa12, &rcu, + unsafe { &mut EP_MEMORY }, + ); + + let mut serial = SerialPort::new(&usb_bus); + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST") + .device_class(USB_CLASS_CDC) + .build(); + + loop { + if !usb_dev.poll(&mut [&mut serial]) { + continue; + } + + let mut buf = [0u8; 64]; + + match serial.read(&mut buf) { + Ok(count) if count > 0 => { + led.set_low().unwrap(); // Turn on + + // Echo back in upper case + for c in buf[0..count].iter_mut() { + if 0x61 <= *c && *c <= 0x7a { + *c &= !0x20; + } + } + + let mut write_offset = 0; + while write_offset < count { + match serial.write(&buf[write_offset..count]) { + Ok(len) if len > 0 => { + write_offset += len; + } + _ => {} + } + } + } + _ => {} + } + + led.set_high().unwrap(); // Turn off + } +} diff --git a/src/lib.rs b/src/lib.rs index a64f159..e1809df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,3 +13,6 @@ pub mod stdout; #[cfg(feature = "sdcard")] #[cfg_attr(docsrs, doc(cfg(feature = "sdcard")))] pub mod sdcard; +#[cfg(feature = "usb")] +#[cfg_attr(docsrs, doc(cfg(feature = "usb")))] +pub mod usb; diff --git a/src/usb.rs b/src/usb.rs new file mode 100644 index 0000000..330ee02 --- /dev/null +++ b/src/usb.rs @@ -0,0 +1,34 @@ +//! On-board USB OTG FS +//! +//! - D- = PA11 +//! - D+ = PA12 + +use gd32vf103xx_hal::pac; +use gd32vf103xx_hal::rcu::Rcu; +use gd32vf103xx_hal::gpio::gpioa::{PA11, PA12}; +use gd32vf103xx_hal::gpio::Active; +pub use gd32vf103xx_hal::otg_fs::{UsbBus, UsbBusType, USB}; + +use usb_device::bus::UsbBusAllocator; + +/// Initializes USB FS bus +pub fn usb( + global: pac::USBFS_GLOBAL, + device: pac::USBFS_DEVICE, + pwrclk: pac::USBFS_PWRCLK, + pin_dm: PA11, + pin_dp: PA12, + rcu: &Rcu, + ep_mem: &'static mut [u32], +) -> UsbBusAllocator { + let usb = USB { + usb_global: global, + usb_device: device, + usb_pwrclk: pwrclk, + pin_dm: pin_dm.into_floating_input(), + pin_dp: pin_dp.into_floating_input(), + hclk: rcu.clocks.hclk(), + }; + + UsbBus::new(usb, ep_mem) +} From f327f78c2220c6cb50d43c9ebb7bf88359a36530 Mon Sep 17 00:00:00 2001 From: K Date: Sun, 5 Feb 2023 13:59:03 +0500 Subject: [PATCH 4/5] Add rv-link gdb config --- rv-link.gdb | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 rv-link.gdb diff --git a/rv-link.gdb b/rv-link.gdb new file mode 100644 index 0000000..fc2f78b --- /dev/null +++ b/rv-link.gdb @@ -0,0 +1,12 @@ +target remote /dev/ttyRvlGdb + +# print demangled symbols +set print asm-demangle on + +set confirm off + +# set backtrace limit to not have infinite backtrace loops +set backtrace limit 32 + +load +continue From 2283d008d3fa6ad593ba8acf18a61a1703110f02 Mon Sep 17 00:00:00 2001 From: K Date: Sun, 5 Feb 2023 13:59:30 +0500 Subject: [PATCH 5/5] Add build profiles to manifest --- Cargo.toml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 839e919..2e5a660 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,3 +60,23 @@ required-features = ["usb"] [[example]] name = "serial_usb" required-features = ["usb"] + +[profile.dev] +opt-level = 1 +debug = true +debug-assertions = true +overflow-checks = true +lto = false +#panic = 'unwind' +incremental = true +codegen-units = 256 + +[profile.release] +opt-level = "s" +debug = true +debug-assertions = false +overflow-checks = false +lto = true +panic = "abort" +incremental = false +codegen-units = 1