aboutsummaryrefslogtreecommitdiff
path: root/embassy-mcxa
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-12-05 20:45:59 +0100
committerJames Munns <[email protected]>2025-12-05 20:45:59 +0100
commit5d8f3a3d18eda339e258193295cf332d7e01882e (patch)
treecb20b9e64c682a1157896852a1123db38a3cf4e0 /embassy-mcxa
parent787bf84963ecd32306b6b2993504b2196f71cf72 (diff)
Clean up some common PAC operations using helper methods
Diffstat (limited to 'embassy-mcxa')
-rw-r--r--embassy-mcxa/src/dma.rs423
1 files changed, 147 insertions, 276 deletions
diff --git a/embassy-mcxa/src/dma.rs b/embassy-mcxa/src/dma.rs
index d563c2e29..b3ea94dbf 100644
--- a/embassy-mcxa/src/dma.rs
+++ b/embassy-mcxa/src/dma.rs
@@ -581,7 +581,6 @@ pub struct DmaChannel<C: Channel> {
581// - [`write_to_peripheral()`](DmaChannel::write_to_peripheral) - Memory-to-peripheral with custom eDMA TCD block 581// - [`write_to_peripheral()`](DmaChannel::write_to_peripheral) - Memory-to-peripheral with custom eDMA TCD block
582// - [`read_from_peripheral()`](DmaChannel::read_from_peripheral) - Peripheral-to-memory with custom eDMA TCD block 582// - [`read_from_peripheral()`](DmaChannel::read_from_peripheral) - Peripheral-to-memory with custom eDMA TCD block
583// - [`mem_to_mem()`](DmaChannel::mem_to_mem) - Memory-to-memory using default eDMA TCD block 583// - [`mem_to_mem()`](DmaChannel::mem_to_mem) - Memory-to-memory using default eDMA TCD block
584// - [`transfer_mem_to_mem()`](DmaChannel::transfer_mem_to_mem) - Memory-to-memory with custom eDMA TCD block
585// 584//
586// The `Transfer` manages the DMA lifecycle automatically: 585// The `Transfer` manages the DMA lifecycle automatically:
587// - Enables channel request 586// - Enables channel request
@@ -673,6 +672,87 @@ impl<C: Channel> DmaChannel<C> {
673 edma.tcd(C::INDEX) 672 edma.tcd(C::INDEX)
674 } 673 }
675 674
675 fn clear_tcd(t: &'static pac::edma_0_tcd0::Tcd) {
676 // Full TCD reset following NXP SDK pattern (EDMA_TcdResetExt).
677 // Reset ALL TCD registers to 0 to clear any stale configuration from
678 // previous transfers. This is critical when reusing a channel.
679 t.tcd_saddr().write(|w| unsafe { w.saddr().bits(0) });
680 t.tcd_soff().write(|w| unsafe { w.soff().bits(0) });
681 t.tcd_attr().write(|w| unsafe { w.bits(0) });
682 t.tcd_nbytes_mloffno().write(|w| unsafe { w.nbytes().bits(0) });
683 t.tcd_slast_sda().write(|w| unsafe { w.slast_sda().bits(0) });
684 t.tcd_daddr().write(|w| unsafe { w.daddr().bits(0) });
685 t.tcd_doff().write(|w| unsafe { w.doff().bits(0) });
686 t.tcd_citer_elinkno().write(|w| unsafe { w.bits(0) });
687 t.tcd_dlast_sga().write(|w| unsafe { w.dlast_sga().bits(0) });
688 t.tcd_csr().write(|w| unsafe { w.bits(0) }); // Clear CSR completely
689 t.tcd_biter_elinkno().write(|w| unsafe { w.bits(0) });
690 }
691
692 #[inline]
693 fn set_major_loop_ct_elinkno(t: &'static pac::edma_0_tcd0::Tcd, count: u16) {
694 t.tcd_biter_elinkno().write(|w| unsafe { w.biter().bits(count) });
695 t.tcd_citer_elinkno().write(|w| unsafe { w.citer().bits(count) });
696 }
697
698 #[inline]
699 fn set_minor_loop_ct_no_offsets(t: &'static pac::edma_0_tcd0::Tcd, count: u32) {
700 t.tcd_nbytes_mloffno().write(|w| unsafe { w.nbytes().bits(count) });
701 }
702
703 #[inline]
704 fn set_no_final_adjustments(t: &'static pac::edma_0_tcd0::Tcd) {
705 // No source/dest adjustment after major loop
706 t.tcd_slast_sda().write(|w| unsafe { w.slast_sda().bits(0) });
707 t.tcd_dlast_sga().write(|w| unsafe { w.dlast_sga().bits(0) });
708 }
709
710 #[inline]
711 fn set_source_ptr<T>(t: &'static pac::edma_0_tcd0::Tcd, p: *const T) {
712 t.tcd_saddr().write(|w| unsafe { w.saddr().bits(p as u32) });
713 }
714
715 #[inline]
716 fn set_source_increment(t: &'static pac::edma_0_tcd0::Tcd, sz: WordSize) {
717 t.tcd_soff().write(|w| unsafe { w.soff().bits(sz.bytes() as u16) });
718 }
719
720 #[inline]
721 fn set_source_fixed(t: &'static pac::edma_0_tcd0::Tcd) {
722 t.tcd_soff().write(|w| unsafe { w.soff().bits(0) });
723 }
724
725 #[inline]
726 fn set_dest_ptr<T>(t: &'static pac::edma_0_tcd0::Tcd, p: *mut T) {
727 t.tcd_daddr().write(|w| unsafe { w.daddr().bits(p as u32) });
728 }
729
730 #[inline]
731 fn set_dest_increment(t: &'static pac::edma_0_tcd0::Tcd, sz: WordSize) {
732 t.tcd_doff().write(|w| unsafe { w.doff().bits(sz.bytes() as u16) });
733 }
734
735 #[inline]
736 fn set_dest_fixed(t: &'static pac::edma_0_tcd0::Tcd) {
737 t.tcd_doff().write(|w| unsafe { w.doff().bits(0) });
738 }
739
740 #[inline]
741 fn set_even_transfer_size(t: &'static pac::edma_0_tcd0::Tcd, sz: WordSize) {
742 let hw_size = sz.to_hw_size();
743 t.tcd_attr().write(|w| unsafe { w.ssize().bits(hw_size).dsize().bits(hw_size) } );
744 }
745
746 #[inline]
747 fn reset_channel_state(t: &'static pac::edma_0_tcd0::Tcd) {
748 // CSR: Resets to all zeroes (disabled), "done" is cleared by writing 1
749 t.ch_csr().write(|w| w.done().clear_bit_by_one());
750 // ES: Resets to all zeroes (disabled), "err" is cleared by writing 1
751 t.ch_es().write(|w| w.err().clear_bit_by_one());
752 // INT: Resets to all zeroes (disabled), "int" is cleared by writing 1
753 t.ch_int().write(|w| w.int().clear_bit_by_one());
754 }
755
676 /// Start an async transfer. 756 /// Start an async transfer.
677 /// 757 ///
678 /// The channel must already be configured. This enables the channel 758 /// The channel must already be configured. This enables the channel
@@ -716,32 +796,7 @@ impl<C: Channel> DmaChannel<C> {
716 /// 796 ///
717 /// The source and destination buffers must remain valid for the 797 /// The source and destination buffers must remain valid for the
718 /// duration of the transfer. 798 /// duration of the transfer.
719 pub unsafe fn mem_to_mem<W: Word>(&self, src: &[W], dst: &mut [W], options: TransferOptions) -> Transfer<'_> { 799 pub fn mem_to_mem<W: Word>(&self, src: &[W], dst: &mut [W], options: TransferOptions) -> Transfer<'_> {
720 self.transfer_mem_to_mem(src, dst, options)
721 }
722
723 /// Perform a memory-to-memory DMA transfer.
724 ///
725 /// This is a type-safe wrapper that uses the `Word` trait to determine
726 /// the correct transfer width automatically.
727 ///
728 /// # Arguments
729 ///
730 /// * `edma` - Reference to the eDMA TCD register block
731 /// * `src` - Source buffer
732 /// * `dst` - Destination buffer (must be at least as large as src)
733 /// * `options` - Transfer configuration options
734 ///
735 /// # Safety
736 ///
737 /// The source and destination buffers must remain valid for the
738 /// duration of the transfer.
739 pub unsafe fn transfer_mem_to_mem<W: Word>(
740 &self,
741 src: &[W],
742 dst: &mut [W],
743 options: TransferOptions,
744 ) -> Transfer<'_> {
745 assert!(!src.is_empty()); 800 assert!(!src.is_empty());
746 assert!(dst.len() >= src.len()); 801 assert!(dst.len() >= src.len());
747 assert!(src.len() <= 0x7fff); 802 assert!(src.len() <= 0x7fff);
@@ -752,36 +807,12 @@ impl<C: Channel> DmaChannel<C> {
752 let t = self.tcd(); 807 let t = self.tcd();
753 808
754 // Reset channel state - clear DONE, disable requests, clear errors 809 // Reset channel state - clear DONE, disable requests, clear errors
755 t.ch_csr().write(|w| { 810 Self::reset_channel_state(t);
756 w.erq()
757 .disable()
758 .earq()
759 .disable()
760 .eei()
761 .no_error()
762 .done()
763 .clear_bit_by_one()
764 });
765 t.ch_es().write(|w| w.err().clear_bit_by_one());
766 t.ch_int().write(|w| w.int().clear_bit_by_one());
767 811
768 // Memory barrier to ensure channel state is fully reset before touching TCD 812 // Memory barrier to ensure channel state is fully reset before touching TCD
769 cortex_m::asm::dsb(); 813 cortex_m::asm::dsb();
770 814
771 // Full TCD reset following NXP SDK pattern (EDMA_TcdResetExt). 815 Self::clear_tcd(t);
772 // Reset ALL TCD registers to 0 to clear any stale configuration from
773 // previous transfers. This is critical when reusing a channel.
774 t.tcd_saddr().write(|w| w.saddr().bits(0));
775 t.tcd_soff().write(|w| w.soff().bits(0));
776 t.tcd_attr().write(|w| w.bits(0));
777 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(0));
778 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0));
779 t.tcd_daddr().write(|w| w.daddr().bits(0));
780 t.tcd_doff().write(|w| w.doff().bits(0));
781 t.tcd_citer_elinkno().write(|w| w.bits(0));
782 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(0));
783 t.tcd_csr().write(|w| w.bits(0)); // Clear CSR completely
784 t.tcd_biter_elinkno().write(|w| w.bits(0));
785 816
786 // Memory barrier after TCD reset 817 // Memory barrier after TCD reset
787 cortex_m::asm::dsb(); 818 cortex_m::asm::dsb();
@@ -792,28 +823,25 @@ impl<C: Channel> DmaChannel<C> {
792 // Now configure the new transfer 823 // Now configure the new transfer
793 824
794 // Source address and increment 825 // Source address and increment
795 t.tcd_saddr().write(|w| w.saddr().bits(src.as_ptr() as u32)); 826 Self::set_source_ptr(t, src.as_ptr());
796 t.tcd_soff().write(|w| w.soff().bits(size.bytes() as u16)); 827 Self::set_source_increment(t, size);
797 828
798 // Destination address and increment 829 // Destination address and increment
799 t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32)); 830 Self::set_dest_ptr(t, dst.as_mut_ptr());
800 t.tcd_doff().write(|w| w.doff().bits(size.bytes() as u16)); 831 Self::set_dest_increment(t, size);
801 832
802 // Transfer attributes (size) 833 // Transfer attributes (size)
803 let hw_size = size.to_hw_size(); 834 Self::set_even_transfer_size(t, size);
804 t.tcd_attr().write(|w| w.ssize().bits(hw_size).dsize().bits(hw_size));
805 835
806 // Minor loop: transfer all bytes in one minor loop 836 // Minor loop: transfer all bytes in one minor loop
807 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(byte_count)); 837 Self::set_minor_loop_ct_no_offsets(t, byte_count);
808 838
809 // No source/dest adjustment after major loop 839 // No source/dest adjustment after major loop
810 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); 840 Self::set_no_final_adjustments(t);
811 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(0));
812 841
813 // Major loop count = 1 (single major loop) 842 // Major loop count = 1 (single major loop)
814 // Write BITER first, then CITER (CITER must match BITER at start) 843 // Write BITER first, then CITER (CITER must match BITER at start)
815 t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); 844 Self::set_major_loop_ct_elinkno(t, 1);
816 t.tcd_citer_elinkno().write(|w| w.citer().bits(1));
817 845
818 // Memory barrier before setting START 846 // Memory barrier before setting START
819 cortex_m::asm::dsb(); 847 cortex_m::asm::dsb();
@@ -862,10 +890,7 @@ impl<C: Channel> DmaChannel<C> {
862 /// // buffer is now filled with 0xDEADBEEF 890 /// // buffer is now filled with 0xDEADBEEF
863 /// ``` 891 /// ```
864 /// 892 ///
865 /// # Safety 893 pub fn memset<W: Word>(&self, pattern: &W, dst: &mut [W], options: TransferOptions) -> Transfer<'_> {
866 ///
867 /// - The pattern and destination buffer must remain valid for the duration of the transfer.
868 pub unsafe fn memset<W: Word>(&self, pattern: &W, dst: &mut [W], options: TransferOptions) -> Transfer<'_> {
869 assert!(!dst.is_empty()); 894 assert!(!dst.is_empty());
870 assert!(dst.len() <= 0x7fff); 895 assert!(dst.len() <= 0x7fff);
871 896
@@ -877,36 +902,12 @@ impl<C: Channel> DmaChannel<C> {
877 let t = self.tcd(); 902 let t = self.tcd();
878 903
879 // Reset channel state - clear DONE, disable requests, clear errors 904 // Reset channel state - clear DONE, disable requests, clear errors
880 t.ch_csr().write(|w| { 905 Self::reset_channel_state(t);
881 w.erq()
882 .disable()
883 .earq()
884 .disable()
885 .eei()
886 .no_error()
887 .done()
888 .clear_bit_by_one()
889 });
890 t.ch_es().write(|w| w.err().clear_bit_by_one());
891 t.ch_int().write(|w| w.int().clear_bit_by_one());
892 906
893 // Memory barrier to ensure channel state is fully reset before touching TCD 907 // Memory barrier to ensure channel state is fully reset before touching TCD
894 cortex_m::asm::dsb(); 908 cortex_m::asm::dsb();
895 909
896 // Full TCD reset following NXP SDK pattern (EDMA_TcdResetExt). 910 Self::clear_tcd(t);
897 // Reset ALL TCD registers to 0 to clear any stale configuration from
898 // previous transfers. This is critical when reusing a channel.
899 t.tcd_saddr().write(|w| w.saddr().bits(0));
900 t.tcd_soff().write(|w| w.soff().bits(0));
901 t.tcd_attr().write(|w| w.bits(0));
902 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(0));
903 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0));
904 t.tcd_daddr().write(|w| w.daddr().bits(0));
905 t.tcd_doff().write(|w| w.doff().bits(0));
906 t.tcd_citer_elinkno().write(|w| w.bits(0));
907 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(0));
908 t.tcd_csr().write(|w| w.bits(0)); // Clear CSR completely
909 t.tcd_biter_elinkno().write(|w| w.bits(0));
910 911
911 // Memory barrier after TCD reset 912 // Memory barrier after TCD reset
912 cortex_m::asm::dsb(); 913 cortex_m::asm::dsb();
@@ -923,29 +924,26 @@ impl<C: Channel> DmaChannel<C> {
923 // START triggers. 924 // START triggers.
924 925
925 // Source: pattern address, fixed (soff=0) 926 // Source: pattern address, fixed (soff=0)
926 t.tcd_saddr().write(|w| w.saddr().bits(pattern as *const W as u32)); 927 Self::set_source_ptr(t, pattern);
927 t.tcd_soff().write(|w| w.soff().bits(0)); // Fixed source - reads pattern repeatedly 928 Self::set_source_fixed(t);
928 929
929 // Destination: memory buffer, incrementing by word size 930 // Destination: memory buffer, incrementing by word size
930 t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32)); 931 Self::set_dest_ptr(t, dst.as_mut_ptr());
931 t.tcd_doff().write(|w| w.doff().bits(byte_size as u16)); 932 Self::set_dest_increment(t, size);
932 933
933 // Transfer attributes - source and dest are same word size 934 // Transfer attributes - source and dest are same word size
934 let hw_size = size.to_hw_size(); 935 Self::set_even_transfer_size(t, size);
935 t.tcd_attr().write(|w| w.ssize().bits(hw_size).dsize().bits(hw_size));
936 936
937 // Minor loop: transfer ALL bytes in one minor loop (like mem_to_mem) 937 // Minor loop: transfer ALL bytes in one minor loop (like mem_to_mem)
938 // This allows the entire transfer to complete with a single START trigger 938 // This allows the entire transfer to complete with a single START trigger
939 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(total_bytes)); 939 Self::set_minor_loop_ct_no_offsets(t, total_bytes);
940 940
941 // No address adjustment after major loop 941 // No address adjustment after major loop
942 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); 942 Self::set_no_final_adjustments(t);
943 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(0));
944 943
945 // Major loop count = 1 (single major loop, all data in minor loop) 944 // Major loop count = 1 (single major loop, all data in minor loop)
946 // Write BITER first, then CITER (CITER must match BITER at start) 945 // Write BITER first, then CITER (CITER must match BITER at start)
947 t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); 946 Self::set_major_loop_ct_elinkno(t, 1);
948 t.tcd_citer_elinkno().write(|w| w.citer().bits(1));
949 947
950 // Memory barrier before setting START 948 // Memory barrier before setting START
951 cortex_m::asm::dsb(); 949 cortex_m::asm::dsb();
@@ -1066,42 +1064,28 @@ impl<C: Channel> DmaChannel<C> {
1066 let t = self.tcd(); 1064 let t = self.tcd();
1067 1065
1068 // Reset channel state 1066 // Reset channel state
1069 t.ch_csr().write(|w| w.erq().disable().done().clear_bit_by_one()); 1067 Self::reset_channel_state(t);
1070 t.ch_es().write(|w| w.bits(0));
1071 t.ch_int().write(|w| w.int().clear_bit_by_one());
1072 1068
1073 // Addresses 1069 // Addresses
1074 t.tcd_saddr().write(|w| w.saddr().bits(buf.as_ptr() as u32)); 1070 Self::set_source_ptr(t, buf.as_ptr());
1075 t.tcd_daddr().write(|w| w.daddr().bits(peri_addr as u32)); 1071 t.tcd_daddr().write(|w| w.daddr().bits(peri_addr as u32));
1076 1072
1077 // Offsets: Source increments, Dest fixed 1073 // Offsets: Source increments, Dest fixed
1078 t.tcd_soff().write(|w| w.soff().bits(byte_size as u16)); 1074 Self::set_source_increment(t, size);
1079 t.tcd_doff().write(|w| w.doff().bits(0)); 1075 Self::set_dest_fixed(t);
1080 1076
1081 // Attributes: set size and explicitly disable modulo 1077 // Attributes: set size and explicitly disable modulo
1082 let hw_size = size.to_hw_size(); 1078 Self::set_even_transfer_size(t, size);
1083 t.tcd_attr().write(|w| {
1084 w.ssize()
1085 .bits(hw_size)
1086 .dsize()
1087 .bits(hw_size)
1088 .smod()
1089 .disable()
1090 .dmod()
1091 .bits(0)
1092 });
1093 1079
1094 // Minor loop: transfer one word per request (match old: only set nbytes) 1080 // Minor loop: transfer one word per request (match old: only set nbytes)
1095 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(byte_size as u32)); 1081 Self::set_minor_loop_ct_no_offsets(t, byte_size as u32);
1096 1082
1097 // No final adjustments 1083 // No final adjustments
1098 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); 1084 Self::set_no_final_adjustments(t);
1099 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(0));
1100 1085
1101 // Major loop count = number of words 1086 // Major loop count = number of words
1102 let count = buf.len() as u16; 1087 let count = buf.len() as u16;
1103 t.tcd_citer_elinkno().write(|w| w.citer().bits(count).elink().disable()); 1088 Self::set_major_loop_ct_elinkno(t, count);
1104 t.tcd_biter_elinkno().write(|w| w.biter().bits(count).elink().disable());
1105 1089
1106 // CSR: interrupt on major loop complete and auto-clear ERQ 1090 // CSR: interrupt on major loop complete and auto-clear ERQ
1107 t.tcd_csr().write(|w| { 1091 t.tcd_csr().write(|w| {
@@ -1232,60 +1216,28 @@ impl<C: Channel> DmaChannel<C> {
1232 let t = self.tcd(); 1216 let t = self.tcd();
1233 1217
1234 // Reset channel control/error/interrupt state 1218 // Reset channel control/error/interrupt state
1235 t.ch_csr().write(|w| { 1219 Self::reset_channel_state(t);
1236 w.erq()
1237 .disable()
1238 .earq()
1239 .disable()
1240 .eei()
1241 .no_error()
1242 .ebw()
1243 .disable()
1244 .done()
1245 .clear_bit_by_one()
1246 });
1247 t.ch_es().write(|w| w.bits(0));
1248 t.ch_int().write(|w| w.int().clear_bit_by_one());
1249 1220
1250 // Source: peripheral register, fixed 1221 // Source: peripheral register, fixed
1251 t.tcd_saddr().write(|w| w.saddr().bits(peri_addr as u32)); 1222 Self::set_source_ptr(t, peri_addr);
1252 t.tcd_soff().write(|w| w.soff().bits(0)); // No increment 1223 Self::set_source_fixed(t);
1253 1224
1254 // Destination: memory buffer, incrementing 1225 // Destination: memory buffer, incrementing
1255 t.tcd_daddr().write(|w| w.daddr().bits(buf.as_mut_ptr() as u32)); 1226 Self::set_dest_ptr(t, buf.as_mut_ptr());
1256 t.tcd_doff().write(|w| w.doff().bits(byte_size as u16)); 1227 Self::set_dest_increment(t, size);
1257 1228
1258 // Transfer attributes: set size and explicitly disable modulo 1229 // Transfer attributes: set size and explicitly disable modulo
1259 let hw_size = size.to_hw_size(); 1230 Self::set_even_transfer_size(t, size);
1260 t.tcd_attr().write(|w| {
1261 w.ssize()
1262 .bits(hw_size)
1263 .dsize()
1264 .bits(hw_size)
1265 .smod()
1266 .disable()
1267 .dmod()
1268 .bits(0)
1269 });
1270 1231
1271 // Minor loop: transfer one word per request, no offsets 1232 // Minor loop: transfer one word per request, no offsets
1272 t.tcd_nbytes_mloffno().write(|w| { 1233 Self::set_minor_loop_ct_no_offsets(t, byte_size as u32);
1273 w.nbytes()
1274 .bits(byte_size as u32)
1275 .dmloe()
1276 .offset_not_applied()
1277 .smloe()
1278 .offset_not_applied()
1279 });
1280 1234
1281 // Major loop count = number of words 1235 // Major loop count = number of words
1282 let count = buf.len() as u16; 1236 let count = buf.len() as u16;
1283 t.tcd_citer_elinkno().write(|w| w.citer().bits(count).elink().disable()); 1237 Self::set_major_loop_ct_elinkno(t, count);
1284 t.tcd_biter_elinkno().write(|w| w.biter().bits(count).elink().disable());
1285 1238
1286 // No address adjustment after major loop 1239 // No address adjustment after major loop
1287 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); 1240 Self::set_no_final_adjustments(t);
1288 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(0));
1289 1241
1290 // Control/status: interrupt on major complete, auto-clear ERQ when done 1242 // Control/status: interrupt on major complete, auto-clear ERQ when done
1291 t.tcd_csr().write(|w| { 1243 t.tcd_csr().write(|w| {
@@ -1356,42 +1308,28 @@ impl<C: Channel> DmaChannel<C> {
1356 let t = self.tcd(); 1308 let t = self.tcd();
1357 1309
1358 // Reset channel state 1310 // Reset channel state
1359 t.ch_csr().write(|w| w.erq().disable().done().clear_bit_by_one()); 1311 Self::reset_channel_state(t);
1360 t.ch_es().write(|w| w.bits(0));
1361 t.ch_int().write(|w| w.int().clear_bit_by_one());
1362 1312
1363 // Addresses 1313 // Addresses
1364 t.tcd_saddr().write(|w| w.saddr().bits(buf.as_ptr() as u32)); 1314 Self::set_source_ptr(t, buf.as_ptr());
1365 t.tcd_daddr().write(|w| w.daddr().bits(peri_addr as u32)); 1315 Self::set_dest_ptr(t, peri_addr);
1366 1316
1367 // Offsets: Source increments, Dest fixed 1317 // Offsets: Source increments, Dest fixed
1368 t.tcd_soff().write(|w| w.soff().bits(byte_size as u16)); 1318 Self::set_source_increment(t, size);
1369 t.tcd_doff().write(|w| w.doff().bits(0)); 1319 Self::set_dest_fixed(t);
1370 1320
1371 // Attributes: set size and explicitly disable modulo 1321 // Attributes: set size and explicitly disable modulo
1372 let hw_size = size.to_hw_size(); 1322 Self::set_even_transfer_size(t, size);
1373 t.tcd_attr().write(|w| {
1374 w.ssize()
1375 .bits(hw_size)
1376 .dsize()
1377 .bits(hw_size)
1378 .smod()
1379 .disable()
1380 .dmod()
1381 .bits(0)
1382 });
1383 1323
1384 // Minor loop: transfer one word per request 1324 // Minor loop: transfer one word per request
1385 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(byte_size as u32)); 1325 Self::set_minor_loop_ct_no_offsets(t, byte_size as u32);
1386 1326
1387 // No final adjustments 1327 // No final adjustments
1388 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); 1328 Self::set_no_final_adjustments(t);
1389 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(0));
1390 1329
1391 // Major loop count = number of words 1330 // Major loop count = number of words
1392 let count = buf.len() as u16; 1331 let count = buf.len() as u16;
1393 t.tcd_citer_elinkno().write(|w| w.citer().bits(count).elink().disable()); 1332 Self::set_major_loop_ct_elinkno(t, count);
1394 t.tcd_biter_elinkno().write(|w| w.biter().bits(count).elink().disable());
1395 1333
1396 // CSR: optional interrupt on major loop complete and auto-clear ERQ 1334 // CSR: optional interrupt on major loop complete and auto-clear ERQ
1397 t.tcd_csr().write(|w| { 1335 t.tcd_csr().write(|w| {
@@ -1456,53 +1394,28 @@ impl<C: Channel> DmaChannel<C> {
1456 let t = self.tcd(); 1394 let t = self.tcd();
1457 1395
1458 // Reset channel control/error/interrupt state 1396 // Reset channel control/error/interrupt state
1459 t.ch_csr().write(|w| { 1397 Self::reset_channel_state(t);
1460 w.erq()
1461 .disable()
1462 .earq()
1463 .disable()
1464 .eei()
1465 .no_error()
1466 .ebw()
1467 .disable()
1468 .done()
1469 .clear_bit_by_one()
1470 });
1471 t.ch_es().write(|w| w.bits(0));
1472 t.ch_int().write(|w| w.int().clear_bit_by_one());
1473 1398
1474 // Source: peripheral register, fixed 1399 // Source: peripheral register, fixed
1475 t.tcd_saddr().write(|w| w.saddr().bits(peri_addr as u32)); 1400 Self::set_source_ptr(t, peri_addr);
1476 t.tcd_soff().write(|w| w.soff().bits(0)); 1401 Self::set_source_fixed(t);
1477 1402
1478 // Destination: memory buffer, incrementing 1403 // Destination: memory buffer, incrementing
1479 t.tcd_daddr().write(|w| w.daddr().bits(buf.as_mut_ptr() as u32)); 1404 Self::set_dest_ptr(t, buf.as_mut_ptr());
1480 t.tcd_doff().write(|w| w.doff().bits(byte_size as u16)); 1405 Self::set_dest_increment(t, size);
1481 1406
1482 // Attributes: set size and explicitly disable modulo 1407 // Attributes: set size and explicitly disable modulo
1483 let hw_size = size.to_hw_size(); 1408 Self::set_even_transfer_size(t, size);
1484 t.tcd_attr().write(|w| {
1485 w.ssize()
1486 .bits(hw_size)
1487 .dsize()
1488 .bits(hw_size)
1489 .smod()
1490 .disable()
1491 .dmod()
1492 .bits(0)
1493 });
1494 1409
1495 // Minor loop: transfer one word per request 1410 // Minor loop: transfer one word per request
1496 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(byte_size as u32)); 1411 Self::set_minor_loop_ct_no_offsets(t, byte_size as u32);
1497 1412
1498 // No final adjustments 1413 // No final adjustments
1499 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); 1414 Self::set_no_final_adjustments(t);
1500 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(0));
1501 1415
1502 // Major loop count = number of words 1416 // Major loop count = number of words
1503 let count = buf.len() as u16; 1417 let count = buf.len() as u16;
1504 t.tcd_citer_elinkno().write(|w| w.citer().bits(count).elink().disable()); 1418 Self::set_major_loop_ct_elinkno(t, count);
1505 t.tcd_biter_elinkno().write(|w| w.biter().bits(count).elink().disable());
1506 1419
1507 // CSR: optional interrupt on major loop complete and auto-clear ERQ 1420 // CSR: optional interrupt on major loop complete and auto-clear ERQ
1508 t.tcd_csr().write(|w| { 1421 t.tcd_csr().write(|w| {
@@ -2233,56 +2146,25 @@ impl<C: Channel> DmaChannel<C> {
2233 let t = self.tcd(); 2146 let t = self.tcd();
2234 2147
2235 // Reset channel state 2148 // Reset channel state
2236 t.ch_csr().write(|w| { 2149 Self::reset_channel_state(t);
2237 w.erq()
2238 .disable()
2239 .earq()
2240 .disable()
2241 .eei()
2242 .no_error()
2243 .ebw()
2244 .disable()
2245 .done()
2246 .clear_bit_by_one()
2247 });
2248 t.ch_es().write(|w| w.bits(0));
2249 t.ch_int().write(|w| w.int().clear_bit_by_one());
2250 2150
2251 // Source: peripheral register, fixed 2151 // Source: peripheral register, fixed
2252 t.tcd_saddr().write(|w| w.saddr().bits(peri_addr as u32)); 2152 Self::set_source_ptr(t, peri_addr);
2253 t.tcd_soff().write(|w| w.soff().bits(0)); // No increment 2153 Self::set_source_fixed(t);
2254 2154
2255 // Destination: memory buffer, incrementing 2155 // Destination: memory buffer, incrementing
2256 t.tcd_daddr().write(|w| w.daddr().bits(buf.as_mut_ptr() as u32)); 2156 Self::set_dest_ptr(t, buf.as_mut_ptr());
2257 t.tcd_doff().write(|w| w.doff().bits(byte_size as u16)); 2157 Self::set_dest_increment(t, size);
2258 2158
2259 // Transfer attributes 2159 // Transfer attributes
2260 let hw_size = size.to_hw_size(); 2160 Self::set_even_transfer_size(t, size);
2261 t.tcd_attr().write(|w| {
2262 w.ssize()
2263 .bits(hw_size)
2264 .dsize()
2265 .bits(hw_size)
2266 .smod()
2267 .disable()
2268 .dmod()
2269 .bits(0)
2270 });
2271 2161
2272 // Minor loop: transfer one word per request 2162 // Minor loop: transfer one word per request
2273 t.tcd_nbytes_mloffno().write(|w| { 2163 Self::set_minor_loop_ct_no_offsets(t, byte_size as u32);
2274 w.nbytes()
2275 .bits(byte_size as u32)
2276 .dmloe()
2277 .offset_not_applied()
2278 .smloe()
2279 .offset_not_applied()
2280 });
2281 2164
2282 // Major loop count = buffer size 2165 // Major loop count = buffer size
2283 let count = buf.len() as u16; 2166 let count = buf.len() as u16;
2284 t.tcd_citer_elinkno().write(|w| w.citer().bits(count).elink().disable()); 2167 Self::set_major_loop_ct_elinkno(t, count);
2285 t.tcd_biter_elinkno().write(|w| w.biter().bits(count).elink().disable());
2286 2168
2287 // After major loop: reset destination to buffer start (circular) 2169 // After major loop: reset destination to buffer start (circular)
2288 let buf_bytes = (buf.len() * byte_size) as i32; 2170 let buf_bytes = (buf.len() * byte_size) as i32;
@@ -2475,18 +2357,7 @@ impl<W: Word> ScatterGatherBuilder<W> {
2475 2357
2476 // Reset channel state - clear DONE, disable requests, clear errors 2358 // Reset channel state - clear DONE, disable requests, clear errors
2477 // This ensures the channel is in a clean state before loading the TCD 2359 // This ensures the channel is in a clean state before loading the TCD
2478 t.ch_csr().write(|w| { 2360 Self::reset_channel_state(t);
2479 w.erq()
2480 .disable()
2481 .earq()
2482 .disable()
2483 .eei()
2484 .no_error()
2485 .done()
2486 .clear_bit_by_one()
2487 });
2488 t.ch_es().write(|w| w.err().clear_bit_by_one());
2489 t.ch_int().write(|w| w.int().clear_bit_by_one());
2490 2361
2491 // Memory barrier to ensure channel state is reset before loading TCD 2362 // Memory barrier to ensure channel state is reset before loading TCD
2492 cortex_m::asm::dsb(); 2363 cortex_m::asm::dsb();