diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-03-16 21:37:24 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-03-16 21:37:24 +0100 |
| commit | 2e004ccf9ee68d09a70c04c8c62c0558252af575 (patch) | |
| tree | de80577b46363a4ab14a382f5981019c553c2387 | |
| parent | 38f26137fc67beb874aa73c9a7ab2150d9f3d372 (diff) | |
| parent | cecbe082ff5505b69cd4cc7138a4275d7af4aa8a (diff) | |
Merge pull request #3970 from elagil/fix_usb_iso_in_ep_stat
Fix USB ISO IN EP stat and ISO OUT buffer order
| -rw-r--r-- | embassy-stm32/src/usb/usb.rs | 158 |
1 files changed, 83 insertions, 75 deletions
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index b9a16bbf1..8dabfc78f 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -80,10 +80,10 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 80 | 80 | ||
| 81 | if istr.ctr() { | 81 | if istr.ctr() { |
| 82 | let index = istr.ep_id() as usize; | 82 | let index = istr.ep_id() as usize; |
| 83 | CTR_TRIGGERED[index].store(true, Ordering::Relaxed); | ||
| 84 | 83 | ||
| 85 | let mut epr = regs.epr(index).read(); | 84 | let mut epr = regs.epr(index).read(); |
| 86 | if epr.ctr_rx() { | 85 | if epr.ctr_rx() { |
| 86 | RX_COMPLETE[index].store(true, Ordering::Relaxed); | ||
| 87 | if index == 0 && epr.setup() { | 87 | if index == 0 && epr.setup() { |
| 88 | EP0_SETUP.store(true, Ordering::Relaxed); | 88 | EP0_SETUP.store(true, Ordering::Relaxed); |
| 89 | } | 89 | } |
| @@ -91,6 +91,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 91 | EP_OUT_WAKERS[index].wake(); | 91 | EP_OUT_WAKERS[index].wake(); |
| 92 | } | 92 | } |
| 93 | if epr.ctr_tx() { | 93 | if epr.ctr_tx() { |
| 94 | TX_PENDING[index].store(false, Ordering::Relaxed); | ||
| 94 | //trace!("EP {} TX", index); | 95 | //trace!("EP {} TX", index); |
| 95 | EP_IN_WAKERS[index].wake(); | 96 | EP_IN_WAKERS[index].wake(); |
| 96 | } | 97 | } |
| @@ -122,7 +123,8 @@ const USBRAM_ALIGN: usize = 4; | |||
| 122 | static BUS_WAKER: AtomicWaker = AtomicWaker::new(); | 123 | static BUS_WAKER: AtomicWaker = AtomicWaker::new(); |
| 123 | static EP0_SETUP: AtomicBool = AtomicBool::new(false); | 124 | static EP0_SETUP: AtomicBool = AtomicBool::new(false); |
| 124 | 125 | ||
| 125 | static CTR_TRIGGERED: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; | 126 | static TX_PENDING: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; |
| 127 | static RX_COMPLETE: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; | ||
| 126 | static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; | 128 | static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; |
| 127 | static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; | 129 | static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; |
| 128 | static IRQ_RESET: AtomicBool = AtomicBool::new(false); | 130 | static IRQ_RESET: AtomicBool = AtomicBool::new(false); |
| @@ -204,15 +206,13 @@ mod btable { | |||
| 204 | mod btable { | 206 | mod btable { |
| 205 | use super::*; | 207 | use super::*; |
| 206 | 208 | ||
| 207 | pub(super) fn write_in_tx<T: Instance>(_index: usize, _addr: u16) {} | ||
| 208 | |||
| 209 | pub(super) fn write_in_rx<T: Instance>(_index: usize, _addr: u16) {} | ||
| 210 | |||
| 211 | pub(super) fn write_in_len_tx<T: Instance>(index: usize, addr: u16, len: u16) { | 209 | pub(super) fn write_in_len_tx<T: Instance>(index: usize, addr: u16, len: u16) { |
| 210 | assert_eq!(addr & 0b11, 0); | ||
| 212 | USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); | 211 | USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); |
| 213 | } | 212 | } |
| 214 | 213 | ||
| 215 | pub(super) fn write_in_len_rx<T: Instance>(index: usize, addr: u16, len: u16) { | 214 | pub(super) fn write_in_len_rx<T: Instance>(index: usize, addr: u16, len: u16) { |
| 215 | assert_eq!(addr & 0b11, 0); | ||
| 216 | USBRAM | 216 | USBRAM |
| 217 | .mem(index * 2 + 1) | 217 | .mem(index * 2 + 1) |
| 218 | .write_value((addr as u32) | ((len as u32) << 16)); | 218 | .write_value((addr as u32) | ((len as u32) << 16)); |
| @@ -363,10 +363,11 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 363 | return false; // reserved for control pipe | 363 | return false; // reserved for control pipe |
| 364 | } | 364 | } |
| 365 | let used = ep.used_out || ep.used_in; | 365 | let used = ep.used_out || ep.used_in; |
| 366 | if used && (ep.ep_type == EndpointType::Isochronous || ep.ep_type == EndpointType::Bulk) { | 366 | if used && (ep.ep_type == EndpointType::Isochronous) { |
| 367 | // Isochronous and bulk endpoints are double-buffered. | 367 | // Isochronous endpoints are always double-buffered. |
| 368 | // Their corresponding endpoint/channel registers are forced to be unidirectional. | 368 | // Their corresponding endpoint/channel registers are forced to be unidirectional. |
| 369 | // Do not reuse this index. | 369 | // Do not reuse this index. |
| 370 | // FIXME: Bulk endpoints can be double buffered, but are not in the current implementation. | ||
| 370 | return false; | 371 | return false; |
| 371 | } | 372 | } |
| 372 | 373 | ||
| @@ -412,11 +413,23 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 412 | let len = align_len_up(max_packet_size); | 413 | let len = align_len_up(max_packet_size); |
| 413 | let addr = self.alloc_ep_mem(len); | 414 | let addr = self.alloc_ep_mem(len); |
| 414 | 415 | ||
| 415 | // ep_in_len is written when actually TXing packets. | 416 | #[cfg(not(any(usbram_32_2048, usbram_32_1024)))] |
| 416 | btable::write_in_tx::<T>(index, addr); | 417 | { |
| 418 | // ep_in_len is written when actually transmitting packets. | ||
| 419 | btable::write_in_tx::<T>(index, addr); | ||
| 417 | 420 | ||
| 418 | if ep_type == EndpointType::Isochronous { | 421 | if ep_type == EndpointType::Isochronous { |
| 419 | btable::write_in_rx::<T>(index, addr); | 422 | btable::write_in_rx::<T>(index, addr); |
| 423 | } | ||
| 424 | } | ||
| 425 | |||
| 426 | #[cfg(any(usbram_32_2048, usbram_32_1024))] | ||
| 427 | { | ||
| 428 | btable::write_in_len_tx::<T>(index, addr, 0); | ||
| 429 | |||
| 430 | if ep_type == EndpointType::Isochronous { | ||
| 431 | btable::write_in_len_rx::<T>(index, addr, 0); | ||
| 432 | } | ||
| 420 | } | 433 | } |
| 421 | 434 | ||
| 422 | EndpointBuffer { | 435 | EndpointBuffer { |
| @@ -640,22 +653,25 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 640 | fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { | 653 | fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { |
| 641 | trace!("set_enabled {:?} {}", ep_addr, enabled); | 654 | trace!("set_enabled {:?} {}", ep_addr, enabled); |
| 642 | // This can race, so do a retry loop. | 655 | // This can race, so do a retry loop. |
| 643 | let reg = T::regs().epr(ep_addr.index() as _); | 656 | let epr = T::regs().epr(ep_addr.index() as _); |
| 644 | trace!("EPR before: {:04x}", reg.read().0); | 657 | trace!("EPR before: {:04x}", epr.read().0); |
| 645 | match ep_addr.direction() { | 658 | match ep_addr.direction() { |
| 646 | Direction::In => { | 659 | Direction::In => { |
| 647 | loop { | 660 | loop { |
| 648 | let want_stat = match enabled { | 661 | let want_stat = match enabled { |
| 649 | false => Stat::DISABLED, | 662 | false => Stat::DISABLED, |
| 650 | true => Stat::NAK, | 663 | true => match epr.read().ep_type() { |
| 664 | EpType::ISO => Stat::VALID, | ||
| 665 | _ => Stat::NAK, | ||
| 666 | }, | ||
| 651 | }; | 667 | }; |
| 652 | let r = reg.read(); | 668 | let r = epr.read(); |
| 653 | if r.stat_tx() == want_stat { | 669 | if r.stat_tx() == want_stat { |
| 654 | break; | 670 | break; |
| 655 | } | 671 | } |
| 656 | let mut w = invariant(r); | 672 | let mut w = invariant(r); |
| 657 | w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits())); | 673 | w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits())); |
| 658 | reg.write_value(w); | 674 | epr.write_value(w); |
| 659 | } | 675 | } |
| 660 | EP_IN_WAKERS[ep_addr.index()].wake(); | 676 | EP_IN_WAKERS[ep_addr.index()].wake(); |
| 661 | } | 677 | } |
| @@ -665,18 +681,18 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 665 | false => Stat::DISABLED, | 681 | false => Stat::DISABLED, |
| 666 | true => Stat::VALID, | 682 | true => Stat::VALID, |
| 667 | }; | 683 | }; |
| 668 | let r = reg.read(); | 684 | let r = epr.read(); |
| 669 | if r.stat_rx() == want_stat { | 685 | if r.stat_rx() == want_stat { |
| 670 | break; | 686 | break; |
| 671 | } | 687 | } |
| 672 | let mut w = invariant(r); | 688 | let mut w = invariant(r); |
| 673 | w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits())); | 689 | w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits())); |
| 674 | reg.write_value(w); | 690 | epr.write_value(w); |
| 675 | } | 691 | } |
| 676 | EP_OUT_WAKERS[ep_addr.index()].wake(); | 692 | EP_OUT_WAKERS[ep_addr.index()].wake(); |
| 677 | } | 693 | } |
| 678 | } | 694 | } |
| 679 | trace!("EPR after: {:04x}", reg.read().0); | 695 | trace!("EPR after: {:04x}", epr.read().0); |
| 680 | } | 696 | } |
| 681 | 697 | ||
| 682 | async fn enable(&mut self) {} | 698 | async fn enable(&mut self) {} |
| @@ -712,6 +728,7 @@ impl Dir for Out { | |||
| 712 | /// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same | 728 | /// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same |
| 713 | /// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve | 729 | /// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve |
| 714 | /// two directions at the same time. | 730 | /// two directions at the same time. |
| 731 | #[derive(Clone, Copy, Debug)] | ||
| 715 | enum PacketBuffer { | 732 | enum PacketBuffer { |
| 716 | /// The RX buffer - must be used for single-buffered OUT endpoints | 733 | /// The RX buffer - must be used for single-buffered OUT endpoints |
| 717 | Rx, | 734 | Rx, |
| @@ -836,7 +853,8 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 836 | if self.info.ep_type == EndpointType::Isochronous { | 853 | if self.info.ep_type == EndpointType::Isochronous { |
| 837 | // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. | 854 | // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. |
| 838 | // Therefore, this instead waits until the `CTR` interrupt was triggered. | 855 | // Therefore, this instead waits until the `CTR` interrupt was triggered. |
| 839 | if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) { | 856 | if matches!(stat, Stat::DISABLED) || RX_COMPLETE[index].load(Ordering::Relaxed) { |
| 857 | assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); | ||
| 840 | Poll::Ready(stat) | 858 | Poll::Ready(stat) |
| 841 | } else { | 859 | } else { |
| 842 | Poll::Pending | 860 | Poll::Pending |
| @@ -851,7 +869,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 851 | }) | 869 | }) |
| 852 | .await; | 870 | .await; |
| 853 | 871 | ||
| 854 | CTR_TRIGGERED[index].store(false, Ordering::Relaxed); | 872 | RX_COMPLETE[index].store(false, Ordering::Relaxed); |
| 855 | 873 | ||
| 856 | if stat == Stat::DISABLED { | 874 | if stat == Stat::DISABLED { |
| 857 | return Err(EndpointError::Disabled); | 875 | return Err(EndpointError::Disabled); |
| @@ -859,31 +877,26 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 859 | 877 | ||
| 860 | let regs = T::regs(); | 878 | let regs = T::regs(); |
| 861 | 879 | ||
| 862 | let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { | 880 | let rx_len = if self.info.ep_type == EndpointType::Isochronous { |
| 863 | // Find the buffer, which is currently in use. Read from the OTHER buffer. | 881 | // Find the buffer, which is currently in use. Read from the OTHER buffer. |
| 864 | if regs.epr(index).read().dtog_rx() { | 882 | let packet_buffer = if regs.epr(index).read().dtog_rx() { |
| 865 | PacketBuffer::Rx | ||
| 866 | } else { | ||
| 867 | PacketBuffer::Tx | 883 | PacketBuffer::Tx |
| 868 | } | ||
| 869 | } else { | ||
| 870 | PacketBuffer::Rx | ||
| 871 | }; | ||
| 872 | |||
| 873 | let rx_len = self.read_data_double_buffered(buf, packet_buffer)?; | ||
| 874 | |||
| 875 | regs.epr(index).write(|w| { | ||
| 876 | w.set_ep_type(convert_type(self.info.ep_type)); | ||
| 877 | w.set_ea(self.info.addr.index() as _); | ||
| 878 | if self.info.ep_type == EndpointType::Isochronous { | ||
| 879 | w.set_stat_rx(Stat::from_bits(0)); // STAT_RX remains `VALID`. | ||
| 880 | } else { | 884 | } else { |
| 885 | PacketBuffer::Rx | ||
| 886 | }; | ||
| 887 | self.read_data_double_buffered(buf, packet_buffer)? | ||
| 888 | } else { | ||
| 889 | regs.epr(index).write(|w| { | ||
| 890 | w.set_ep_type(convert_type(self.info.ep_type)); | ||
| 891 | w.set_ea(self.info.addr.index() as _); | ||
| 881 | w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); | 892 | w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); |
| 882 | } | 893 | w.set_stat_tx(Stat::from_bits(0)); |
| 883 | w.set_stat_tx(Stat::from_bits(0)); | 894 | w.set_ctr_rx(true); // don't clear |
| 884 | w.set_ctr_rx(true); // don't clear | 895 | w.set_ctr_tx(true); // don't clear |
| 885 | w.set_ctr_tx(true); // don't clear | 896 | }); |
| 886 | }); | 897 | |
| 898 | self.read_data(buf)? | ||
| 899 | }; | ||
| 887 | trace!("READ OK, rx_len = {}", rx_len); | 900 | trace!("READ OK, rx_len = {}", rx_len); |
| 888 | 901 | ||
| 889 | Ok(rx_len) | 902 | Ok(rx_len) |
| @@ -895,18 +908,31 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 895 | if buf.len() > self.info.max_packet_size as usize { | 908 | if buf.len() > self.info.max_packet_size as usize { |
| 896 | return Err(EndpointError::BufferOverflow); | 909 | return Err(EndpointError::BufferOverflow); |
| 897 | } | 910 | } |
| 911 | trace!("WRITE WAITING, buf.len() = {}", buf.len()); | ||
| 898 | 912 | ||
| 913 | let regs = T::regs(); | ||
| 899 | let index = self.info.addr.index(); | 914 | let index = self.info.addr.index(); |
| 900 | 915 | ||
| 901 | trace!("WRITE WAITING"); | 916 | if self.info.ep_type == EndpointType::Isochronous { |
| 917 | // Find the buffer, which is currently in use. Write to the OTHER buffer. | ||
| 918 | let packet_buffer = if regs.epr(index).read().dtog_tx() { | ||
| 919 | PacketBuffer::Rx | ||
| 920 | } else { | ||
| 921 | PacketBuffer::Tx | ||
| 922 | }; | ||
| 923 | |||
| 924 | self.write_data_double_buffered(buf, packet_buffer); | ||
| 925 | } | ||
| 926 | |||
| 902 | let stat = poll_fn(|cx| { | 927 | let stat = poll_fn(|cx| { |
| 903 | EP_IN_WAKERS[index].register(cx.waker()); | 928 | EP_IN_WAKERS[index].register(cx.waker()); |
| 904 | let regs = T::regs(); | 929 | let regs = T::regs(); |
| 905 | let stat = regs.epr(index).read().stat_tx(); | 930 | let stat = regs.epr(index).read().stat_tx(); |
| 906 | if self.info.ep_type == EndpointType::Isochronous { | 931 | if self.info.ep_type == EndpointType::Isochronous { |
| 907 | // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. | 932 | // The isochronous endpoint does not change its `STAT_TX` field to `NAK` after sending a packet. |
| 908 | // Therefore, this instead waits until the `CTR` interrupt was triggered. | 933 | // Therefore, this instead waits until the `CTR` interrupt was triggered. |
| 909 | if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) { | 934 | if matches!(stat, Stat::DISABLED) || !TX_PENDING[index].load(Ordering::Relaxed) { |
| 935 | assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); | ||
| 910 | Poll::Ready(stat) | 936 | Poll::Ready(stat) |
| 911 | } else { | 937 | } else { |
| 912 | Poll::Pending | 938 | Poll::Pending |
| @@ -921,41 +947,23 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 921 | }) | 947 | }) |
| 922 | .await; | 948 | .await; |
| 923 | 949 | ||
| 924 | CTR_TRIGGERED[index].store(false, Ordering::Relaxed); | ||
| 925 | |||
| 926 | if stat == Stat::DISABLED { | 950 | if stat == Stat::DISABLED { |
| 927 | return Err(EndpointError::Disabled); | 951 | return Err(EndpointError::Disabled); |
| 928 | } | 952 | } |
| 929 | 953 | ||
| 930 | let regs = T::regs(); | 954 | if self.info.ep_type != EndpointType::Isochronous { |
| 931 | 955 | self.write_data(buf); | |
| 932 | let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { | ||
| 933 | // Find the buffer, which is currently in use. Write to the OTHER buffer. | ||
| 934 | if regs.epr(index).read().dtog_tx() { | ||
| 935 | PacketBuffer::Tx | ||
| 936 | } else { | ||
| 937 | PacketBuffer::Rx | ||
| 938 | } | ||
| 939 | } else { | ||
| 940 | PacketBuffer::Tx | ||
| 941 | }; | ||
| 942 | |||
| 943 | self.write_data_double_buffered(buf, packet_buffer); | ||
| 944 | 956 | ||
| 945 | let regs = T::regs(); | 957 | regs.epr(index).write(|w| { |
| 946 | regs.epr(index).write(|w| { | 958 | w.set_ep_type(convert_type(self.info.ep_type)); |
| 947 | w.set_ep_type(convert_type(self.info.ep_type)); | 959 | w.set_ea(self.info.addr.index() as _); |
| 948 | w.set_ea(self.info.addr.index() as _); | ||
| 949 | if self.info.ep_type == EndpointType::Isochronous { | ||
| 950 | w.set_stat_tx(Stat::from_bits(0)); // STAT_TX remains `VALID`. | ||
| 951 | } else { | ||
| 952 | w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); | 960 | w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); |
| 953 | } | 961 | w.set_stat_rx(Stat::from_bits(0)); |
| 954 | w.set_stat_rx(Stat::from_bits(0)); | 962 | w.set_ctr_rx(true); // don't clear |
| 955 | w.set_ctr_rx(true); // don't clear | 963 | w.set_ctr_tx(true); // don't clear |
| 956 | w.set_ctr_tx(true); // don't clear | 964 | }); |
| 957 | }); | 965 | } |
| 958 | 966 | TX_PENDING[index].store(true, Ordering::Relaxed); | |
| 959 | trace!("WRITE OK"); | 967 | trace!("WRITE OK"); |
| 960 | 968 | ||
| 961 | Ok(()) | 969 | Ok(()) |
