From 7846e30a25dfbbb2794035894d4b9e5c0f1ef41d Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Thu, 11 Aug 2022 13:40:04 -0400 Subject: =?UTF-8?q?usb=20peripheral=20now=20starting=20=E2=80=98connect()?= =?UTF-8?q?=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 19 ++ Cargo.toml | 2 + src/blink.rs | 10 +- src/log.rs | 4 +- src/main.rs | 36 ++- src/usb.rs | 903 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 963 insertions(+), 11 deletions(-) create mode 100644 src/usb.rs 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]] @@ -284,6 +286,23 @@ version = "1.0.3" 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" 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, + timer: Timer, frequency: Hertz, led: LED, state: State, } impl Task { - pub fn new(mut timer: timer::Timer, frequency: Hertz, led: LED) -> Self { + pub fn new(mut timer: Timer, 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::::timer6(p.TIMER6, Hertz(1), &mut rcu); + let timer = Timer::::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 { + 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 { + 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 { + 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 { + 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 { + 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, + ep_type: EndpointType, + max_packet_size: u16, + _interval: u8 + ) -> Result { + 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 { + 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 { + 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 + } +} -- cgit v1.2.3