diff options
| author | xoviat <[email protected]> | 2025-11-25 03:34:54 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-25 03:34:54 +0000 |
| commit | 67f9d80d81bceca1fd53e64fff38729322556810 (patch) | |
| tree | 80ee08b08ddb82fe712da50b0a0859d4ded6b9b9 | |
| parent | 5ffb3698541674d57fddb22044ac0f06397c6113 (diff) | |
| parent | ee14305d152273254571d2a5a8192fad26f3ab73 (diff) | |
Merge pull request #4942 from xoviat/xspi
pull changes for xspi
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/hspi/mod.rs | 93 | ||||
| -rw-r--r-- | embassy-stm32/src/ospi/mod.rs | 60 | ||||
| -rw-r--r-- | embassy-stm32/src/xspi/mod.rs | 98 |
4 files changed, 147 insertions, 107 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index a66b2d437..6140b3238 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -40,7 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 40 | - feat: Configurable gpio speed for QSPI | 40 | - feat: Configurable gpio speed for QSPI |
| 41 | - feat: derive Clone, Copy and defmt::Format for all *SPI-related configs | 41 | - feat: derive Clone, Copy and defmt::Format for all *SPI-related configs |
| 42 | - fix: handle address and data-length errors in OSPI | 42 | - fix: handle address and data-length errors in OSPI |
| 43 | - feat: Allow OSPI DMA writes larger than 64kB using chunking | 43 | - feat: Allow OSPI/HSPI/XSPI DMA writes larger than 64kB using chunking |
| 44 | - feat: More ADC enums for g0 PAC, API change for oversampling, allow separate sample times | 44 | - feat: More ADC enums for g0 PAC, API change for oversampling, allow separate sample times |
| 45 | - feat: Add USB CRS sync support for STM32C071 | 45 | - feat: Add USB CRS sync support for STM32C071 |
| 46 | - fix: RTC register definition for STM32L4P5 and L4Q5 as they use v3 register map. | 46 | - fix: RTC register definition for STM32L4P5 and L4Q5 as they use v3 register map. |
| @@ -51,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 51 | - feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668)) | 51 | - feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668)) |
| 52 | - feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options | 52 | - feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options |
| 53 | - change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer | 53 | - change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer |
| 54 | - fix: Properly set the transfer size for OSPI/HSPI/XSPI transfers with word sizes other than 8 bits. | ||
| 54 | - fix: stm32/adc: Calculate the ADC prescaler in a way that it allows for the max frequency to be reached | 55 | - fix: stm32/adc: Calculate the ADC prescaler in a way that it allows for the max frequency to be reached |
| 55 | - fix: Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696) | 56 | - fix: Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696) |
| 56 | - change: timer: added output compare values | 57 | - change: timer: added output compare values |
diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs index 69baa708e..1d3560678 100644 --- a/embassy-stm32/src/hspi/mod.rs +++ b/embassy-stm32/src/hspi/mod.rs | |||
| @@ -391,7 +391,7 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> { | |||
| 391 | while T::REGS.sr().read().busy() {} | 391 | while T::REGS.sr().read().busy() {} |
| 392 | 392 | ||
| 393 | T::REGS.cr().modify(|w| { | 393 | T::REGS.cr().modify(|w| { |
| 394 | w.set_fmode(0.into()); | 394 | w.set_fmode(FunctionalMode::IndirectWrite.into()); |
| 395 | }); | 395 | }); |
| 396 | 396 | ||
| 397 | // Configure alternate bytes | 397 | // Configure alternate bytes |
| @@ -498,7 +498,8 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> { | |||
| 498 | w.set_dmaen(false); | 498 | w.set_dmaen(false); |
| 499 | }); | 499 | }); |
| 500 | 500 | ||
| 501 | self.configure_command(&transaction, Some(buf.len()))?; | 501 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 502 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 502 | 503 | ||
| 503 | let current_address = T::REGS.ar().read().address(); | 504 | let current_address = T::REGS.ar().read().address(); |
| 504 | let current_instruction = T::REGS.ir().read().instruction(); | 505 | let current_instruction = T::REGS.ir().read().instruction(); |
| @@ -537,7 +538,8 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> { | |||
| 537 | w.set_dmaen(false); | 538 | w.set_dmaen(false); |
| 538 | }); | 539 | }); |
| 539 | 540 | ||
| 540 | self.configure_command(&transaction, Some(buf.len()))?; | 541 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 542 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 541 | 543 | ||
| 542 | T::REGS | 544 | T::REGS |
| 543 | .cr() | 545 | .cr() |
| @@ -767,7 +769,8 @@ impl<'d, T: Instance> Hspi<'d, T, Async> { | |||
| 767 | // Wait for peripheral to be free | 769 | // Wait for peripheral to be free |
| 768 | while T::REGS.sr().read().busy() {} | 770 | while T::REGS.sr().read().busy() {} |
| 769 | 771 | ||
| 770 | self.configure_command(&transaction, Some(buf.len()))?; | 772 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 773 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 771 | 774 | ||
| 772 | let current_address = T::REGS.ar().read().address(); | 775 | let current_address = T::REGS.ar().read().address(); |
| 773 | let current_instruction = T::REGS.ir().read().instruction(); | 776 | let current_instruction = T::REGS.ir().read().instruction(); |
| @@ -782,16 +785,18 @@ impl<'d, T: Instance> Hspi<'d, T, Async> { | |||
| 782 | T::REGS.ar().write(|v| v.set_address(current_address)); | 785 | T::REGS.ar().write(|v| v.set_address(current_address)); |
| 783 | } | 786 | } |
| 784 | 787 | ||
| 785 | let transfer = unsafe { | 788 | for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) { |
| 786 | self.dma | 789 | let transfer = unsafe { |
| 787 | .as_mut() | 790 | self.dma |
| 788 | .unwrap() | 791 | .as_mut() |
| 789 | .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) | 792 | .unwrap() |
| 790 | }; | 793 | .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default()) |
| 794 | }; | ||
| 791 | 795 | ||
| 792 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 796 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 793 | 797 | ||
| 794 | transfer.blocking_wait(); | 798 | transfer.blocking_wait(); |
| 799 | } | ||
| 795 | 800 | ||
| 796 | finish_dma(T::REGS); | 801 | finish_dma(T::REGS); |
| 797 | 802 | ||
| @@ -807,21 +812,24 @@ impl<'d, T: Instance> Hspi<'d, T, Async> { | |||
| 807 | // Wait for peripheral to be free | 812 | // Wait for peripheral to be free |
| 808 | while T::REGS.sr().read().busy() {} | 813 | while T::REGS.sr().read().busy() {} |
| 809 | 814 | ||
| 810 | self.configure_command(&transaction, Some(buf.len()))?; | 815 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 816 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 811 | T::REGS | 817 | T::REGS |
| 812 | .cr() | 818 | .cr() |
| 813 | .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into())); | 819 | .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into())); |
| 814 | 820 | ||
| 815 | let transfer = unsafe { | 821 | for chunk in buf.chunks(0xFFFF / W::size().bytes()) { |
| 816 | self.dma | 822 | let transfer = unsafe { |
| 817 | .as_mut() | 823 | self.dma |
| 818 | .unwrap() | 824 | .as_mut() |
| 819 | .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) | 825 | .unwrap() |
| 820 | }; | 826 | .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default()) |
| 827 | }; | ||
| 821 | 828 | ||
| 822 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 829 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 823 | 830 | ||
| 824 | transfer.blocking_wait(); | 831 | transfer.blocking_wait(); |
| 832 | } | ||
| 825 | 833 | ||
| 826 | finish_dma(T::REGS); | 834 | finish_dma(T::REGS); |
| 827 | 835 | ||
| @@ -837,7 +845,8 @@ impl<'d, T: Instance> Hspi<'d, T, Async> { | |||
| 837 | // Wait for peripheral to be free | 845 | // Wait for peripheral to be free |
| 838 | while T::REGS.sr().read().busy() {} | 846 | while T::REGS.sr().read().busy() {} |
| 839 | 847 | ||
| 840 | self.configure_command(&transaction, Some(buf.len()))?; | 848 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 849 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 841 | 850 | ||
| 842 | let current_address = T::REGS.ar().read().address(); | 851 | let current_address = T::REGS.ar().read().address(); |
| 843 | let current_instruction = T::REGS.ir().read().instruction(); | 852 | let current_instruction = T::REGS.ir().read().instruction(); |
| @@ -852,16 +861,18 @@ impl<'d, T: Instance> Hspi<'d, T, Async> { | |||
| 852 | T::REGS.ar().write(|v| v.set_address(current_address)); | 861 | T::REGS.ar().write(|v| v.set_address(current_address)); |
| 853 | } | 862 | } |
| 854 | 863 | ||
| 855 | let transfer = unsafe { | 864 | for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) { |
| 856 | self.dma | 865 | let transfer = unsafe { |
| 857 | .as_mut() | 866 | self.dma |
| 858 | .unwrap() | 867 | .as_mut() |
| 859 | .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) | 868 | .unwrap() |
| 860 | }; | 869 | .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default()) |
| 870 | }; | ||
| 861 | 871 | ||
| 862 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 872 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 863 | 873 | ||
| 864 | transfer.await; | 874 | transfer.await; |
| 875 | } | ||
| 865 | 876 | ||
| 866 | finish_dma(T::REGS); | 877 | finish_dma(T::REGS); |
| 867 | 878 | ||
| @@ -877,21 +888,25 @@ impl<'d, T: Instance> Hspi<'d, T, Async> { | |||
| 877 | // Wait for peripheral to be free | 888 | // Wait for peripheral to be free |
| 878 | while T::REGS.sr().read().busy() {} | 889 | while T::REGS.sr().read().busy() {} |
| 879 | 890 | ||
| 880 | self.configure_command(&transaction, Some(buf.len()))?; | 891 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 892 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 881 | T::REGS | 893 | T::REGS |
| 882 | .cr() | 894 | .cr() |
| 883 | .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into())); | 895 | .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into())); |
| 884 | 896 | ||
| 885 | let transfer = unsafe { | 897 | // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU. |
| 886 | self.dma | 898 | for chunk in buf.chunks(0xFFFF / W::size().bytes()) { |
| 887 | .as_mut() | 899 | let transfer = unsafe { |
| 888 | .unwrap() | 900 | self.dma |
| 889 | .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) | 901 | .as_mut() |
| 890 | }; | 902 | .unwrap() |
| 903 | .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default()) | ||
| 904 | }; | ||
| 891 | 905 | ||
| 892 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 906 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 893 | 907 | ||
| 894 | transfer.await; | 908 | transfer.await; |
| 909 | } | ||
| 895 | 910 | ||
| 896 | finish_dma(T::REGS); | 911 | finish_dma(T::REGS); |
| 897 | 912 | ||
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 592a8594a..2d5dbd95a 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs | |||
| @@ -451,7 +451,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { | |||
| 451 | } | 451 | } |
| 452 | 452 | ||
| 453 | T::REGS.cr().modify(|w| { | 453 | T::REGS.cr().modify(|w| { |
| 454 | w.set_fmode(0.into()); | 454 | w.set_fmode(vals::FunctionalMode::INDIRECT_WRITE); |
| 455 | }); | 455 | }); |
| 456 | 456 | ||
| 457 | // Configure alternate bytes | 457 | // Configure alternate bytes |
| @@ -577,7 +577,8 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { | |||
| 577 | w.set_dmaen(false); | 577 | w.set_dmaen(false); |
| 578 | }); | 578 | }); |
| 579 | 579 | ||
| 580 | self.configure_command(&transaction, Some(buf.len()))?; | 580 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 581 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 581 | 582 | ||
| 582 | let current_address = T::REGS.ar().read().address(); | 583 | let current_address = T::REGS.ar().read().address(); |
| 583 | let current_instruction = T::REGS.ir().read().instruction(); | 584 | let current_instruction = T::REGS.ir().read().instruction(); |
| @@ -616,7 +617,8 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { | |||
| 616 | w.set_dmaen(false); | 617 | w.set_dmaen(false); |
| 617 | }); | 618 | }); |
| 618 | 619 | ||
| 619 | self.configure_command(&transaction, Some(buf.len()))?; | 620 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 621 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 620 | 622 | ||
| 621 | T::REGS | 623 | T::REGS |
| 622 | .cr() | 624 | .cr() |
| @@ -1153,7 +1155,8 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { | |||
| 1153 | // Wait for peripheral to be free | 1155 | // Wait for peripheral to be free |
| 1154 | while T::REGS.sr().read().busy() {} | 1156 | while T::REGS.sr().read().busy() {} |
| 1155 | 1157 | ||
| 1156 | self.configure_command(&transaction, Some(buf.len()))?; | 1158 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 1159 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 1157 | 1160 | ||
| 1158 | let current_address = T::REGS.ar().read().address(); | 1161 | let current_address = T::REGS.ar().read().address(); |
| 1159 | let current_instruction = T::REGS.ir().read().instruction(); | 1162 | let current_instruction = T::REGS.ir().read().instruction(); |
| @@ -1168,16 +1171,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { | |||
| 1168 | T::REGS.ar().write(|v| v.set_address(current_address)); | 1171 | T::REGS.ar().write(|v| v.set_address(current_address)); |
| 1169 | } | 1172 | } |
| 1170 | 1173 | ||
| 1171 | let transfer = unsafe { | 1174 | for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) { |
| 1172 | self.dma | 1175 | let transfer = unsafe { |
| 1173 | .as_mut() | 1176 | self.dma |
| 1174 | .unwrap() | 1177 | .as_mut() |
| 1175 | .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) | 1178 | .unwrap() |
| 1176 | }; | 1179 | .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default()) |
| 1180 | }; | ||
| 1177 | 1181 | ||
| 1178 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 1182 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 1179 | 1183 | ||
| 1180 | transfer.blocking_wait(); | 1184 | transfer.blocking_wait(); |
| 1185 | } | ||
| 1181 | 1186 | ||
| 1182 | finish_dma(T::REGS); | 1187 | finish_dma(T::REGS); |
| 1183 | 1188 | ||
| @@ -1193,13 +1198,14 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { | |||
| 1193 | // Wait for peripheral to be free | 1198 | // Wait for peripheral to be free |
| 1194 | while T::REGS.sr().read().busy() {} | 1199 | while T::REGS.sr().read().busy() {} |
| 1195 | 1200 | ||
| 1196 | self.configure_command(&transaction, Some(buf.len()))?; | 1201 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 1202 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 1197 | T::REGS | 1203 | T::REGS |
| 1198 | .cr() | 1204 | .cr() |
| 1199 | .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); | 1205 | .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); |
| 1200 | 1206 | ||
| 1201 | // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU. | 1207 | // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU. |
| 1202 | for chunk in buf.chunks(0xFFFF) { | 1208 | for chunk in buf.chunks(0xFFFF / W::size().bytes()) { |
| 1203 | let transfer = unsafe { | 1209 | let transfer = unsafe { |
| 1204 | self.dma | 1210 | self.dma |
| 1205 | .as_mut() | 1211 | .as_mut() |
| @@ -1226,7 +1232,8 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { | |||
| 1226 | // Wait for peripheral to be free | 1232 | // Wait for peripheral to be free |
| 1227 | while T::REGS.sr().read().busy() {} | 1233 | while T::REGS.sr().read().busy() {} |
| 1228 | 1234 | ||
| 1229 | self.configure_command(&transaction, Some(buf.len()))?; | 1235 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 1236 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 1230 | 1237 | ||
| 1231 | let current_address = T::REGS.ar().read().address(); | 1238 | let current_address = T::REGS.ar().read().address(); |
| 1232 | let current_instruction = T::REGS.ir().read().instruction(); | 1239 | let current_instruction = T::REGS.ir().read().instruction(); |
| @@ -1241,16 +1248,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { | |||
| 1241 | T::REGS.ar().write(|v| v.set_address(current_address)); | 1248 | T::REGS.ar().write(|v| v.set_address(current_address)); |
| 1242 | } | 1249 | } |
| 1243 | 1250 | ||
| 1244 | let transfer = unsafe { | 1251 | for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) { |
| 1245 | self.dma | 1252 | let transfer = unsafe { |
| 1246 | .as_mut() | 1253 | self.dma |
| 1247 | .unwrap() | 1254 | .as_mut() |
| 1248 | .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) | 1255 | .unwrap() |
| 1249 | }; | 1256 | .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default()) |
| 1257 | }; | ||
| 1250 | 1258 | ||
| 1251 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 1259 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 1252 | 1260 | ||
| 1253 | transfer.await; | 1261 | transfer.await; |
| 1262 | } | ||
| 1254 | 1263 | ||
| 1255 | finish_dma(T::REGS); | 1264 | finish_dma(T::REGS); |
| 1256 | 1265 | ||
| @@ -1266,13 +1275,14 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { | |||
| 1266 | // Wait for peripheral to be free | 1275 | // Wait for peripheral to be free |
| 1267 | while T::REGS.sr().read().busy() {} | 1276 | while T::REGS.sr().read().busy() {} |
| 1268 | 1277 | ||
| 1269 | self.configure_command(&transaction, Some(buf.len()))?; | 1278 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 1279 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 1270 | T::REGS | 1280 | T::REGS |
| 1271 | .cr() | 1281 | .cr() |
| 1272 | .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); | 1282 | .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); |
| 1273 | 1283 | ||
| 1274 | // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU. | 1284 | // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU. |
| 1275 | for chunk in buf.chunks(0xFFFF) { | 1285 | for chunk in buf.chunks(0xFFFF / W::size().bytes()) { |
| 1276 | let transfer = unsafe { | 1286 | let transfer = unsafe { |
| 1277 | self.dma | 1287 | self.dma |
| 1278 | .as_mut() | 1288 | .as_mut() |
diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs index a80a2692b..466e1a9b4 100644 --- a/embassy-stm32/src/xspi/mod.rs +++ b/embassy-stm32/src/xspi/mod.rs | |||
| @@ -420,9 +420,9 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { | |||
| 420 | return Err(XspiError::InvalidCommand); | 420 | return Err(XspiError::InvalidCommand); |
| 421 | } | 421 | } |
| 422 | 422 | ||
| 423 | T::REGS.cr().modify(|w| { | 423 | T::REGS |
| 424 | w.set_fmode(0.into()); | 424 | .cr() |
| 425 | }); | 425 | .modify(|w| w.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); |
| 426 | 426 | ||
| 427 | // Configure alternate bytes | 427 | // Configure alternate bytes |
| 428 | if let Some(ab) = command.alternate_bytes { | 428 | if let Some(ab) = command.alternate_bytes { |
| @@ -538,8 +538,8 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { | |||
| 538 | w.set_dmaen(false); | 538 | w.set_dmaen(false); |
| 539 | }); | 539 | }); |
| 540 | 540 | ||
| 541 | // self.configure_command(&transaction, Some(buf.len()))?; | 541 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 542 | self.configure_command(&transaction, Some(buf.len())).unwrap(); | 542 | self.configure_command(&transaction, Some(transfer_size_bytes))?; |
| 543 | 543 | ||
| 544 | let current_address = T::REGS.ar().read().address(); | 544 | let current_address = T::REGS.ar().read().address(); |
| 545 | let current_instruction = T::REGS.ir().read().instruction(); | 545 | let current_instruction = T::REGS.ir().read().instruction(); |
| @@ -578,7 +578,8 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { | |||
| 578 | w.set_dmaen(false); | 578 | w.set_dmaen(false); |
| 579 | }); | 579 | }); |
| 580 | 580 | ||
| 581 | self.configure_command(&transaction, Some(buf.len()))?; | 581 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 582 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 582 | 583 | ||
| 583 | T::REGS | 584 | T::REGS |
| 584 | .cr() | 585 | .cr() |
| @@ -1145,7 +1146,8 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { | |||
| 1145 | // Wait for peripheral to be free | 1146 | // Wait for peripheral to be free |
| 1146 | while T::REGS.sr().read().busy() {} | 1147 | while T::REGS.sr().read().busy() {} |
| 1147 | 1148 | ||
| 1148 | self.configure_command(&transaction, Some(buf.len()))?; | 1149 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 1150 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 1149 | 1151 | ||
| 1150 | let current_address = T::REGS.ar().read().address(); | 1152 | let current_address = T::REGS.ar().read().address(); |
| 1151 | let current_instruction = T::REGS.ir().read().instruction(); | 1153 | let current_instruction = T::REGS.ir().read().instruction(); |
| @@ -1160,16 +1162,18 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { | |||
| 1160 | T::REGS.ar().write(|v| v.set_address(current_address)); | 1162 | T::REGS.ar().write(|v| v.set_address(current_address)); |
| 1161 | } | 1163 | } |
| 1162 | 1164 | ||
| 1163 | let transfer = unsafe { | 1165 | for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) { |
| 1164 | self.dma | 1166 | let transfer = unsafe { |
| 1165 | .as_mut() | 1167 | self.dma |
| 1166 | .unwrap() | 1168 | .as_mut() |
| 1167 | .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) | 1169 | .unwrap() |
| 1168 | }; | 1170 | .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default()) |
| 1171 | }; | ||
| 1169 | 1172 | ||
| 1170 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 1173 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 1171 | 1174 | ||
| 1172 | transfer.blocking_wait(); | 1175 | transfer.blocking_wait(); |
| 1176 | } | ||
| 1173 | 1177 | ||
| 1174 | finish_dma(T::REGS); | 1178 | finish_dma(T::REGS); |
| 1175 | 1179 | ||
| @@ -1185,21 +1189,24 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { | |||
| 1185 | // Wait for peripheral to be free | 1189 | // Wait for peripheral to be free |
| 1186 | while T::REGS.sr().read().busy() {} | 1190 | while T::REGS.sr().read().busy() {} |
| 1187 | 1191 | ||
| 1188 | self.configure_command(&transaction, Some(buf.len()))?; | 1192 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 1193 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 1189 | T::REGS | 1194 | T::REGS |
| 1190 | .cr() | 1195 | .cr() |
| 1191 | .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); | 1196 | .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); |
| 1192 | 1197 | ||
| 1193 | let transfer = unsafe { | 1198 | for chunk in buf.chunks(0xFFFF / W::size().bytes()) { |
| 1194 | self.dma | 1199 | let transfer = unsafe { |
| 1195 | .as_mut() | 1200 | self.dma |
| 1196 | .unwrap() | 1201 | .as_mut() |
| 1197 | .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) | 1202 | .unwrap() |
| 1198 | }; | 1203 | .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default()) |
| 1204 | }; | ||
| 1199 | 1205 | ||
| 1200 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 1206 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 1201 | 1207 | ||
| 1202 | transfer.blocking_wait(); | 1208 | transfer.blocking_wait(); |
| 1209 | } | ||
| 1203 | 1210 | ||
| 1204 | finish_dma(T::REGS); | 1211 | finish_dma(T::REGS); |
| 1205 | 1212 | ||
| @@ -1215,7 +1222,8 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { | |||
| 1215 | // Wait for peripheral to be free | 1222 | // Wait for peripheral to be free |
| 1216 | while T::REGS.sr().read().busy() {} | 1223 | while T::REGS.sr().read().busy() {} |
| 1217 | 1224 | ||
| 1218 | self.configure_command(&transaction, Some(buf.len()))?; | 1225 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 1226 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 1219 | 1227 | ||
| 1220 | let current_address = T::REGS.ar().read().address(); | 1228 | let current_address = T::REGS.ar().read().address(); |
| 1221 | let current_instruction = T::REGS.ir().read().instruction(); | 1229 | let current_instruction = T::REGS.ir().read().instruction(); |
| @@ -1230,16 +1238,18 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { | |||
| 1230 | T::REGS.ar().write(|v| v.set_address(current_address)); | 1238 | T::REGS.ar().write(|v| v.set_address(current_address)); |
| 1231 | } | 1239 | } |
| 1232 | 1240 | ||
| 1233 | let transfer = unsafe { | 1241 | for chunk in buf.chunks_mut(0xFFFF / W::size().bytes()) { |
| 1234 | self.dma | 1242 | let transfer = unsafe { |
| 1235 | .as_mut() | 1243 | self.dma |
| 1236 | .unwrap() | 1244 | .as_mut() |
| 1237 | .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) | 1245 | .unwrap() |
| 1238 | }; | 1246 | .read(T::REGS.dr().as_ptr() as *mut W, chunk, Default::default()) |
| 1247 | }; | ||
| 1239 | 1248 | ||
| 1240 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 1249 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 1241 | 1250 | ||
| 1242 | transfer.await; | 1251 | transfer.await; |
| 1252 | } | ||
| 1243 | 1253 | ||
| 1244 | finish_dma(T::REGS); | 1254 | finish_dma(T::REGS); |
| 1245 | 1255 | ||
| @@ -1255,21 +1265,25 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { | |||
| 1255 | // Wait for peripheral to be free | 1265 | // Wait for peripheral to be free |
| 1256 | while T::REGS.sr().read().busy() {} | 1266 | while T::REGS.sr().read().busy() {} |
| 1257 | 1267 | ||
| 1258 | self.configure_command(&transaction, Some(buf.len()))?; | 1268 | let transfer_size_bytes = buf.len() * W::size().bytes(); |
| 1269 | self.configure_command(&transaction, Some(transfer_size_bytes))?; | ||
| 1259 | T::REGS | 1270 | T::REGS |
| 1260 | .cr() | 1271 | .cr() |
| 1261 | .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); | 1272 | .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); |
| 1262 | 1273 | ||
| 1263 | let transfer = unsafe { | 1274 | // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU. |
| 1264 | self.dma | 1275 | for chunk in buf.chunks(0xFFFF / W::size().bytes()) { |
| 1265 | .as_mut() | 1276 | let transfer = unsafe { |
| 1266 | .unwrap() | 1277 | self.dma |
| 1267 | .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) | 1278 | .as_mut() |
| 1268 | }; | 1279 | .unwrap() |
| 1280 | .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default()) | ||
| 1281 | }; | ||
| 1269 | 1282 | ||
| 1270 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | 1283 | T::REGS.cr().modify(|w| w.set_dmaen(true)); |
| 1271 | 1284 | ||
| 1272 | transfer.await; | 1285 | transfer.await; |
| 1286 | } | ||
| 1273 | 1287 | ||
| 1274 | finish_dma(T::REGS); | 1288 | finish_dma(T::REGS); |
| 1275 | 1289 | ||
