Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Adding module-level documentation for DMA and INTERRUPT peripherals
  • Loading branch information
playfulFence committed Aug 9, 2023
commit 2666144060c4628f857ff8eae6164a5a75f94be1
19 changes: 19 additions & 0 deletions esp-hal-common/src/dma/gdma.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
//! Direct Memory Access
//!
//! ## Overview
//! The GDMA (General DMA) module is a part of the DMA (Direct Memory Access) driver for ESP chips.
//! Of the Espressif chip range, every chip except of `ESP32` and `ESP32-S2` uses the `GDMA` type of direct memory access.
//!
//! DMA is a hardware feature that allows data transfer between memory and peripherals without
//! involving the CPU, resulting in efficient data movement and reduced CPU overhead.
//! The `GDMA` module provides multiple DMA channels, each capable of managing data transfer for various peripherals.
//!
//! This module implements DMA channels, such as `channel0`, `channel1` and so on. Each channel struct
//! implements the `ChannelTypes` trait, which provides associated types for peripheral configuration.
//!
//! GDMA peripheral can be initializes using the `new` function, which reqires a DMA peripheral instance and a clock control reference.
//! ```no_run
//! let dma = Gdma::new(peripherals.DMA, &mut system.peripheral_clock_control);
//! ```
//!
//! <em>PS: Note that the number of DMA channels is chip-specific.</em>


use crate::{
dma::*,
Expand Down
61 changes: 60 additions & 1 deletion esp-hal-common/src/dma/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,63 @@
//! Direct Memory Access Commons
//!
//! Descriptors should be sized as `((BUFFERSIZE + 4091) / 4092) * 3`. I.e., to
//! ## Overview
//! The `DMA` driver provides an interface to efficiently transfer data between different memory regions
//! within the ESP microcontroller without involving the CPU. The `Direct Memory Access` (DMA) controller is a hardware
//! block responsible for managing these data transfers.
//!
//! The driver is organized into several components and traits, each responsible for handling specific
//! functionalities of the `DMA` controller. Below is an overview of the main components and their functionalities:
//! * `Tx` and `Rx` traits:
//! - These traits define the behaviors and functionalities required for DMA transmit and receive operations.</br>
//! The `Tx` trait includes functions to start, stop, and check the completion status of an outbound DMA transfer.</br>
//! On the other hand, the Rx trait provides similar functionalities for inbound DMA transfers.
//! * `DmaTransfer` and `DmaTransferRxTx` traits:
//! - The `DmaTransfer` trait and `DmaTransferRxTx` trait are used for in-progress DMA transfers.</br>
//! They allow waiting for the transfer to complete and checking its status.
//! Additionally, the `DmaTransferRxTx` trait extends the functionalities to support both receive and transmit
//! operations in a single trait.
//! * `RegisterAccess` trait:
//! - This trait defines a set of methods that allow low-level access to the DMA controller's registers.</br>
//! It provides functions to initialize DMA channels, configure burst mode, priority, and peripheral for both
//! input and output data transfers.</br>Additionally, it supports clearing interrupts, resetting channels, setting
//! descriptor addresses, and checking for descriptor errors.
//!
//! Notice, that this module is a common version of the DMA driver, `ESP32` and `ESP32-S2` are using older `PDMA` controller,
//! whenever other chips are using newer `GDMA` controller.
//!
//! ## Example
//! #### Initialize and utilize DMA controller in `SPI`
//! ```no_run
//! let dma = Gdma::new(peripherals.DMA, &mut system.peripheral_clock_control);
//! let dma_channel = dma.channel0;
//!
//! // For `ESP32` and `ESP32-S2` chips use `Pdma` controller instead:
//! // let dma = Dma::new(system.dma, &mut system.peripheral_clock_control);
//! // let dma_channel = dma.spi2channel;
//!
//! let mut descriptors = [0u32; 8 * 3];
//! let mut rx_descriptors = [0u32; 8 * 3];
//!
//! let mut spi = Spi::new(
//! peripherals.SPI2,
//! sclk,
//! mosi,
//! miso,
//! cs,
//! 100u32.kHz(),
//! SpiMode::Mode0,
//! &mut system.peripheral_clock_control,
//! &clocks,
//! )
//! .with_dma(dma_channel.configure(
//! false,
//! &mut descriptors,
//! &mut rx_descriptors,
//! DmaPriority::Priority0,
//! ));
//! ```
//!
//! ⚠️ Note: Descriptors should be sized as `((BUFFERSIZE + 4091) / 4092) * 3`. I.e., to
//! transfer buffers of size `1..=4092`, you need 3 descriptors.

use core::{marker::PhantomData, sync::atomic::compiler_fence};
Expand Down Expand Up @@ -308,6 +365,7 @@ where
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker;
}

// DMA receive channel
pub struct ChannelRx<'a, T, R>
where
T: RxChannel<R>,
Expand Down Expand Up @@ -607,6 +665,7 @@ where
fn waker() -> &'static embassy_sync::waitqueue::AtomicWaker;
}

/// DMA transmit channel
pub struct ChannelTx<'a, T, R>
where
T: TxChannel<R>,
Expand Down
15 changes: 15 additions & 0 deletions esp-hal-common/src/dma/pdma.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
//! Direct Memory Access
//!
//! ## Overview
//! The `pdma` module is part of the DMA (Direct Memory Access) driver designed for ESP chips.
//! Of the Espressif chip range, only `ESP32` and `ESP32-S2` use the `PDMA` type of direct memory access.
//!
//! This module provides efficient direct data transfer capabilities between peripherals and memory without involving the CPU.
//! It enables bidirectional data transfers through DMA channels, making it particularly useful for high-speed
//! data transfers, such as [SPI (Serial Peripheral Interface)] and [I2S (Inter-IC Sound)] communication.
//!
//!
//!
//! [SPI (Serial Peripheral Interface)]: ../spi/index.html
//! [I2S (Inter-IC Sound)]: ../i2s/index.html



use crate::{
dma::*,
Expand Down
124 changes: 124 additions & 0 deletions esp-hal-common/src/interrupt/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,128 @@
//! Interrupt support
//!
//! ## Overview
//! The `interrupt` driver is a crucial module for ESP chips. Its primary purpose is to manage and handle
//! interrupts, which are asynchronous events requiring immediate attention from the CPU. Interrupts are essential in various
//! applications, such as real-time tasks, I/O communications, and handling external events like hardware signals.
//!
//! The core functionality of the `interrupt` driver revolves around the management of interrupts.
//! When an interrupt occurs, it temporarily stops the ongoing CPU operations, saves its current state, and starts
//! executing the corresponding interrupt service routine (ISR). The interrupt service routine is a user-defined
//! function that performs the necessary actions to handle the specific interrupt.
//! Once the ISR is executed, the driver restores the saved CPU state and resumes normal program execution.
//!
//! In scenarios where multiple interrupts may occur simultaneously, the interrupt driver determines the `priority`
//! of each interrupt. This prioritization ensures that critical or high-priority tasks are handled first.
//! It helps prevent delays in time-sensitive applications and allows the system to allocate resources efficiently.
//! This functionality is provided and implemented by the `priority` enum.
//!
//!
//! ## Example
//! ```no_run
//! #[entry]
//! fn main() -> ! {
//! ...
//! critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int));
//!
//! interrupt::enable(
//! peripherals::Interrupt::FROM_CPU_INTR0,
//! interrupt::Priority::Priority1,
//! )
//! .unwrap();
//! interrupt::enable(
//! peripherals::Interrupt::FROM_CPU_INTR1,
//! interrupt::Priority::Priority2,
//! )
//! .unwrap();
//! interrupt::enable(
//! peripherals::Interrupt::FROM_CPU_INTR2,
//! interrupt::Priority::Priority2,
//! )
//! .unwrap();
//! interrupt::enable(
//! peripherals::Interrupt::FROM_CPU_INTR3,
//! interrupt::Priority::Priority15,
//! )
//! .unwrap();
//! unsafe { riscv::interrupt::enable() }
//!
//! // raise mid priority interrupt.
//! // The handler raises one interrupt at lower priority, one at same and one at
//! // higher. We expect to see the higher priority served immeiately before
//! // exiting the handler Once the handler is exited we expect to see same
//! // priority and low priority interrupts served in that order
//! critical_section::with(|cs| {
//! SWINT
//! .borrow_ref_mut(cs)
//! .as_mut()
//! .unwrap()
//! .raise(SoftwareInterrupt::SoftwareInterrupt1);
//! });
//! loop {}
//! }
//!
//! #[interrupt]
//! fn FROM_CPU_INTR0() {
//! esp_println::println!("SW interrupt0");
//! critical_section::with(|cs| {
//! SWINT
//! .borrow_ref_mut(cs)
//! .as_mut()
//! .unwrap()
//! .reset(SoftwareInterrupt::SoftwareInterrupt0);
//! });
//! }
//! #[interrupt]
//! fn FROM_CPU_INTR1() {
//! esp_println::println!("SW interrupt1 entry");
//! critical_section::with(|cs| {
//! SWINT
//! .borrow_ref_mut(cs)
//! .as_mut()
//! .unwrap()
//! .reset(SoftwareInterrupt::SoftwareInterrupt1);
//! SWINT
//! .borrow_ref_mut(cs)
//! .as_mut()
//! .unwrap()
//! .raise(SoftwareInterrupt::SoftwareInterrupt2); // raise interrupt at same priority
//! SWINT
//! .borrow_ref_mut(cs)
//! .as_mut()
//! .unwrap()
//! .raise(SoftwareInterrupt::SoftwareInterrupt3); // raise interrupt at higher priority
//! SWINT
//! .borrow_ref_mut(cs)
//! .as_mut()
//! .unwrap()
//! .raise(SoftwareInterrupt::SoftwareInterrupt0); // raise interrupt at
//! // lower priority
//! });
//! esp_println::println!("SW interrupt1 exit");
//! }
//! #[interrupt]
//! fn FROM_CPU_INTR2() {
//! esp_println::println!("SW interrupt2");
//! critical_section::with(|cs| {
//! SWINT
//! .borrow_ref_mut(cs)
//! .as_mut()
//! .unwrap()
//! .reset(SoftwareInterrupt::SoftwareInterrupt2);
//! });
//! }
//! #[interrupt]
//! fn FROM_CPU_INTR3() {
//! esp_println::println!("SW interrupt3");
//! critical_section::with(|cs| {
//! SWINT
//! .borrow_ref_mut(cs)
//! .as_mut()
//! .unwrap()
//! .reset(SoftwareInterrupt::SoftwareInterrupt3);
//! });
//! }
//! ```

#[cfg(riscv)]
pub use riscv::*;
Expand Down