diff options
| author | elagil <[email protected]> | 2025-03-15 20:16:20 +0100 |
|---|---|---|
| committer | elagil <[email protected]> | 2025-03-15 20:16:32 +0100 |
| commit | 0b468ef29cc67e05aae01031604b746b1f21ffcd (patch) | |
| tree | 923360663c44f4e40c2056e8fb4cbfb130b9ce74 | |
| parent | 0b6b0756ed5e6f259cf2fed8bf6de008eab78cb1 (diff) | |
fix: iso out order
| -rw-r--r-- | embassy-stm32/src/usb/usb.rs | 75 |
1 files changed, 37 insertions, 38 deletions
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 31ab8f76d..cb97169ee 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -83,7 +83,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 83 | 83 | ||
| 84 | let mut epr = regs.epr(index).read(); | 84 | let mut epr = regs.epr(index).read(); |
| 85 | if epr.ctr_rx() { | 85 | if epr.ctr_rx() { |
| 86 | CTR_RX_TRIGGERED[index].store(true, Ordering::Relaxed); | 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,7 +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 | CTR_TX_TRIGGERED[index].store(true, Ordering::Relaxed); | 94 | TX_PENDING[index].store(false, Ordering::Relaxed); |
| 95 | //trace!("EP {} TX", index); | 95 | //trace!("EP {} TX", index); |
| 96 | EP_IN_WAKERS[index].wake(); | 96 | EP_IN_WAKERS[index].wake(); |
| 97 | } | 97 | } |
| @@ -123,8 +123,8 @@ const USBRAM_ALIGN: usize = 4; | |||
| 123 | static BUS_WAKER: AtomicWaker = AtomicWaker::new(); | 123 | static BUS_WAKER: AtomicWaker = AtomicWaker::new(); |
| 124 | static EP0_SETUP: AtomicBool = AtomicBool::new(false); | 124 | static EP0_SETUP: AtomicBool = AtomicBool::new(false); |
| 125 | 125 | ||
| 126 | static CTR_TX_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 CTR_RX_TRIGGERED: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; | 127 | static RX_COMPLETE: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; |
| 128 | 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]; |
| 129 | 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]; |
| 130 | static IRQ_RESET: AtomicBool = AtomicBool::new(false); | 130 | static IRQ_RESET: AtomicBool = AtomicBool::new(false); |
| @@ -417,10 +417,10 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 417 | let addr = self.alloc_ep_mem(len); | 417 | let addr = self.alloc_ep_mem(len); |
| 418 | 418 | ||
| 419 | // ep_in_len is written when actually TXing packets. | 419 | // ep_in_len is written when actually TXing packets. |
| 420 | btable::write_in_tx::<T>(index, addr); | 420 | btable::write_in_len_tx::<T>(index, addr, 0); |
| 421 | 421 | ||
| 422 | if ep_type == EndpointType::Isochronous { | 422 | if ep_type == EndpointType::Isochronous { |
| 423 | btable::write_in_rx::<T>(index, addr); | 423 | btable::write_in_len_rx::<T>(index, addr, 0); |
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | EndpointBuffer { | 426 | EndpointBuffer { |
| @@ -719,6 +719,7 @@ impl Dir for Out { | |||
| 719 | /// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same | 719 | /// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same |
| 720 | /// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve | 720 | /// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve |
| 721 | /// two directions at the same time. | 721 | /// two directions at the same time. |
| 722 | #[derive(Clone, Copy, Debug)] | ||
| 722 | enum PacketBuffer { | 723 | enum PacketBuffer { |
| 723 | /// The RX buffer - must be used for single-buffered OUT endpoints | 724 | /// The RX buffer - must be used for single-buffered OUT endpoints |
| 724 | Rx, | 725 | Rx, |
| @@ -843,7 +844,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 843 | if self.info.ep_type == EndpointType::Isochronous { | 844 | if self.info.ep_type == EndpointType::Isochronous { |
| 844 | // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. | 845 | // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. |
| 845 | // Therefore, this instead waits until the `CTR` interrupt was triggered. | 846 | // Therefore, this instead waits until the `CTR` interrupt was triggered. |
| 846 | if matches!(stat, Stat::DISABLED) || CTR_RX_TRIGGERED[index].load(Ordering::Relaxed) { | 847 | if matches!(stat, Stat::DISABLED) || RX_COMPLETE[index].load(Ordering::Relaxed) { |
| 847 | assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); | 848 | assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); |
| 848 | Poll::Ready(stat) | 849 | Poll::Ready(stat) |
| 849 | } else { | 850 | } else { |
| @@ -859,7 +860,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 859 | }) | 860 | }) |
| 860 | .await; | 861 | .await; |
| 861 | 862 | ||
| 862 | CTR_RX_TRIGGERED[index].store(false, Ordering::Relaxed); | 863 | RX_COMPLETE[index].store(false, Ordering::Relaxed); |
| 863 | 864 | ||
| 864 | if stat == Stat::DISABLED { | 865 | if stat == Stat::DISABLED { |
| 865 | return Err(EndpointError::Disabled); | 866 | return Err(EndpointError::Disabled); |
| @@ -870,9 +871,9 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | |||
| 870 | let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { | 871 | let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { |
| 871 | // Find the buffer, which is currently in use. Read from the OTHER buffer. | 872 | // Find the buffer, which is currently in use. Read from the OTHER buffer. |
| 872 | if regs.epr(index).read().dtog_rx() { | 873 | if regs.epr(index).read().dtog_rx() { |
| 873 | PacketBuffer::Rx | ||
| 874 | } else { | ||
| 875 | PacketBuffer::Tx | 874 | PacketBuffer::Tx |
| 875 | } else { | ||
| 876 | PacketBuffer::Rx | ||
| 876 | } | 877 | } |
| 877 | } else { | 878 | } else { |
| 878 | PacketBuffer::Rx | 879 | PacketBuffer::Rx |
| @@ -904,7 +905,21 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 904 | return Err(EndpointError::BufferOverflow); | 905 | return Err(EndpointError::BufferOverflow); |
| 905 | } | 906 | } |
| 906 | trace!("WRITE WAITING, buf.len() = {}", buf.len()); | 907 | trace!("WRITE WAITING, buf.len() = {}", buf.len()); |
| 908 | |||
| 909 | let regs = T::regs(); | ||
| 907 | let index = self.info.addr.index(); | 910 | let index = self.info.addr.index(); |
| 911 | |||
| 912 | if self.info.ep_type == EndpointType::Isochronous { | ||
| 913 | // Find the buffer, which is currently in use. Write to the OTHER buffer. | ||
| 914 | let packet_buffer = if regs.epr(index).read().dtog_tx() { | ||
| 915 | PacketBuffer::Rx | ||
| 916 | } else { | ||
| 917 | PacketBuffer::Tx | ||
| 918 | }; | ||
| 919 | |||
| 920 | self.write_data_double_buffered(buf, packet_buffer); | ||
| 921 | } | ||
| 922 | |||
| 908 | let stat = poll_fn(|cx| { | 923 | let stat = poll_fn(|cx| { |
| 909 | EP_IN_WAKERS[index].register(cx.waker()); | 924 | EP_IN_WAKERS[index].register(cx.waker()); |
| 910 | let regs = T::regs(); | 925 | let regs = T::regs(); |
| @@ -912,7 +927,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 912 | if self.info.ep_type == EndpointType::Isochronous { | 927 | if self.info.ep_type == EndpointType::Isochronous { |
| 913 | // The isochronous endpoint does not change its `STAT_TX` field to `NAK` after sending a packet. | 928 | // The isochronous endpoint does not change its `STAT_TX` field to `NAK` after sending a packet. |
| 914 | // Therefore, this instead waits until the `CTR` interrupt was triggered. | 929 | // Therefore, this instead waits until the `CTR` interrupt was triggered. |
| 915 | if matches!(stat, Stat::DISABLED) || CTR_TX_TRIGGERED[index].load(Ordering::Relaxed) { | 930 | if matches!(stat, Stat::DISABLED) || !TX_PENDING[index].load(Ordering::Relaxed) { |
| 916 | assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); | 931 | assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); |
| 917 | Poll::Ready(stat) | 932 | Poll::Ready(stat) |
| 918 | } else { | 933 | } else { |
| @@ -928,39 +943,23 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 928 | }) | 943 | }) |
| 929 | .await; | 944 | .await; |
| 930 | 945 | ||
| 931 | CTR_TX_TRIGGERED[index].store(false, Ordering::Relaxed); | ||
| 932 | |||
| 933 | if stat == Stat::DISABLED { | 946 | if stat == Stat::DISABLED { |
| 934 | return Err(EndpointError::Disabled); | 947 | return Err(EndpointError::Disabled); |
| 935 | } | 948 | } |
| 936 | 949 | ||
| 937 | let regs = T::regs(); | 950 | if self.info.ep_type != EndpointType::Isochronous { |
| 938 | 951 | self.write_data(buf); | |
| 939 | let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { | ||
| 940 | // Find the buffer, which is currently in use. Write to the OTHER buffer. | ||
| 941 | if regs.epr(index).read().dtog_tx() { | ||
| 942 | PacketBuffer::Tx | ||
| 943 | } else { | ||
| 944 | PacketBuffer::Rx | ||
| 945 | } | ||
| 946 | } else { | ||
| 947 | PacketBuffer::Tx | ||
| 948 | }; | ||
| 949 | |||
| 950 | self.write_data_double_buffered(buf, packet_buffer); | ||
| 951 | 952 | ||
| 952 | regs.epr(index).write(|w| { | 953 | regs.epr(index).write(|w| { |
| 953 | w.set_ep_type(convert_type(self.info.ep_type)); | 954 | w.set_ep_type(convert_type(self.info.ep_type)); |
| 954 | w.set_ea(self.info.addr.index() as _); | 955 | w.set_ea(self.info.addr.index() as _); |
| 955 | if self.info.ep_type == EndpointType::Isochronous { | ||
| 956 | w.set_stat_tx(Stat::from_bits(0)); // STAT_TX remains `VALID`. | ||
| 957 | } else { | ||
| 958 | w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); | 956 | w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); |
| 959 | } | 957 | w.set_stat_rx(Stat::from_bits(0)); |
| 960 | w.set_stat_rx(Stat::from_bits(0)); | 958 | w.set_ctr_rx(true); // don't clear |
| 961 | w.set_ctr_rx(true); // don't clear | 959 | w.set_ctr_tx(true); // don't clear |
| 962 | w.set_ctr_tx(true); // don't clear | 960 | }); |
| 963 | }); | 961 | } |
| 962 | TX_PENDING[index].store(true, Ordering::Relaxed); | ||
| 964 | trace!("WRITE OK"); | 963 | trace!("WRITE OK"); |
| 965 | 964 | ||
| 966 | Ok(()) | 965 | Ok(()) |
