|
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; |
@@ -1046,3 +1049,91 @@ unsafe impl DmaRxBuffer for EmptyBuf { |
1046 | 1049 | 0 |
1047 | 1050 | } |
1048 | 1051 | } |
| 1052 | + |
| 1053 | +/// DMA Loop Buffer |
| 1054 | +/// |
| 1055 | +/// This consists of a single descriptor that points to itself and points to a |
| 1056 | +/// single buffer, resulting in the buffer being transmitted over and over |
| 1057 | +/// again, indefinitely. |
| 1058 | +/// |
| 1059 | +/// Note: A DMA descriptor is 12 bytes. If your buffer is significantly shorter |
| 1060 | +/// than this, the DMA channel will spend more time reading the descriptor than |
| 1061 | +/// it does reading the buffer, which may leave it unable to keep up with the |
| 1062 | +/// bandwidth requirements of some peripherals at high frequencies. |
| 1063 | +pub struct DmaLoopBuf { |
| 1064 | + descriptor: &'static mut DmaDescriptor, |
| 1065 | + buffer: &'static mut [u8], |
| 1066 | +} |
| 1067 | + |
| 1068 | +impl DmaLoopBuf { |
| 1069 | + /// Create a new [DmaLoopBuf]. |
| 1070 | + pub fn new( |
| 1071 | + descriptor: &'static mut DmaDescriptor, |
| 1072 | + buffer: &'static mut [u8], |
| 1073 | + ) -> Result<DmaLoopBuf, DmaBufError> { |
| 1074 | + if !is_slice_in_dram(buffer) { |
| 1075 | + return Err(DmaBufError::UnsupportedMemoryRegion); |
| 1076 | + } |
| 1077 | + if !is_slice_in_dram(core::slice::from_ref(descriptor)) { |
| 1078 | + return Err(DmaBufError::UnsupportedMemoryRegion); |
| 1079 | + } |
| 1080 | + |
| 1081 | + if buffer.len() > max_chunk_size(None) { |
| 1082 | + return Err(DmaBufError::InsufficientDescriptors); |
| 1083 | + } |
| 1084 | + |
| 1085 | + descriptor.set_owner(Owner::Dma); // Doesn't matter |
| 1086 | + descriptor.set_suc_eof(false); |
| 1087 | + descriptor.set_length(buffer.len()); |
| 1088 | + descriptor.set_size(buffer.len()); |
| 1089 | + descriptor.buffer = buffer.as_mut_ptr(); |
| 1090 | + descriptor.next = descriptor; |
| 1091 | + |
| 1092 | + Ok(Self { descriptor, buffer }) |
| 1093 | + } |
| 1094 | + |
| 1095 | + /// Consume the buf, returning the descriptor and buffer. |
| 1096 | + pub fn split(self) -> (&'static mut DmaDescriptor, &'static mut [u8]) { |
| 1097 | + (self.descriptor, self.buffer) |
| 1098 | + } |
| 1099 | +} |
| 1100 | + |
| 1101 | +unsafe impl DmaTxBuffer for DmaLoopBuf { |
| 1102 | + type View = Self; |
| 1103 | + |
| 1104 | + fn prepare(&mut self) -> Preparation { |
| 1105 | + Preparation { |
| 1106 | + start: self.descriptor, |
| 1107 | + block_size: None, |
| 1108 | + is_burstable: true, |
| 1109 | + // The DMA must not check the owner bit, as it is never set. |
| 1110 | + check_owner: Some(false), |
| 1111 | + } |
| 1112 | + } |
| 1113 | + |
| 1114 | + fn into_view(self) -> Self::View { |
| 1115 | + self |
| 1116 | + } |
| 1117 | + |
| 1118 | + fn from_view(view: Self::View) -> Self { |
| 1119 | + view |
| 1120 | + } |
| 1121 | + |
| 1122 | + fn length(&self) -> usize { |
| 1123 | + panic!("DmaLoopBuf does not have a length") |
| 1124 | + } |
| 1125 | +} |
| 1126 | + |
| 1127 | +impl Deref for DmaLoopBuf { |
| 1128 | + type Target = [u8]; |
| 1129 | + |
| 1130 | + fn deref(&self) -> &Self::Target { |
| 1131 | + self.buffer |
| 1132 | + } |
| 1133 | +} |
| 1134 | + |
| 1135 | +impl DerefMut for DmaLoopBuf { |
| 1136 | + fn deref_mut(&mut self) -> &mut Self::Target { |
| 1137 | + self.buffer |
| 1138 | + } |
| 1139 | +} |
0 commit comments