aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2022-08-11 13:40:04 -0400
committerBrian Cully <bjc@kublai.com>2022-08-11 13:40:04 -0400
commit7846e30a25dfbbb2794035894d4b9e5c0f1ef41d (patch)
tree9ad8ee61fdcccd6200396d4f9164b4ad4d823d69
parent8c1cb71bbe54301b711519267d40bf854f6fcf1f (diff)
downloadluchie-7846e30a25dfbbb2794035894d4b9e5c0f1ef41d.tar.gz
luchie-7846e30a25dfbbb2794035894d4b9e5c0f1ef41d.zip
usb peripheral now starting ‘connect()’
-rw-r--r--Cargo.lock19
-rw-r--r--Cargo.toml2
-rw-r--r--src/blink.rs10
-rw-r--r--src/log.rs4
-rwxr-xr-xsrc/main.rs36
-rw-r--r--src/usb.rs903
6 files changed, 963 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7b0fdc3..ff4e28f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -103,6 +103,8 @@ dependencies = [
"nb 1.0.0",
"riscv 0.8.0",
"riscv-rt",
+ "usb-device",
+ "usbd-serial",
]
[[package]]
@@ -285,6 +287,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
[[package]]
+name = "usb-device"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
+
+[[package]]
+name = "usbd-serial"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db75519b86287f12dcf0d171c7cf4ecc839149fe9f3b720ac4cfce52959e1dfe"
+dependencies = [
+ "embedded-hal",
+ "nb 0.1.3",
+ "usb-device",
+]
+
+[[package]]
name = "vcell"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 3a8e031..ab7756a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,6 +23,8 @@ riscv = "0.8.0"
riscv-rt = "0.9.0"
nb = "1.0.0"
embedded-hal = "0.2.7"
+usb-device = "0.2.9"
+usbd-serial = "0.1.1"
[[bin]]
name = "luchie"
diff --git a/src/blink.rs b/src/blink.rs
index 8e17b21..bb53845 100644
--- a/src/blink.rs
+++ b/src/blink.rs
@@ -6,7 +6,7 @@ use gd32vf103xx_hal::{
eclic::{self, EclicExt},
pac::{self, Interrupt},
time::Hertz,
- timer,
+ timer::{Event, Timer},
};
use nb;
@@ -18,20 +18,20 @@ enum State {
}
pub struct Task {
- timer: timer::Timer<pac::TIMER6>,
+ timer: Timer<pac::TIMER6>,
frequency: Hertz,
led: LED,
state: State,
}
impl Task {
- pub fn new(mut timer: timer::Timer<pac::TIMER6>, frequency: Hertz, led: LED) -> Self {
+ pub fn new(mut timer: Timer<pac::TIMER6>, frequency: Hertz, led: LED) -> Self {
pac::ECLIC::setup(Interrupt::TIMER6, eclic::TriggerType::RisingEdge, eclic::Level::L0, eclic::Priority::P3);
unsafe { pac::ECLIC::unmask(Interrupt::TIMER6); }
if !pac::ECLIC::is_enabled(Interrupt::TIMER6) {
panic!("timer6 interrupt not enabled");
}
- timer.listen(timer::Event::Update);
+ timer.listen(Event::Update);
Self { timer, frequency, led, state: State::ToggleLED }
}
@@ -41,6 +41,7 @@ impl Task {
State::WaitForTimer => {
if let Ok(_) = self.timer.wait() {
self.state = State::ToggleLED;
+ // self.timer.unlisten(Event::Update);
Ok(())
} else {
Err(nb::Error::WouldBlock)
@@ -50,6 +51,7 @@ impl Task {
self.led.toggle();
self.timer.start(self.frequency);
self.state = State::WaitForTimer;
+ // self.timer.listen(Event::Update);
Err(nb::Error::WouldBlock)
}
}
diff --git a/src/log.rs b/src/log.rs
index b6204d6..ddb6792 100644
--- a/src/log.rs
+++ b/src/log.rs
@@ -9,7 +9,7 @@ use riscv::interrupt::{self, Mutex};
#[macro_export]
macro_rules! log {
($($args:tt)+) => {
- $crate::log::log_args(core::format_args!($($args)+));
+ $crate::log::log_args(core::format_args!($($args)+))
}
}
@@ -17,7 +17,7 @@ macro_rules! log {
macro_rules! logln {
() => ({ kprint!("\r\n") });
($fmt: literal $(, $($arg: tt)+)?) => {
- log!(concat!($fmt, "\n") $(, $($arg)+)?);
+ log!(concat!($fmt, "\n") $(, $($arg)+)?)
}
}
diff --git a/src/main.rs b/src/main.rs
index 6cb4139..19f2b7a 100755
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,15 +4,17 @@
mod blink;
mod led;
mod log;
+mod usb;
use gd32vf103xx_hal::{
afio::AfioExt,
eclic::{self, EclicExt},
+ exti::Exti,
gpio::GpioExt,
pac::{self, Peripherals},
rcu::RcuExt,
serial::Serial,
- time::Hertz,
+ time::{Hertz, MegaHertz},
timer::Timer,
};
use riscv::{
@@ -29,10 +31,11 @@ use led::LED;
fn main(_hartid: usize) -> ! {
let p = Peripherals::take().expect("couldn't take peripherals");
+ pac::ECLIC::reset();
pac::ECLIC::set_threshold_level(eclic::Level::L0);
pac::ECLIC::set_level_priority_bits(eclic::LevelPriorityBits::L3P1);
- let mut rcu = p.RCU.configure().freeze();
+ let mut rcu = p.RCU.configure().sysclk(MegaHertz(48)).freeze();
let mut afio = p.AFIO.constrain(&mut rcu);
let gpioa = p.GPIOA.split(&mut rcu);
@@ -49,22 +52,45 @@ fn main(_hartid: usize) -> ! {
let (tx, _rx) = serial.split();
log::init(tx);
- let timer = Timer::<pac::TIMER6>::timer6(p.TIMER6, Hertz(1), &mut rcu);
+ let timer = Timer::<pac::TIMER6>::timer6(p.TIMER6, Hertz(5), &mut rcu);
let led = LED::new(gpioa.pa7);
let mut blink = blink::Task::new(timer, Hertz(5), led);
+ logln!("+++ busabus");
+ let mut exti = Exti::new(p.EXTI);
+ let bus = usb::Bus::new(p.USBFS_GLOBAL, p.USBFS_DEVICE, p.USBFS_PWRCLK, &mut rcu, &mut exti);
+ bus.init();
+ // let bus_alloc = UsbBusAllocator::new(bus);
+ // logln!("+++ devadev");
+ // let mut usb_dev = UsbDeviceBuilder::new(&bus_alloc, UsbVidPid(0xdead, 0xbeef))
+ // .manufacturer("luchie")
+ // .product("pad")
+ // .serial_number("test")
+ // .build();
+ // logln!("+++ superserious");
+ //let mut serial = SerialPort::new(&bus_alloc);
+
+ unsafe { interrupt::enable() };
+
loop {
let mut can_sleep = true;
+ log!("yo");
if let Ok(_) = blink.poll() {
can_sleep = false;
}
- log!("yo!");
- logln!(" mtv raps");
+ log!(" mtv");
+ // was: usb_dev.poll(&mut [&mut serial])
+ // if usb_dev.poll(&mut []) {
+ // can_sleep = false;
+ // }
+ log!(" raps");
if can_sleep {
+ log!("!");
unsafe { wfi() };
}
+ logln!("");
}
}
diff --git a/src/usb.rs b/src/usb.rs
new file mode 100644
index 0000000..c6920e1
--- /dev/null
+++ b/src/usb.rs
@@ -0,0 +1,903 @@
+//use embedded_hal::digital::v2::OutputPin;
+use gd32vf103xx_hal::prelude::_embedded_hal_blocking_delay_DelayMs;
+use gd32vf103xx_hal::{
+ eclic::{EclicExt, Level, Priority, TriggerType},
+ exti::{Exti, ExtiLine, InternalLine, TriggerEdge},
+ pac::{ECLIC, Interrupt, RCU, USBFS_DEVICE, USBFS_GLOBAL, USBFS_PWRCLK},
+ rcu::Rcu,
+ time::MegaHertz,
+};
+use riscv::{
+ asm::delay,
+ interrupt,
+};
+use usb_device::{
+ class_prelude::*,
+ bus::PollResult,
+ UsbDirection,
+};
+
+use crate::{log, logln};
+
+struct EPAllocation(u8);
+impl EPAllocation {
+ const MAX_ENDPOINT: usize = 4;
+
+ fn new() -> Self {
+ EPAllocation(0)
+ }
+
+ fn is_alloc(&self, index: usize) -> Result<bool, UsbError> {
+ if index < Self::MAX_ENDPOINT {
+ let test = 1 << index;
+ logln!("is_alloc: {} & {} = {}", self.0, test, self.0 & test == test);
+ Ok(self.0 & test == test)
+ } else {
+ logln!("is_alloc underflow");
+ Err(UsbError::EndpointOverflow)
+ }
+ }
+
+ fn is_free(&self, index: usize) -> Result<bool, UsbError> {
+ self.is_alloc(index).map(|v| !v)
+ }
+
+ fn alloc(&mut self, index: usize) -> Result<(), UsbError> {
+ if index < Self::MAX_ENDPOINT {
+ let test = 1 << index;
+ self.0 |= test;
+ logln!("alloc: {} & {}", self.0, test);
+ Ok(())
+ } else {
+ logln!("alloc underflow");
+ Err(UsbError::EndpointOverflow)
+ }
+ }
+
+ fn next_ep(&self) -> Result<usize, UsbError> {
+ for i in 0..Self::MAX_ENDPOINT {
+ if self.is_free(i)? {
+ logln!("next: {}", i);
+ return Ok(i)
+ }
+ }
+ logln!("next underflow");
+ Err(UsbError::EndpointOverflow)
+ }
+
+ fn iter(&self) -> EPAllocationIter {
+ EPAllocationIter { i: 0, alloc: self }
+ }
+}
+
+struct EPAllocationIter<'a> {
+ i: u8,
+ alloc: &'a EPAllocation,
+}
+
+impl Iterator for EPAllocationIter<'_> {
+ type Item = u8;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ while let Ok(is_alloc) = self.alloc.is_alloc(self.i.into()) {
+ self.i += 1;
+ if is_alloc {
+ return Some(self.i - 1);
+ }
+ }
+ None
+ }
+}
+
+pub struct Bus {
+ usbg: USBFS_GLOBAL,
+ usbd: USBFS_DEVICE,
+ usbpwr: USBFS_PWRCLK,
+
+ ep_in_alloc: EPAllocation,
+ ep_out_alloc: EPAllocation,
+}
+
+fn rcu_config(rcu: &mut Rcu) {
+ let system_clock = rcu.clocks.sysclk();
+ let psc: u8 = if system_clock == MegaHertz(48).into() {
+ logln!("48mhz");
+ 0b01
+ } else if system_clock == MegaHertz(72).into() {
+ logln!("72mhz");
+ 0b00
+ } else if system_clock == MegaHertz(96).into() {
+ logln!("96mhz");
+ 0b11
+ } else {
+ logln!("clk: {}", system_clock.0);
+ 0b01
+ };
+ // rcu_usb_clock_config(psc)
+ let rcup = unsafe { &*RCU::ptr() };
+ rcup.cfg0.modify(|_, w| unsafe { w.usbfspsc().bits(psc) });
+
+ // Enable USB peripheral
+ rcup.ahben.modify(|_, w| w.usbfsen().set_bit());
+ // Reset USB peripheral
+ // rcup.ahbrst.modify(|_, w| w.usbfsrst().set_bit());
+ // rcup.ahbrst.modify(|_, w| w.usbfsrst().clear_bit());
+
+}
+
+fn intr_config(exti: &mut Exti) {
+ ECLIC::setup(Interrupt::USBFS, TriggerType::RisingEdge, Level::L1, Priority::P0);
+
+ let rcup = unsafe { &*RCU::ptr() };
+
+ // Enable PMU clock
+ rcup.apb1en.modify(|_, w| w.pmuen().set_bit());
+
+ // Reset USB peripheral
+ rcup.apb1rst.modify(|_, w| w.pmurst().set_bit());
+ rcup.apb1rst.modify(|_, w| w.pmurst().clear_bit());
+
+ let line = ExtiLine::from_internal_line(InternalLine::UsbWakeup);
+ Exti::clear(line);
+ exti.listen(line, TriggerEdge::Rising);
+
+ ECLIC::setup(Interrupt::USBFS_WKUP, TriggerType::RisingEdge, Level::L1, Priority::P0);
+
+ unsafe {
+ ECLIC::unmask(Interrupt::USBFS);
+ ECLIC::unmask(Interrupt::USBFS_WKUP);
+ }
+}
+
+impl Bus {
+ pub fn new(
+ usbg: USBFS_GLOBAL,
+ usbd: USBFS_DEVICE,
+ usbpwr: USBFS_PWRCLK,
+ rcu: &mut Rcu,
+ exti: &mut Exti,
+ ) -> Self {
+ /*
+ eclic_global_interrupt_enable();
+
+ eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL2_PRIO2);
+
+ usb_rcu_config();
+
+ usb_timer_init();
+
+ usb_intr_config();
+
+ usbd_init (&USB_OTG_dev, USB_CORE_ENUM_FS, &usbd_cdc_cb);
+
+ */
+ rcu_config(rcu);
+
+ intr_config(exti);
+
+ let ep_in_alloc = EPAllocation::new();
+ let ep_out_alloc = EPAllocation::new();
+ Self { usbg, usbd, usbpwr, ep_in_alloc, ep_out_alloc }
+ }
+
+ fn basic_init(&self) {
+ // transfer_mode = use_fifo
+ // core_speed = full
+ // core_enum = 1 (FS) (HS is 0)
+ // reg_base = USBFS_REG_BASE;
+
+ /* set the host channel numbers */
+ // usb_basic->num_pipe = USBFS_MAX_CHANNEL_COUNT;
+
+ // /* set the device endpoint numbers */
+ // usb_basic->num_ep = USBFS_MAX_EP_COUNT;
+
+ // /* USBFS core use embedded physical layer */
+ // usb_basic->phy_itf = USB_EMBEDDED_PHY;
+ // usb_basic->sof_enable = USB_SOF_OUTPUT; /* 1 in cdcacm */
+ // usb_basic->low_power = USB_LOW_POWER; /* 1 in cdcacm */
+ }
+
+ fn mdelay(d: u32) {
+ let mut delay = riscv::delay::McycleDelay::new(108_000);
+ delay.delay_ms(d);
+ }
+
+ fn udelay(d: u32) {
+ let mut delay = riscv::delay::McycleDelay::new(108);
+ delay.delay_ms(d);
+ }
+
+ fn core_reset(&self) {
+ self.usbg.grstctl.modify(|_, w| w.csrst().set_bit());
+ while self.usbg.grstctl.read().csrst().bit_is_set() {}
+ Self::udelay(3);
+ }
+
+ fn core_init(&self) {
+ self.usbg.gahbcs.modify(|_, w| w.ginten().clear_bit());
+ // this sets a reserved field to a magic value, and i hope
+ // it's not neccessary.
+ self.usbg.gusbcs.modify(|r, w| unsafe { w.bits(r.bits() | 1 << 6) });
+ logln!("-> core_reset");
+ self.core_reset();
+ logln!("<- core_reset");
+ self.usbg.gccfg.modify(|_, w| {
+ w
+ .pwron().set_bit()
+ .vbusacen().set_bit()
+ .vbusbcen().set_bit()
+ .sofoen().set_bit()
+ });
+
+ Self::mdelay(20);
+ }
+
+ fn devdisconnect(&self) {
+ self.usbd.dctl.modify(|_, w| w.sd().set_bit());
+ }
+
+ fn disconnect(&self) {
+ self.devdisconnect();
+ Self::mdelay(3);
+ }
+
+ // 32 bit words
+ const RX_FIFO_SIZE: u16 = 128;
+ const TX_FIFO_SIZE: [u16; 4] = [64, 128, 0, 0];
+
+ fn devint_enable(&self) {
+ self.usbg.gotgintf.write(|w| unsafe { w.bits(0xffff_ffffu32) });
+ self.usbg.gintf.write(|w| unsafe { w.bits(0xbfff_ffffu32) });
+ self.usbg.ginten.modify(|_, w| {
+ w
+ .wkupie().set_bit()
+ .spie().set_bit()
+ .rxfneie().set_bit()
+ .rstie().set_bit()
+ .enumfie().set_bit()
+ .iepie().set_bit()
+ .oepie().set_bit()
+ .sofie().set_bit()
+ .mfie().set_bit()
+ });
+ self.usbg.gahbcs.modify(|_, w| w.ginten().set_bit());
+ }
+
+ fn txfifo_flush(&self, fifo_num: u8) {
+ self.usbg.grstctl.modify(|_, w| {
+ unsafe {
+ w
+ .txfnum().bits(fifo_num)
+ .txff().set_bit()
+ }
+ });
+ while self.usbg.grstctl.read().txff().bit_is_set() {}
+
+ Self::mdelay(3);
+ }
+
+ fn rxfifo_flush(&self) {
+ self.usbg.grstctl.modify(|_, w| w.txff().set_bit());
+ while self.usbg.grstctl.read().txff().bit_is_set() {}
+
+ Self::mdelay(3);
+ }
+
+ fn devcore_init(&self) {
+ self.usbg.gusbcs.modify(|_, w| {
+ w
+ .fdm().clear_bit()
+ .fhm().clear_bit()
+ });
+ self.usbg.gusbcs.modify(|_, w| w.fdm().set_bit());
+ self.usbpwr.pwrclkctl.modify(|_, w| unsafe { w.bits(0) });
+ self.usbd.dcfg.modify(|_, w| {
+ unsafe {
+ w
+ .eopft().bits(0)
+ .ds().bits(0b11)
+ }
+ });
+ self.usbg.grflen.modify(|_, w| unsafe { w.rxfd().bits(Self::RX_FIFO_SIZE)});
+ self.usbg.hnptflen().modify(|_, w| {
+ unsafe {
+ w
+ .hnptxfd().bits(Self::TX_FIFO_SIZE[0])
+ .hnptxrsar().bits(Self::RX_FIFO_SIZE)
+ }
+ });
+ let mut ram_addr = Self::RX_FIFO_SIZE;
+
+ ram_addr += Self::TX_FIFO_SIZE[0];
+ self.usbg.diep1tflen.modify(|_, w| {
+ unsafe {
+ w
+ .ieptxfd().bits(Self::TX_FIFO_SIZE[1])
+ .ieptxrsar().bits(ram_addr)
+ }
+ });
+ ram_addr += Self::TX_FIFO_SIZE[1];
+ self.usbg.diep1tflen.modify(|_, w| {
+ unsafe {
+ w
+ .ieptxfd().bits(Self::TX_FIFO_SIZE[2])
+ .ieptxrsar().bits(ram_addr)
+ }
+ });
+ ram_addr += Self::TX_FIFO_SIZE[2];
+ self.usbg.diep1tflen.modify(|_, w| {
+ unsafe {
+ w
+ .ieptxfd().bits(Self::TX_FIFO_SIZE[3])
+ .ieptxrsar().bits(ram_addr)
+ }
+ });
+
+ self.txfifo_flush(0x10);
+ self.rxfifo_flush();
+
+ self.usbd.diepinten.modify(|_, w| unsafe { w.bits(0) });
+ self.usbd.doepinten.modify(|_, w| unsafe { w.bits(0) });
+ self.usbd.daepinten.modify(|_, w| unsafe { w.bits(0) });
+ // read-only in the pac and datasheet
+ //self.usbd.daepint.modify(|_, w| unsafe { w.bits(0xffff_ffffu32) });
+
+ if self.usbd.diep0ctl.read().epen().bit_is_set() {
+ self.usbd.diep0ctl.modify(|_, w| w.epd().set_bit().snak().set_bit());
+ } else {
+ self.usbd.diep0ctl.write(|w| unsafe { w.bits(0) });
+ }
+ self.usbd.diep0len.write(|w| unsafe { w.bits(0) });
+ self.usbd.diep0intf.write(|w| unsafe { w.bits(0xff) });
+
+ if self.usbd.doep0ctl.read().epen().bit_is_set() {
+ self.usbd.doep0ctl.modify(|_, w| w.snak().set_bit());
+ } else {
+ self.usbd.doep0ctl.write(|w| unsafe { w.bits(0) });
+ }
+ self.usbd.doep0len.write(|w| unsafe { w.bits(0) });
+ self.usbd.doep0intf.write(|w| unsafe { w.bits(0xff) });
+
+ if self.usbd.diep1ctl.read().epen().bit_is_set() {
+ self.usbd.diep1ctl.modify(|_, w| w.epd().set_bit().snak().set_bit());
+ } else {
+ self.usbd.diep1ctl.write(|w| unsafe { w.bits(0) });
+ }
+ self.usbd.diep1len.write(|w| unsafe { w.bits(0) });
+ self.usbd.diep1intf.write(|w| unsafe { w.bits(0xff) });
+
+ if self.usbd.doep1ctl.read().epen().bit_is_set() {
+ self.usbd.doep1ctl.modify(|_, w| w.epd().set_bit().snak().set_bit());
+ } else {
+ self.usbd.doep1ctl.write(|w| unsafe { w.bits(0) });
+ }
+ self.usbd.doep1len.write(|w| unsafe { w.bits(0) });
+ self.usbd.doep1intf.write(|w| unsafe { w.bits(0xff) });
+
+ if self.usbd.diep2ctl.read().epen().bit_is_set() {
+ self.usbd.diep2ctl.modify(|_, w| w.epd().set_bit().snak().set_bit());
+ } else {
+ self.usbd.diep2ctl.write(|w| unsafe { w.bits(0) });
+ }
+ self.usbd.diep2len.write(|w| unsafe { w.bits(0) });
+ self.usbd.diep2intf.write(|w| unsafe { w.bits(0xff) });
+
+ if self.usbd.doep2ctl.read().epen().bit_is_set() {
+ self.usbd.doep2ctl.modify(|_, w| w.epd().set_bit().snak().set_bit());
+ } else {
+ self.usbd.doep2ctl.write(|w| unsafe { w.bits(0) });
+ }
+ self.usbd.doep2len.write(|w| unsafe { w.bits(0) });
+ self.usbd.doep2intf.write(|w| unsafe { w.bits(0xff) });
+
+ if self.usbd.diep3ctl.read().epen().bit_is_set() {
+ self.usbd.diep3ctl.modify(|_, w| w.epd().set_bit().snak().set_bit());
+ } else {
+ self.usbd.diep3ctl.write(|w| unsafe { w.bits(0) });
+ }
+ self.usbd.diep3len.write(|w| unsafe { w.bits(0) });
+ self.usbd.diep3intf.write(|w| unsafe { w.bits(0xff) });
+
+ if self.usbd.doep3ctl.read().epen().bit_is_set() {
+ self.usbd.doep3ctl.modify(|_, w| w.epd().set_bit().snak().set_bit());
+ } else {
+ self.usbd.doep3ctl.write(|w| unsafe { w.bits(0) });
+ }
+ self.usbd.doep3len.write(|w| unsafe { w.bits(0) });
+ self.usbd.doep3intf.write(|w| unsafe { w.bits(0xff) });
+
+
+ self.devint_enable();
+ }
+
+ fn devconnect(&self) {
+ self.usbd.dctl.modify(|_, w| w.sd().clear_bit());
+ }
+
+ fn connect(&self) {
+ self.devconnect();
+ Self::mdelay(3);
+ }
+
+ pub fn init(&self) {
+ logln!("!!! basic_init");
+ self.basic_init();
+ logln!("!!! core_init");
+ self.core_init();
+ logln!("!!! disconnect");
+ self.disconnect();
+ logln!("!!! devcore_init");
+ self.devcore_init();
+ logln!("!!! connect");
+ self.connect();
+
+ // cur_status = default;
+ }
+}
+
+unsafe impl Sync for Bus {}
+
+fn mpl_from_int(i: usize) -> Result<u8, UsbError> {
+ match i {
+ 64 => Ok(0b00),
+ 32 => Ok(0b01),
+ 16 => Ok(0b10),
+ 8 => Ok(0b11),
+ _ => Err(UsbError::Unsupported),
+ }
+}
+
+trait ToBits {
+ type Width;
+ fn to_bits(&self) -> Self::Width;
+}
+
+impl ToBits for EndpointType {
+ type Width = u8;
+
+ fn to_bits(&self) -> Self::Width {
+ match self {
+ EndpointType::Control => 0b00,
+ EndpointType::Isochronous => 0b01,
+ EndpointType::Bulk => 0b10,
+ EndpointType::Interrupt => 0b11,
+ }
+ }
+}
+
+impl UsbBus for Bus {
+ // TODO: just allocate. enable() is called after this and can
+ // enable the endpoints. gets called with ep0
+ fn alloc_ep(
+ &mut self,
+ dir: UsbDirection,
+ ep_addr: Option<EndpointAddress>,
+ ep_type: EndpointType,
+ max_packet_size: u16,
+ _interval: u8
+ ) -> Result<EndpointAddress, UsbError> {
+ logln!("--- alloc_ep {:?} {:?} {:?} {}", dir, ep_addr, ep_type, max_packet_size);
+ let fd = self.usbg.hptflen.read().hptxfd().bits();
+ let sar = self.usbg.hptflen.read().hptxfsar().bits();
+ logln!("fd: 0x{:08x} sar: 0x{:08x}", fd, sar);
+ let ep_alloc = if dir == UsbDirection::Out {
+ &mut self.ep_out_alloc
+ } else {
+ &mut self.ep_in_alloc
+ };
+ interrupt::free(|_cs| {
+ let mpl = mpl_from_int(max_packet_size as usize)?;
+ let next = {
+ let a = ep_alloc.next_ep()?;
+ EndpointAddress::from_parts(a, dir)
+ };
+ let addr = match ep_addr {
+ None => next,
+ Some(a) => {
+ if ep_alloc.is_free(a.index())? {
+ a
+ } else {
+ return Err(UsbError::InvalidEndpoint);
+ }
+ },
+ };
+ let eptype = ep_type.to_bits();
+ // i yield! i can think of no good way to cover all cases
+ // without macros.
+ unsafe {
+ logln!("checking dir/idx");
+ match (dir, addr.index()) {
+ (_, 0) => {
+ let nfd = self.usbg.diep0tflen().read().iep0txfd().bits();
+ let nsar = self.usbg.diep0tflen().read().iep0txrsar().bits();
+ logln!("{}ifd: 0x{:08x} sar: 0x{:08x}", 0, nfd, nsar);
+ self.usbd.diep0ctl.modify(|_, w| {
+ w
+ .bits(mpl.into())
+ .epen().clear_bit()
+ });
+
+ self.usbd.doep0ctl.modify(|_, w| {
+ w
+ .bits(mpl.into())
+ .epen().clear_bit()
+ });
+ }
+
+ (UsbDirection::In, 1) => {
+ let nfd = self.usbg.diep1tflen.read().ieptxfd().bits();
+ let nsar = self.usbg.diep1tflen.read().ieptxrsar().bits();
+ logln!("{}ifd: 0x{:08x} sar: 0x{:08x}", 1, nfd, nsar);
+ self.usbd.diep1ctl.modify(|_, w| {
+ w
+ .eptype().bits(eptype)
+ .mpl().bits(mpl.into())
+ .epen().clear_bit()
+ });
+ }
+ (UsbDirection::Out, 1) => {
+ self.usbd.doep1ctl.modify(|_, w| {
+ w
+ .eptype().bits(eptype)
+ .mpl().bits(mpl.into())
+ .epen().clear_bit()
+ });
+ }
+ (UsbDirection::In, 2) => {
+ let nfd = self.usbg.diep2tflen.read().ieptxfd().bits();
+ let nsar = self.usbg.diep2tflen.read().ieptxrsar().bits();
+ logln!("{}ifd: 0x{:08x} sar: 0x{:08x}", 2, nfd, nsar);
+ self.usbd.diep2ctl.modify(|_, w| {
+ w
+ .eptype().bits(eptype)
+ .mpl().bits(mpl.into())
+ .epen().clear_bit()
+ });
+ }
+ (UsbDirection::Out, 2) => {
+ self.usbd.doep2ctl.modify(|_, w| {
+ w
+ .eptype().bits(eptype)
+ .mpl().bits(mpl.into())
+ .epen().clear_bit()
+ });
+ }
+ (UsbDirection::In, 3) => {
+ let nfd = self.usbg.diep3tflen.read().ieptxfd().bits();
+ let nsar = self.usbg.diep3tflen.read().ieptxrsar().bits();
+ logln!("{}ifd: 0x{:08x} sar: 0x{:08x}", 3, nfd, nsar);
+ self.usbd.diep3ctl.modify(|_, w| {
+ w
+ .eptype().bits(eptype)
+ .mpl().bits(mpl.into())
+ .epen().clear_bit()
+ });
+ }
+ (UsbDirection::Out, 3) => {
+ self.usbd.doep3ctl.modify(|_, w| {
+ w
+ .eptype().bits(eptype)
+ .mpl().bits(mpl.into())
+ .epen().clear_bit()
+ });
+ }
+ (dir, ep) => {
+ logln!("--- couldn't alloc ep for {:?} {}", dir, ep);
+ return Err(UsbError::EndpointOverflow)
+ },
+ }
+ }
+
+ ep_alloc.alloc(addr.index())?;
+ logln!("--- allocated ep for {:?} {}", dir, addr.index());
+ Ok(addr)
+ })
+ }
+
+ // reset() is called after this. start enumeration there
+ fn enable(&mut self) {
+ logln!("--- enable");
+ interrupt::free(|_cs| {
+ // power off the bus
+ self.usbg.gccfg.modify(|_, w| w.pwron().clear_bit());
+
+ self.usbg.gahbcs.modify(|_, w| w.ginten().clear_bit());
+
+ // See: [[file:~/src/GD32VF103_Firmware_Library/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_regs.h::define GUSBCS_EMBPHY BIT(6) /*!< embedded PHY selected */]] and [[file:~/src/GD32VF103_Firmware_Library/Firmware/GD32VF103_usbfs_driver/Source/drv_usb_core.c::usb_regs->gr->GUSBCS |= GUSBCS_EMBPHY;]]
+ // GUSBCS_EMBPHY ?? bit 6
+ self.usbg.gusbcs.modify(|r, w| unsafe { w.bits(r.bits() | 1 << 6) });
+
+ // usb_core_reset
+ self.usbg.grstctl.modify(|_, w| w.csrst().set_bit());
+ while self.usbg.grstctl.read().csrst().bit_is_set() {}
+ unsafe { delay(108_000 * 3) };
+
+ self.usbg.gccfg.modify(|_, w| {
+ w
+ .pwron().set_bit()
+ .vbusacen().set_bit()
+ .vbusbcen().set_bit()
+ .sofoen().set_bit()
+ });
+
+ // delay 20ms
+ unsafe { delay(108_000 * 20) };
+
+ // RST should trigger when the host notices the device,
+ // which will proceed to ‘reset()’
+ });
+ logln!("--- enable: done");
+ }
+
+ // everything is allocated, the device is enabled. now reset
+ // everything to begin enumeration
+ fn reset(&self) {
+ logln!("--- reset");
+ // program d[oi]ep[0123]ctl
+ // d[oi]epinten
+ // d[oi]eplen
+ // set epen in ctl reg
+
+ interrupt::free(|_cs| {
+ for ep in self.ep_out_alloc.iter() {
+ match ep {
+ 0 => self.usbd.doep0ctl.modify(|_, w| w.epen().set_bit()),
+ 1 => self.usbd.doep1ctl.modify(|_, w| w.epen().set_bit()),
+ 2 => self.usbd.doep2ctl.modify(|_, w| w.epen().set_bit()),
+ 3 => self.usbd.doep3ctl.modify(|_, w| w.epen().set_bit()),
+ _ => (),
+ }
+ }
+
+ for ep in self.ep_in_alloc.iter() {
+ match ep {
+ 0 => self.usbd.diep0ctl.modify(|_, w| w.epen().set_bit()),
+ 1 => self.usbd.diep1ctl.modify(|_, w| w.epen().set_bit()),
+ 2 => self.usbd.diep2ctl.modify(|_, w| w.epen().set_bit()),
+ 3 => self.usbd.diep3ctl.modify(|_, w| w.epen().set_bit()),
+ _ => (),
+ }
+ }
+
+ // wait for enum interrupt in gintf register
+ });
+ }
+
+ fn set_device_address(&self, address: u8) {
+ logln!("--- set_device_address");
+ interrupt::free(|_cs| {
+ self.usbd.dcfg.modify(|_, w| unsafe { w.dar().bits(address & 7) });
+ });
+ }
+
+ fn write(&self, _ep_addr: EndpointAddress, buf: &[u8]) -> Result<usize, UsbError> {
+ logln!("--- write");
+ assert!(buf.as_ptr() as u8 & 0b11 == 0);
+ interrupt::free(|_cs| {
+ // new - set ep fifo
+ self.usbg.diep1tflen.modify(|_, w| {
+ unsafe {
+ w
+ // depth (in 32 bit words)
+ .ieptxfd().bits((buf.len() >> 2).try_into().unwrap())
+ // ram start address (in 32 bit words)
+ .ieptxrsar().bits((buf.as_ptr() as usize >> 2).try_into().unwrap())
+ }
+ });
+ });
+ Err(UsbError::WouldBlock)
+ }
+
+ fn read(&self, ep_addr: EndpointAddress, _buf: &mut [u8]) -> Result<usize, UsbError> {
+ logln!("--- read");
+ interrupt::free(|_cs| {
+ match ep_addr.index() {
+ 0 => {
+ let v = &self.usbd.doep0len;
+ logln!(" 0tlen: {}", v.read().tlen().bits());
+ logln!(" 0pcnt: {}", v.read().pcnt().bits());
+ logln!(" 0stpcnt: {}", v.read().stpcnt().bits());
+ },
+ 1 => {
+ let v = &self.usbd.doep1len;
+ logln!(" 1tlen: {}", v.read().tlen().bits());
+ logln!(" 1pcnt: {}", v.read().pcnt().bits());
+ logln!(" 1stpcnt_rxdpid: {}", v.read().stpcnt_rxdpid().bits());
+ },
+ 2 => {
+ let v = &self.usbd.doep1len;
+ logln!(" 2tlen: {}", v.read().tlen().bits());
+ logln!(" 2pcnt: {}", v.read().pcnt().bits());
+ logln!(" 2stpcnt_rxdpid: {}", v.read().stpcnt_rxdpid().bits());
+ },
+ 3 => {
+ let v = &self.usbd.doep1len;
+ logln!(" 3tlen: {}", v.read().tlen().bits());
+ logln!(" 3pcnt: {}", v.read().pcnt().bits());
+ logln!(" 3stpcnt_rxdpid: {}", v.read().stpcnt_rxdpid().bits());
+ },
+ ep => logln!(" bad ep {}", ep),
+ };
+
+ // rx fifo through grstatr/grstatp
+ let ep = usize::from(self.usbg.grstatr_device().read().epnum().bits());
+ let packet_waiting = self.usbg.grstatr_device().read().rpckst().bits() != 1;
+ logln!(" grstatr: {}", self.usbg.grstatr_device().read().bits());
+ logln!(" bcountn: {}", self.usbg.grstatr_device().read().bcount().bits());
+ logln!(" dpid: {}", self.usbg.grstatr_device().read().dpid().bits());
+ logln!(" rpckst: {}", self.usbg.grstatr_device().read().rpckst().bits());
+ logln!(" ep: {}, waiting: {}", ep, packet_waiting);
+ if packet_waiting && ep == ep_addr.index() {
+ logln!(" pkt match");
+ Ok(0)
+ } else {
+ logln!(" wouldblock");
+ Err(UsbError::WouldBlock)
+ }
+ })
+ }
+
+ fn set_stalled(&self, ep_addr: EndpointAddress, _stalled: bool) {
+ logln!("--- set_stalled");
+ let ep = ep_addr.index();
+ interrupt::free(|_cs| {
+ if ep_addr.direction() == UsbDirection::Out {
+ if self.ep_out_alloc.is_alloc(ep).is_ok() {
+ match ep {
+ 0 => self.usbd.doep0ctl.modify(|_, w| w.stall().set_bit()),
+ 1 => self.usbd.doep1ctl.modify(|_, w| w.stall().set_bit()),
+ 2 => self.usbd.doep2ctl.modify(|_, w| w.stall().set_bit()),
+ 3 => self.usbd.doep3ctl.modify(|_, w| w.stall().set_bit()),
+ _ => (),
+ }
+ }
+ } else if let Ok(_) = self.ep_in_alloc.is_alloc(ep) {
+ match ep {
+ 0 => self.usbd.diep0ctl.modify(|_, w| w.epd().set_bit().stall().set_bit()),
+ 1 => self.usbd.diep1ctl.modify(|_, w| w.epd().set_bit().stall().set_bit()),
+ 2 => self.usbd.diep2ctl.modify(|_, w| w.epd().set_bit().stall().set_bit()),
+ 3 => self.usbd.diep3ctl.modify(|_, w| w.epd().set_bit().stall().set_bit()),
+ _ => (),
+ }
+ }
+ })
+ }
+
+ fn is_stalled(&self, ep_addr: EndpointAddress) -> bool {
+ logln!("--- is_stalled");
+ let ep = ep_addr.index();
+ interrupt::free(|_cs| {
+ if ep_addr.direction() == UsbDirection::Out {
+ if self.ep_out_alloc.is_alloc(ep).is_ok() {
+ match ep {
+ 0 => self.usbd.doep0ctl.read().stall().bit_is_set(),
+ 1 => self.usbd.doep1ctl.read().stall().bit_is_set(),
+ 2 => self.usbd.doep2ctl.read().stall().bit_is_set(),
+ 3 => self.usbd.doep3ctl.read().stall().bit_is_set(),
+ _ => false,
+ }
+ } else {
+ false
+ }
+ } else if let Ok(_) = self.ep_in_alloc.is_alloc(ep) {
+ match ep {
+ 0 => self.usbd.diep0ctl.read().stall().bit_is_set(),
+ 1 => self.usbd.diep1ctl.read().stall().bit_is_set(),
+ 2 => self.usbd.diep2ctl.read().stall().bit_is_set(),
+ 3 => self.usbd.diep3ctl.read().stall().bit_is_set(),
+ _ => false,
+ }
+ } else {
+ false
+ }
+ })
+ }
+
+ fn suspend(&self) {
+ logln!("--- suspend");
+ /*
+ __IO uint32_t devstat = udev->regs.dr->DSTAT;
+
+ if ((udev->bp.low_power) && (devstat & DSTAT_SPST)) {
+ /* switch-off the USB clocks */
+ *udev->regs.PWRCLKCTL |= PWRCLKCTL_SHCLK;
+
+ /* enter DEEP_SLEEP mode with LDO in low power mode */
+ pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, WFI_CMD);
+ }
+ */
+ }
+
+ fn resume(&self) {
+ logln!("--- resume");
+ /*
+ if (USB_OTG_dev.bp.low_power) {
+ SystemInit();
+
+ rcu_usb_clock_config(usbfs_prescaler);
+
+ rcu_periph_clock_enable(RCU_USBFS);
+
+ usb_clock_active(&USB_OTG_dev);
+ }
+
+ exti_interrupt_flag_clear(EXTI_18);
+
+ */
+ }
+
+ fn poll(&self) -> PollResult {
+ logln!("--- poll");
+ let res = interrupt::free(|_cs| {
+ let intf = self.usbg.gintf.read();
+ if intf.rst().bit_is_set() {
+ PollResult::Reset
+ } else if intf.sp().bit_is_set() {
+ PollResult::Suspend
+ } else if intf.wkupif().bit_is_set() {
+ PollResult::Resume
+ } else {
+ let statd = self.usbg.grstatr_device().read();
+ let mut ep_setup = 0;
+ let mut ep_out = 0;
+ let mut ep_in_complete = 0;
+
+ // TODO: i don't know of any other way to see if there's a
+ // pending setup packet
+ if statd.rpckst().bits() != 1 {
+ let ep = statd.epnum().bits();
+ let is_setup = statd.rpckst().bits() & 0b10 == 0b10;
+ if is_setup {
+ ep_setup |= 1 << ep;
+ } else {
+ ep_out |= 1 << ep;
+ }
+ }
+
+ if self.usbd.doep0intf.read().tf().bit_is_set() {
+ ep_out |= 1 << 0;
+ }
+ if self.usbd.doep1intf.read().tf().bit_is_set() {
+ ep_out |= 1 << 1;
+ }
+ if self.usbd.doep2intf.read().tf().bit_is_set() {
+ ep_out |= 1 << 2;
+ }
+ if self.usbd.doep3intf.read().tf().bit_is_set() {
+ ep_out |= 1 << 3;
+ }
+
+ if self.usbd.diep0intf.read().tf().bit_is_set() {
+ ep_in_complete |= 1 << 0;
+ }
+ if self.usbd.diep1intf.read().tf().bit_is_set() {
+ ep_in_complete |= 1 << 1;
+ }
+ if self.usbd.diep2intf.read().tf().bit_is_set() {
+ ep_in_complete |= 1 << 2;
+ }
+ if self.usbd.diep3intf.read().tf().bit_is_set() {
+ ep_in_complete |= 1 << 3;
+ }
+
+ if ep_setup != 0 || ep_out != 0 || ep_in_complete != 0 {
+ PollResult::Data { ep_out, ep_in_complete, ep_setup }
+ } else {
+ PollResult::None
+ }
+ }
+ });
+
+ log!("+++ poll: ");
+ match res {
+ PollResult::Reset => logln!("reset"),
+ PollResult::Suspend=> logln!("suspend"),
+ PollResult::Resume => logln!("resume"),
+ PollResult::Data{ep_out, ep_in_complete, ep_setup} => logln!("data(out: {}, in: {}, setup: {})", ep_out, ep_in_complete, ep_setup),
+ PollResult::None => logln!("none"),
+ }
+
+ res
+ }
+}