From 708eff5218dadd069e48e831e44e51c78afa2b9a Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Fri, 17 Dec 2021 17:38:02 +1100 Subject: [PATCH 01/15] Set the odd/even frame bits for isochronous EPs --- src/endpoint.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/endpoint.rs b/src/endpoint.rs index 2860b33..5810f81 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -1,7 +1,8 @@ +use usb_device::class_prelude::EndpointType; use usb_device::{Result, UsbError, UsbDirection}; use usb_device::endpoint::EndpointAddress; use crate::endpoint_memory::{EndpointBuffer, EndpointBufferState}; -use crate::ral::{read_reg, write_reg, modify_reg, endpoint_in, endpoint_out, endpoint0_out}; +use crate::ral::{read_reg, write_reg, modify_reg, endpoint_in, endpoint_out, endpoint0_out, otg_device}; use crate::target::{fifo_write, UsbRegisters}; use crate::target::interrupt::{self, CriticalSection, Mutex}; use core::ops::{Deref, DerefMut}; @@ -121,6 +122,7 @@ impl EndpointIn { pub fn write(&self, buf: &[u8]) -> Result<()> { let ep = self.usb.endpoint_in(self.index() as usize); + let device = self.usb.device(); if self.index() != 0 && read_reg!(endpoint_in, ep, DIEPCTL, EPENA) != 0{ return Err(UsbError::WouldBlock); } @@ -137,6 +139,23 @@ impl EndpointIn { } } + match self.descriptor.ep_type { + // Isochronous endpoints must set the correct even/odd frame bit to + // correspond with the next frame's number. + EndpointType::Isochronous(_) => { + // Previous frame number is OTG_DSTS.FNSOF + let frame_number = read_reg!(otg_device, device, DSTS, FNSOF); + if frame_number & 0x1 == 1 { + // Previous frame number is odd, so upcoming frame is even + modify_reg!(endpoint_in, ep, DIEPCTL, SD0PID_SEVNFRM: 1); + } else { + // Previous frame number is even, so upcoming frame is odd + modify_reg!(endpoint_in, ep, DIEPCTL, SODDFRM_SD1PID: 1); + } + }, + _ => {} + } + #[cfg(feature = "fs")] write_reg!(endpoint_in, ep, DIEPTSIZ, PKTCNT: 1, XFRSIZ: buf.len() as u32); #[cfg(feature = "hs")] @@ -205,6 +224,26 @@ impl EndpointOut { } pub fn read(&self, buf: &mut [u8]) -> Result { + let ep = self.usb.endpoint_out(self.index() as usize); + let device = self.usb.device(); + + match self.descriptor.ep_type { + // Isochronous endpoints must set the correct even/odd frame bit to + // correspond with the next frame's number. + EndpointType::Isochronous(_) => { + // Previous frame number is OTG_DSTS.FNSOF + let frame_number = read_reg!(otg_device, device, DSTS, FNSOF); + if frame_number & 0x1 == 1 { + // Previous frame number is odd, so upcoming frame is even + modify_reg!(endpoint_out, ep, DOEPCTL, SD0PID_SEVNFRM: 1); + } else { + // Previous frame number is even, so upcoming frame is odd + modify_reg!(endpoint_out, ep, DOEPCTL, SODDFRM: 1); + } + }, + _ => {} + } + interrupt::free(|cs| { self.buffer.borrow(cs).borrow_mut().read_packet(buf) }) From 74b7d4d35c768b666c856d2c79170aa9cda56073 Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Fri, 17 Dec 2021 17:38:21 +1100 Subject: [PATCH 02/15] Compatibility with usb_device isochronous PR --- src/endpoint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/endpoint.rs b/src/endpoint.rs index 5810f81..b49a730 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -93,7 +93,7 @@ impl EndpointIn { write_reg!(endpoint_in, regs, DIEPCTL, SNAK: 1, USBAEP: 1, - EPTYP: self.descriptor.ep_type as u32, + EPTYP: self.descriptor.ep_type.to_bm_attributes() as u32, SD0PID_SEVNFRM: 1, TXFNUM: self.index() as u32, MPSIZ: self.descriptor.max_packet_size as u32 @@ -202,7 +202,7 @@ impl EndpointOut { CNAK: 1, EPENA: 1, USBAEP: 1, - EPTYP: self.descriptor.ep_type as u32, + EPTYP: self.descriptor.ep_type.to_bm_attributes() as u32, MPSIZ: self.descriptor.max_packet_size as u32 ); } From b9916302045be1ce0a9ec9f14ba95a9d81292cbe Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Thu, 13 Jan 2022 12:16:37 +1100 Subject: [PATCH 03/15] Delay by 25600 cycles after selecting USB PHY --- src/bus.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bus.rs b/src/bus.rs index 8b510ba..eeef352 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -431,6 +431,13 @@ impl usb_device::bus::UsbBus for UsbBus { } } + // Delay a few cycles after selecting PHY before doing a core reset + // https://community.st.com/s/question/0D53W00000znL7jSAE/stm32h745-usbotg-intermittently-fails-to-respond-to-core-reset + #[cfg(not(feature = "cortex-m"))] + for _ in 0..500000 {}; + #[cfg(feature = "cortex-m")] + cortex_m::asm::delay(25600); + // Perform core soft-reset while read_reg!(otg_global, regs.global(), GRSTCTL, AHBIDL) == 0 {} modify_reg!(otg_global, regs.global(), GRSTCTL, CSRST: 1); From 75f14968ca528e471167f9f3d753e9f8671f6d4c Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Thu, 13 Jan 2022 12:17:28 +1100 Subject: [PATCH 04/15] Minor changes to hopefully make ISO IN eps work --- src/bus.rs | 3 ++- src/endpoint.rs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index eeef352..f8d03b0 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -498,7 +498,8 @@ impl usb_device::bus::UsbBus for UsbBus { write_reg!(otg_global, regs.global(), GINTMSK, USBRST: 1, ENUMDNEM: 1, USBSUSPM: 1, WUIM: 1, - IEPINT: 1, RXFLVLM: 1 + IEPINT: 1, RXFLVLM: 1, + SOFM: 1 ); // clear pending interrupts diff --git a/src/endpoint.rs b/src/endpoint.rs index b49a730..a7e1880 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -139,6 +139,13 @@ impl EndpointIn { } } + #[cfg(feature = "fs")] + write_reg!(endpoint_in, ep, DIEPTSIZ, PKTCNT: 1, XFRSIZ: buf.len() as u32); + #[cfg(feature = "hs")] + write_reg!(endpoint_in, ep, DIEPTSIZ, MCNT: 1, PKTCNT: 1, XFRSIZ: buf.len() as u32); + + modify_reg!(endpoint_in, ep, DIEPCTL, CNAK: 1, EPENA: 1); + match self.descriptor.ep_type { // Isochronous endpoints must set the correct even/odd frame bit to // correspond with the next frame's number. @@ -150,19 +157,12 @@ impl EndpointIn { modify_reg!(endpoint_in, ep, DIEPCTL, SD0PID_SEVNFRM: 1); } else { // Previous frame number is even, so upcoming frame is odd - modify_reg!(endpoint_in, ep, DIEPCTL, SODDFRM_SD1PID: 1); + modify_reg!(endpoint_in, ep, DIEPCTL, SODDFRM: 1); } }, _ => {} } - #[cfg(feature = "fs")] - write_reg!(endpoint_in, ep, DIEPTSIZ, PKTCNT: 1, XFRSIZ: buf.len() as u32); - #[cfg(feature = "hs")] - write_reg!(endpoint_in, ep, DIEPTSIZ, MCNT: 1, PKTCNT: 1, XFRSIZ: buf.len() as u32); - - modify_reg!(endpoint_in, ep, DIEPCTL, CNAK: 1, EPENA: 1); - fifo_write(self.usb, self.index(), buf); Ok(()) From 741d008287a4898f4916da013483659368131a53 Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Fri, 14 Jan 2022 14:02:18 +1100 Subject: [PATCH 05/15] Mask off the SOF interrupt again --- src/bus.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index f8d03b0..eeef352 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -498,8 +498,7 @@ impl usb_device::bus::UsbBus for UsbBus { write_reg!(otg_global, regs.global(), GINTMSK, USBRST: 1, ENUMDNEM: 1, USBSUSPM: 1, WUIM: 1, - IEPINT: 1, RXFLVLM: 1, - SOFM: 1 + IEPINT: 1, RXFLVLM: 1 ); // clear pending interrupts From 0e662b0c569cee7d7c6b07405159d0c78d020299 Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Fri, 14 Jan 2022 14:02:55 +1100 Subject: [PATCH 06/15] Reverse the even/odd frame numbering? --- src/endpoint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/endpoint.rs b/src/endpoint.rs index a7e1880..b093c02 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -152,7 +152,7 @@ impl EndpointIn { EndpointType::Isochronous(_) => { // Previous frame number is OTG_DSTS.FNSOF let frame_number = read_reg!(otg_device, device, DSTS, FNSOF); - if frame_number & 0x1 == 1 { + if frame_number & 0x1 == 0 { // Previous frame number is odd, so upcoming frame is even modify_reg!(endpoint_in, ep, DIEPCTL, SD0PID_SEVNFRM: 1); } else { From 77c24eca58747ab874a5fe876334f2b1a414d9cc Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Fri, 14 Jan 2022 19:22:41 +1100 Subject: [PATCH 07/15] Enable the end point after setting even/odd frame --- src/endpoint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/endpoint.rs b/src/endpoint.rs index b093c02..a0a1551 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -144,8 +144,6 @@ impl EndpointIn { #[cfg(feature = "hs")] write_reg!(endpoint_in, ep, DIEPTSIZ, MCNT: 1, PKTCNT: 1, XFRSIZ: buf.len() as u32); - modify_reg!(endpoint_in, ep, DIEPCTL, CNAK: 1, EPENA: 1); - match self.descriptor.ep_type { // Isochronous endpoints must set the correct even/odd frame bit to // correspond with the next frame's number. @@ -163,6 +161,8 @@ impl EndpointIn { _ => {} } + modify_reg!(endpoint_in, ep, DIEPCTL, CNAK: 1, EPENA: 1); + fifo_write(self.usb, self.index(), buf); Ok(()) From 62a0b0d55160d8b7c808f45680621ae23c683fa3 Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Fri, 14 Jan 2022 21:42:10 +1100 Subject: [PATCH 08/15] Back to what's right --- src/endpoint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/endpoint.rs b/src/endpoint.rs index a0a1551..cf120bc 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -150,7 +150,7 @@ impl EndpointIn { EndpointType::Isochronous(_) => { // Previous frame number is OTG_DSTS.FNSOF let frame_number = read_reg!(otg_device, device, DSTS, FNSOF); - if frame_number & 0x1 == 0 { + if frame_number & 0x1 == 1 { // Previous frame number is odd, so upcoming frame is even modify_reg!(endpoint_in, ep, DIEPCTL, SD0PID_SEVNFRM: 1); } else { From 54f4742dd4ba20d52622d3da210a87df7bf08bff Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Tue, 15 Mar 2022 19:46:46 +1100 Subject: [PATCH 09/15] Use the right register field on FS peripherals --- src/endpoint.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/endpoint.rs b/src/endpoint.rs index cf120bc..8decfaa 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -155,6 +155,9 @@ impl EndpointIn { modify_reg!(endpoint_in, ep, DIEPCTL, SD0PID_SEVNFRM: 1); } else { // Previous frame number is even, so upcoming frame is odd + #[cfg(feature = "fs")] + modify_reg!(endpoint_in, ep, DIEPCTL, SODDFRM_SD1PID: 1); + #[cfg(feature = "hs")] modify_reg!(endpoint_in, ep, DIEPCTL, SODDFRM: 1); } }, From 36c86d1528b5a990ec74556af5d6546f0f41aa63 Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Tue, 15 Mar 2022 19:47:47 +1100 Subject: [PATCH 10/15] Fix Tx FIFO memory calculation This used to allocate 9 * 16 words minimum, no matter how many tx endpoints where active. Now we only account for memory allocated to enabled Tx endpoints when determining how much has already been used. --- src/endpoint_memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/endpoint_memory.rs b/src/endpoint_memory.rs index 7dc33f2..d308fdd 100644 --- a/src/endpoint_memory.rs +++ b/src/endpoint_memory.rs @@ -153,7 +153,7 @@ impl EndpointMemoryAllocator { } let mut used = self.total_rx_buffer_size_words() as usize + 30; - for sz in &self.tx_fifo_size_words { + for sz in &self.tx_fifo_size_words[0..ep_number] { used += core::cmp::max(*sz as usize, 16); } used -= 16; From 99367b59930683fad849ae83e2ac21dfc0c36e58 Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Tue, 15 Mar 2022 20:08:38 +1100 Subject: [PATCH 11/15] Use local usb-device for now --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 3313fd9..f4821a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,9 @@ embedded-hal = "0.2.4" vcell = "0.1.0" usb-device = "0.2.3" +[patch.crates-io] +usb-device = { path = "../usb-device" } + [package.metadata.docs.rs] features = ['cortex-m', 'fs'] From 4304902d5b4b13d9284f5b5f01194ad8bbcd9ddb Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Tue, 2 Aug 2022 21:05:44 +1000 Subject: [PATCH 12/15] Don't use local usb-device --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f4821a7..1bbd41e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ vcell = "0.1.0" usb-device = "0.2.3" [patch.crates-io] -usb-device = { path = "../usb-device" } +usb-device = { git = "https://github.com/dgoodlad/usb-device", branch = "crabdac" } [package.metadata.docs.rs] features = ['cortex-m', 'fs'] From fd4fdde40f31bc1ece6e3991a45a86f78db13f65 Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Wed, 3 Aug 2022 18:11:10 +1000 Subject: [PATCH 13/15] Handle incomplete isochronous IN transfers Per RM0383's OTG documentation, when we receive an IISOIXFR interrupt we must disable and re-enable the IN endpoint and flush its FIFO before retransmitting. --- src/bus.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index eeef352..cc84b43 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -498,7 +498,8 @@ impl usb_device::bus::UsbBus for UsbBus { write_reg!(otg_global, regs.global(), GINTMSK, USBRST: 1, ENUMDNEM: 1, USBSUSPM: 1, WUIM: 1, - IEPINT: 1, RXFLVLM: 1 + IEPINT: 1, RXFLVLM: 1, + IISOIXFRM: 1 ); // clear pending interrupts @@ -585,8 +586,8 @@ impl usb_device::bus::UsbBus for UsbBus { let core_id = read_reg!(otg_global, regs.global(), CID); - let (wakeup, suspend, enum_done, reset, iep, rxflvl) = read_reg!(otg_global, regs.global(), GINTSTS, - WKUPINT, USBSUSP, ENUMDNE, USBRST, IEPINT, RXFLVL + let (wakeup, suspend, enum_done, reset, iep, rxflvl, iisoixfr) = read_reg!(otg_global, regs.global(), GINTSTS, + WKUPINT, USBSUSP, ENUMDNE, USBRST, IEPINT, RXFLVL, IISOIXFR ); if reset != 0 { @@ -649,6 +650,53 @@ impl usb_device::bus::UsbBus for UsbBus { write_reg!(otg_global, regs.global(), GINTSTS, USBSUSP: 1); PollResult::Suspend + } else if iisoixfr != 0 { + use crate::ral::endpoint_in; + + // Incomplete isochronous IN transfer; see + // RM0383 Rev 3 pp797 "Incomplete isochronous IN data transfers" + write_reg!(otg_global, regs.global(), GINTSTS, IISOIXFR: 1); + + let in_endpoints = self.allocator.endpoints_in + .iter() + .flatten() + .map(|ep| ep.address().index()); + + let mut iep: u16 = 0; + + for epnum in in_endpoints { + let ep_regs = regs.endpoint_in(epnum); + + // filter out non-isochronous endpoints + if read_reg!(endpoint_in, ep_regs, DIEPCTL, EPTYP) & 0x11 != 0x01 { continue; } + + // identify incomplete transfers by the presence of the NAK event + // see RM0383 Rev 3 pp 746 description of NAK: + // + // > In case of isochronous IN endpoints the interrupt gets + // > generated when a zero length packet is transmitted due + // > to unavailability of data in the Tx FIFO. + if read_reg!(endpoint_in, ep_regs, DIEPINT) & 1<<13 == 0 { continue; } + + // Set NAK + modify_reg!(endpoint_in, ep_regs, DIEPCTL, SNAK: 1); + while read_reg!(endpoint_in, ep_regs, DIEPINT, INEPNE) == 0 {} + + // Disable the endpoint + modify_reg!(endpoint_in, ep_regs, DIEPCTL, SNAK: 1, EPDIS: 1); + while read_reg!(endpoint_in, ep_regs, DIEPINT, EPDISD) == 0 {} + modify_reg!(endpoint_in, ep_regs, DIEPINT, EPDISD: 1); + assert!(read_reg!(endpoint_in, ep_regs, DIEPCTL, EPENA) == 0); + assert!(read_reg!(endpoint_in, ep_regs, DIEPCTL, EPDIS) == 0); + + // Flush the TX FIFO + modify_reg!(otg_global, regs.global(), GRSTCTL, TXFNUM: epnum as u32, TXFFLSH: 1); + while read_reg!(otg_global, regs.global(), GRSTCTL, TXFFLSH) == 1 {} + + iep |= 1 << epnum; + } + + PollResult::Data { ep_out: 0, ep_in_complete: iep, ep_setup: 0 } } else { let mut ep_out = 0; let mut ep_in_complete = 0; From 04f913dd365a21f0c5f7f6bd574219ca00395275 Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Wed, 3 Aug 2022 18:13:42 +1000 Subject: [PATCH 14/15] No more need for the delay after selecting PHY --- src/bus.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index cc84b43..8fd520f 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -431,13 +431,6 @@ impl usb_device::bus::UsbBus for UsbBus { } } - // Delay a few cycles after selecting PHY before doing a core reset - // https://community.st.com/s/question/0D53W00000znL7jSAE/stm32h745-usbotg-intermittently-fails-to-respond-to-core-reset - #[cfg(not(feature = "cortex-m"))] - for _ in 0..500000 {}; - #[cfg(feature = "cortex-m")] - cortex_m::asm::delay(25600); - // Perform core soft-reset while read_reg!(otg_global, regs.global(), GRSTCTL, AHBIDL) == 0 {} modify_reg!(otg_global, regs.global(), GRSTCTL, CSRST: 1); From 7fdb711b88514158f779cecdd5a3d0138b715a64 Mon Sep 17 00:00:00 2001 From: David Goodlad Date: Wed, 10 Aug 2022 21:15:04 +1000 Subject: [PATCH 15/15] Up-to-date rust-embedded-community/usb-device#60 --- Cargo.toml | 4 ++-- src/endpoint.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1bbd41e..4d2b564 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,10 +14,10 @@ riscv = { version = "0.6.0", optional = true } cortex-m = { version = "0.7.0", optional = true } embedded-hal = "0.2.4" vcell = "0.1.0" -usb-device = "0.2.3" +usb-device = "0.2.9" [patch.crates-io] -usb-device = { git = "https://github.com/dgoodlad/usb-device", branch = "crabdac" } +usb-device = { git = "https://github.com/ianrrees/usb-device", branch = "isochronous" } [package.metadata.docs.rs] features = ['cortex-m', 'fs'] diff --git a/src/endpoint.rs b/src/endpoint.rs index 8decfaa..64b7cb8 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -147,7 +147,7 @@ impl EndpointIn { match self.descriptor.ep_type { // Isochronous endpoints must set the correct even/odd frame bit to // correspond with the next frame's number. - EndpointType::Isochronous(_) => { + EndpointType::Isochronous{..} => { // Previous frame number is OTG_DSTS.FNSOF let frame_number = read_reg!(otg_device, device, DSTS, FNSOF); if frame_number & 0x1 == 1 { @@ -233,7 +233,7 @@ impl EndpointOut { match self.descriptor.ep_type { // Isochronous endpoints must set the correct even/odd frame bit to // correspond with the next frame's number. - EndpointType::Isochronous(_) => { + EndpointType::Isochronous{..} => { // Previous frame number is OTG_DSTS.FNSOF let frame_number = read_reg!(otg_device, device, DSTS, FNSOF); if frame_number & 0x1 == 1 {