diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-04-16 11:41:59 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-04-16 11:41:59 +0000 |
| commit | ca139b9177aeb4ddb7ec54493d0fd62723edfba3 (patch) | |
| tree | b236965284f968a8973649f25b447f43a0e1faca | |
| parent | e38f1011d6234fbc51fbbbb2d93365517705e3ac (diff) | |
| parent | 2315a39293488488ced2369a1d23629af57cc0fb (diff) | |
Merge pull request #2823 from jamesmunns/james/usb-otg-errata
Add critical sections to avoid USB OTG Errata
| -rw-r--r-- | embassy-stm32/src/usb/otg.rs | 106 |
1 files changed, 58 insertions, 48 deletions
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index cabc06367..b386c6977 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs | |||
| @@ -672,45 +672,51 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 672 | 672 | ||
| 673 | let r = T::regs(); | 673 | let r = T::regs(); |
| 674 | 674 | ||
| 675 | // Configure RX fifo size. All endpoints share the same FIFO area. | 675 | // ERRATA NOTE: Don't interrupt FIFOs being written to. The interrupt |
| 676 | let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); | 676 | // handler COULD interrupt us here and do FIFO operations, so ensure |
| 677 | trace!("configuring rx fifo size={}", rx_fifo_size_words); | 677 | // the interrupt does not occur. |
| 678 | 678 | critical_section::with(|_| { | |
| 679 | r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)); | 679 | // Configure RX fifo size. All endpoints share the same FIFO area. |
| 680 | 680 | let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); | |
| 681 | // Configure TX (USB in direction) fifo size for each endpoint | 681 | trace!("configuring rx fifo size={}", rx_fifo_size_words); |
| 682 | let mut fifo_top = rx_fifo_size_words; | 682 | |
| 683 | for i in 0..T::ENDPOINT_COUNT { | 683 | r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)); |
| 684 | if let Some(ep) = self.ep_in[i] { | 684 | |
| 685 | trace!( | 685 | // Configure TX (USB in direction) fifo size for each endpoint |
| 686 | "configuring tx fifo ep={}, offset={}, size={}", | 686 | let mut fifo_top = rx_fifo_size_words; |
| 687 | i, | 687 | for i in 0..T::ENDPOINT_COUNT { |
| 688 | fifo_top, | 688 | if let Some(ep) = self.ep_in[i] { |
| 689 | ep.fifo_size_words | 689 | trace!( |
| 690 | ); | 690 | "configuring tx fifo ep={}, offset={}, size={}", |
| 691 | 691 | i, | |
| 692 | let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; | 692 | fifo_top, |
| 693 | 693 | ep.fifo_size_words | |
| 694 | dieptxf.write(|w| { | 694 | ); |
| 695 | w.set_fd(ep.fifo_size_words); | 695 | |
| 696 | w.set_sa(fifo_top); | 696 | let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; |
| 697 | }); | 697 | |
| 698 | dieptxf.write(|w| { | ||
| 699 | w.set_fd(ep.fifo_size_words); | ||
| 700 | w.set_sa(fifo_top); | ||
| 701 | }); | ||
| 698 | 702 | ||
| 699 | fifo_top += ep.fifo_size_words; | 703 | fifo_top += ep.fifo_size_words; |
| 704 | } | ||
| 700 | } | 705 | } |
| 701 | } | ||
| 702 | 706 | ||
| 703 | assert!( | 707 | assert!( |
| 704 | fifo_top <= T::FIFO_DEPTH_WORDS, | 708 | fifo_top <= T::FIFO_DEPTH_WORDS, |
| 705 | "FIFO allocations exceeded maximum capacity" | 709 | "FIFO allocations exceeded maximum capacity" |
| 706 | ); | 710 | ); |
| 707 | 711 | ||
| 708 | // Flush fifos | 712 | // Flush fifos |
| 709 | r.grstctl().write(|w| { | 713 | r.grstctl().write(|w| { |
| 710 | w.set_rxfflsh(true); | 714 | w.set_rxfflsh(true); |
| 711 | w.set_txfflsh(true); | 715 | w.set_txfflsh(true); |
| 712 | w.set_txfnum(0x10); | 716 | w.set_txfnum(0x10); |
| 717 | }); | ||
| 713 | }); | 718 | }); |
| 719 | |||
| 714 | loop { | 720 | loop { |
| 715 | let x = r.grstctl().read(); | 721 | let x = r.grstctl().read(); |
| 716 | if !x.rxfflsh() && !x.txfflsh() { | 722 | if !x.rxfflsh() && !x.txfflsh() { |
| @@ -1208,27 +1214,31 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 1208 | .await | 1214 | .await |
| 1209 | } | 1215 | } |
| 1210 | 1216 | ||
| 1211 | // Setup transfer size | 1217 | // ERRATA: Transmit data FIFO is corrupted when a write sequence to the FIFO is interrupted with |
| 1212 | r.dieptsiz(index).write(|w| { | 1218 | // accesses to certain OTG_FS registers. |
| 1213 | w.set_mcnt(1); | 1219 | // |
| 1214 | w.set_pktcnt(1); | 1220 | // Prevent the interrupt (which might poke FIFOs) from executing while copying data to FIFOs. |
| 1215 | w.set_xfrsiz(buf.len() as _); | ||
| 1216 | }); | ||
| 1217 | |||
| 1218 | critical_section::with(|_| { | 1221 | critical_section::with(|_| { |
| 1222 | // Setup transfer size | ||
| 1223 | r.dieptsiz(index).write(|w| { | ||
| 1224 | w.set_mcnt(1); | ||
| 1225 | w.set_pktcnt(1); | ||
| 1226 | w.set_xfrsiz(buf.len() as _); | ||
| 1227 | }); | ||
| 1228 | |||
| 1219 | // Enable endpoint | 1229 | // Enable endpoint |
| 1220 | r.diepctl(index).modify(|w| { | 1230 | r.diepctl(index).modify(|w| { |
| 1221 | w.set_cnak(true); | 1231 | w.set_cnak(true); |
| 1222 | w.set_epena(true); | 1232 | w.set_epena(true); |
| 1223 | }); | 1233 | }); |
| 1224 | }); | ||
| 1225 | 1234 | ||
| 1226 | // Write data to FIFO | 1235 | // Write data to FIFO |
| 1227 | for chunk in buf.chunks(4) { | 1236 | for chunk in buf.chunks(4) { |
| 1228 | let mut tmp = [0u8; 4]; | 1237 | let mut tmp = [0u8; 4]; |
| 1229 | tmp[0..chunk.len()].copy_from_slice(chunk); | 1238 | tmp[0..chunk.len()].copy_from_slice(chunk); |
| 1230 | r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))); | 1239 | r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))); |
| 1231 | } | 1240 | } |
| 1241 | }); | ||
| 1232 | 1242 | ||
| 1233 | trace!("write done ep={:?}", self.info.addr); | 1243 | trace!("write done ep={:?}", self.info.addr); |
| 1234 | 1244 | ||
