|
1 | | -use core::ptr::null_mut; |
| 1 | +use core::{ |
| 2 | + ops::{Deref, DerefMut}, |
| 3 | + ptr::null_mut, |
| 4 | +}; |
2 | 5 |
|
3 | 6 | use super::*; |
4 | 7 | use crate::soc::is_slice_in_dram; |
@@ -1000,3 +1003,89 @@ unsafe impl DmaRxBuffer for EmptyBuf { |
1000 | 1003 | 0 |
1001 | 1004 | } |
1002 | 1005 | } |
| 1006 | + |
| 1007 | +/// DMA Loop Buffer |
| 1008 | +/// |
| 1009 | +/// This consists of a single descriptor that points to itself and points to a |
| 1010 | +/// single buffer, resulting in the buffer being transmitted over and over |
| 1011 | +/// again, indefinitely. |
| 1012 | +/// |
| 1013 | +/// Note: A DMA descriptor is 12 bytes. If your buffer is significantly shorter |
| 1014 | +/// than this, the DMA channel will spend more time reading the descriptor than |
| 1015 | +/// it does reading the buffer, which may leave it unable to keep up with the |
| 1016 | +/// bandwidth requirements of some peripherals at high frequencies. |
| 1017 | +pub struct DmaLoopBuf { |
| 1018 | + descriptor: &'static mut DmaDescriptor, |
| 1019 | + buffer: &'static mut [u8], |
| 1020 | +} |
| 1021 | + |
| 1022 | +impl DmaLoopBuf { |
| 1023 | + /// Create a new [DmaLoopBuf]. |
| 1024 | + pub fn new( |
| 1025 | + descriptor: &'static mut DmaDescriptor, |
| 1026 | + buffer: &'static mut [u8], |
| 1027 | + ) -> Result<DmaLoopBuf, DmaBufError> { |
| 1028 | + if !is_slice_in_dram(buffer) { |
| 1029 | + return Err(DmaBufError::UnsupportedMemoryRegion); |
| 1030 | + } |
| 1031 | + if !is_slice_in_dram(core::slice::from_ref(descriptor)) { |
| 1032 | + return Err(DmaBufError::UnsupportedMemoryRegion); |
| 1033 | + } |
| 1034 | + |
| 1035 | + if buffer.len() > max_chunk_size(None) { |
| 1036 | + return Err(DmaBufError::InsufficientDescriptors); |
| 1037 | + } |
| 1038 | + |
| 1039 | + descriptor.set_owner(Owner::Dma); // Doesn't matter |
| 1040 | + descriptor.set_suc_eof(false); |
| 1041 | + descriptor.set_length(buffer.len()); |
| 1042 | + descriptor.set_size(buffer.len()); |
| 1043 | + descriptor.buffer = buffer.as_mut_ptr(); |
| 1044 | + descriptor.next = descriptor; |
| 1045 | + |
| 1046 | + Ok(Self { descriptor, buffer }) |
| 1047 | + } |
| 1048 | + |
| 1049 | + /// Consume the buf, returning the descriptor and buffer. |
| 1050 | + pub fn split(self) -> (&'static mut DmaDescriptor, &'static mut [u8]) { |
| 1051 | + (self.descriptor, self.buffer) |
| 1052 | + } |
| 1053 | +} |
| 1054 | + |
| 1055 | +unsafe impl DmaTxBuffer for DmaLoopBuf { |
| 1056 | + type View = Self; |
| 1057 | + |
| 1058 | + fn prepare(&mut self) -> Preparation { |
| 1059 | + Preparation { |
| 1060 | + start: self.descriptor, |
| 1061 | + block_size: None, |
| 1062 | + is_burstable: true, |
| 1063 | + } |
| 1064 | + } |
| 1065 | + |
| 1066 | + fn into_view(self) -> Self::View { |
| 1067 | + self |
| 1068 | + } |
| 1069 | + |
| 1070 | + fn from_view(view: Self::View) -> Self { |
| 1071 | + view |
| 1072 | + } |
| 1073 | + |
| 1074 | + fn length(&self) -> usize { |
| 1075 | + panic!("DmaLoopBuf does not have a length") |
| 1076 | + } |
| 1077 | +} |
| 1078 | + |
| 1079 | +impl Deref for DmaLoopBuf { |
| 1080 | + type Target = [u8]; |
| 1081 | + |
| 1082 | + fn deref(&self) -> &Self::Target { |
| 1083 | + self.buffer |
| 1084 | + } |
| 1085 | +} |
| 1086 | + |
| 1087 | +impl DerefMut for DmaLoopBuf { |
| 1088 | + fn deref_mut(&mut self) -> &mut Self::Target { |
| 1089 | + self.buffer |
| 1090 | + } |
| 1091 | +} |
0 commit comments