Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce RGB/DPI driver #2415

Merged
merged 8 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Pins::steal()` to unsafely obtain GPIO. (#2335)
- `I2c::with_timeout` (#2361)
- `Spi::half_duplex_read` and `Spi::half_duplex_write` (#2373)
- Add RGB/DPI driver (#2415)
- Add `DmaLoopBuf` (#2415)
- `Cpu::COUNT` and `Cpu::current()` (#2411)
- `UartInterrupt` and related functions (#2406)
- I2S Parallel output driver for ESP32. (#2348, #2436, #2472)
Expand Down
93 changes: 92 additions & 1 deletion esp-hal/src/dma/buffers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use core::ptr::null_mut;
use core::{
ops::{Deref, DerefMut},
ptr::null_mut,
};

use super::*;
use crate::soc::is_slice_in_dram;
Expand Down Expand Up @@ -1046,3 +1049,91 @@ unsafe impl DmaRxBuffer for EmptyBuf {
0
}
}

/// DMA Loop Buffer
///
/// This consists of a single descriptor that points to itself and points to a
/// single buffer, resulting in the buffer being transmitted over and over
/// again, indefinitely.
///
/// Note: A DMA descriptor is 12 bytes. If your buffer is significantly shorter
/// than this, the DMA channel will spend more time reading the descriptor than
/// it does reading the buffer, which may leave it unable to keep up with the
/// bandwidth requirements of some peripherals at high frequencies.
pub struct DmaLoopBuf {
descriptor: &'static mut DmaDescriptor,
buffer: &'static mut [u8],
}

impl DmaLoopBuf {
/// Create a new [DmaLoopBuf].
pub fn new(
descriptor: &'static mut DmaDescriptor,
buffer: &'static mut [u8],
) -> Result<DmaLoopBuf, DmaBufError> {
if !is_slice_in_dram(buffer) {
return Err(DmaBufError::UnsupportedMemoryRegion);
}
if !is_slice_in_dram(core::slice::from_ref(descriptor)) {
return Err(DmaBufError::UnsupportedMemoryRegion);
}

if buffer.len() > max_chunk_size(None) {
return Err(DmaBufError::InsufficientDescriptors);
}

descriptor.set_owner(Owner::Dma); // Doesn't matter
descriptor.set_suc_eof(false);
descriptor.set_length(buffer.len());
descriptor.set_size(buffer.len());
descriptor.buffer = buffer.as_mut_ptr();
descriptor.next = descriptor;

Ok(Self { descriptor, buffer })
}

/// Consume the buf, returning the descriptor and buffer.
pub fn split(self) -> (&'static mut DmaDescriptor, &'static mut [u8]) {
(self.descriptor, self.buffer)
}
}

unsafe impl DmaTxBuffer for DmaLoopBuf {
type View = Self;

fn prepare(&mut self) -> Preparation {
Preparation {
start: self.descriptor,
block_size: None,
is_burstable: true,
// The DMA must not check the owner bit, as it is never set.
check_owner: Some(false),
}
}

fn into_view(self) -> Self::View {
self
}

fn from_view(view: Self::View) -> Self {
view
}

fn length(&self) -> usize {
panic!("DmaLoopBuf does not have a length")
}
}

impl Deref for DmaLoopBuf {
type Target = [u8];

fn deref(&self) -> &Self::Target {
self.buffer
}
}

impl DerefMut for DmaLoopBuf {
fn deref_mut(&mut self) -> &mut Self::Target {
self.buffer
}
}
24 changes: 24 additions & 0 deletions esp-hal/src/dma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,30 @@ macro_rules! dma_rx_stream_buffer {
}};
}

/// Convenience macro to create a [DmaLoopBuf] from a buffer size.
///
/// ## Usage
/// ```rust,no_run
#[doc = crate::before_snippet!()]
/// use esp_hal::dma_loop_buffer;
///
/// let buf = dma_loop_buffer!(2000);
/// # }
/// ```
#[macro_export]
macro_rules! dma_loop_buffer {
($size:expr) => {{
const {
::core::assert!($size <= 4095, "size must be <= 4095");
::core::assert!($size > 0, "size must be > 0");
}

let (buffer, descriptors) = $crate::dma_buffers_impl!($size, $size, is_circular = false);

$crate::dma::DmaLoopBuf::new(&mut descriptors[0], buffer).unwrap()
}};
}

/// DMA Errors
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
Expand Down
Loading