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

Implement DMA based on embedded-dma traits #153

Merged
merged 49 commits into from
Feb 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
876249d
Add DMA and examples for DMA1/DMA2
richardeoin Oct 17, 2020
b111bee
Mark AXISRAM as NOLOAD (as well as SRAM3/4)
richardeoin Oct 17, 2020
0cca09e
Add BDMA, work in progress
richardeoin Oct 18, 2020
e74deb2
Experiment with implementing TargetAddress on a HAL structure
richardeoin Oct 18, 2020
b178f3a
Experiment with DMA methods for I2C, add example with I2C4 and BDMA
richardeoin Oct 18, 2020
a1a719c
Tidy clippy warnings
richardeoin Oct 18, 2020
a8d58b5
Refactor I2C to expose infallible methods for parts of transcations
richardeoin Oct 21, 2020
91de4ee
Tidy more clippy lints
richardeoin Oct 21, 2020
a86c5b6
Add DMBs before and after the stream read/writes normal memory
richardeoin Oct 22, 2020
5ce5fc9
Refactor Stream trait into two parts, add config struct for BDMA
richardeoin Oct 23, 2020
7d5d843
Remove unnecessary trait bound
richardeoin Oct 23, 2020
af88ee0
Implement TargetAddress directly on the PAC/HAL struct itself
richardeoin Oct 27, 2020
d226891
Fix a few typos in the sai module's comments.
antoinevg Oct 31, 2020
a1b9a27
Add enable_dma() method to SAI peripheral
antoinevg Oct 31, 2020
5d2b2a8
Implement peripheral_target_address macro for SAI1-4
antoinevg Oct 31, 2020
e2db677
Add a second iteration of the SAI passthrough example which uses the …
antoinevg Oct 31, 2020
7ddb8a6
Merge pull request #162 from antoinevg/sai_dma_passthru_example_v0.2
richardeoin Nov 1, 2020
8d0605e
Updating DMA macro for SPI types
ryan-summers Nov 3, 2020
0c37c70
Formatting
ryan-summers Nov 3, 2020
f14dd61
Merge pull request #164 from quartiq/rs/spi-dma-types
richardeoin Nov 3, 2020
0575235
rustfmt
richardeoin Nov 3, 2020
624c87e
Add BDMA2 support for RM0455 parts
richardeoin Nov 3, 2020
e694353
Merge remote-tracking branch 'st/master' into feature/dma-rtic-example
ryan-summers Nov 7, 2020
6c738b8
Adding SPI DMA example using RTIC
ryan-summers Nov 7, 2020
d8cb6fa
Updating sample after testing
ryan-summers Nov 8, 2020
62f7fb7
Cleaning up example
ryan-summers Nov 11, 2020
002123c
Fixing clippy
ryan-summers Nov 11, 2020
0bfeeca
Merge pull request #167 from quartiq/feature/dma-rtic-example
richardeoin Nov 11, 2020
d77e835
dma: streamline double buffer address handling
jordens Nov 27, 2020
5585210
dma: StaticWriteBuffer
jordens Nov 27, 2020
301e16b
dma: buf array
jordens Nov 27, 2020
4425323
dma: streamline double buffer
jordens Nov 27, 2020
be1573f
dma: usize for addresses
jordens Nov 28, 2020
2448dba
dma: rewrite next_transfer_with and next_transfer
jordens Dec 1, 2020
f31e7ff
dma: fence() and some cleanups/comments
jordens Dec 2, 2020
0f22d94
dma: update bdma
jordens Dec 2, 2020
131340e
dma: spell
jordens Dec 2, 2020
e70a787
Adding return of remaining transfers
ryan-summers Dec 7, 2020
5f97920
dma: trait docs fixes
jordens Dec 9, 2020
8483294
Updating docs, updating next_transfer_with
ryan-summers Dec 15, 2020
25ee0f3
Merge pull request #173 from quartiq/feature/number-of-transfers
ryan-summers Jan 4, 2021
2954e70
Panic if the transfer length exceeds the hardware capability
richardeoin Dec 19, 2020
7b62474
Merge remote-tracking branch 'quartiq/feature/dma-buffer-swap-logic' …
richardeoin Jan 5, 2021
3da22d4
Add example usage of `next_transfer_with` to the spi-dma example
richardeoin Jan 5, 2021
db8e3a1
[mdma] preparation for MDMA
richardeoin Jan 7, 2021
b40f13e
Implement DMA for constant source buffers
richardeoin Jan 7, 2021
2809fef
Add allow for clippy type_complexity with 5th type parameter
richardeoin Jan 7, 2021
1ac12e1
Merge pull request #178 from richardeoin/dma-const-buf1
richardeoin Jan 13, 2021
2b8a04c
Merge pull request #183 from stm32-rs/master
richardeoin Jan 31, 2021
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
19 changes: 18 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ targets = ["thumbv7em-none-eabihf"]

[dependencies]
embedded-hal = "0.2.4"
embedded-dma = "0.1.2"
cortex-m = "^0.6.2"
cortex-m-rt = "^0.6.12"
stm32h7 = "^0.12.1"
Expand Down Expand Up @@ -172,4 +173,20 @@ required-features = ["rt", "rtc"]

[[example]]
name = "sai-i2s-passthru"
required-features = ["rm0433"]
required-features = ["rm0433"]

[[example]]
name = "sai_dma_passthru"
required-features = ["rm0433"]

[[example]]
name = "dma"
required-features = ["rm0433"]

[[example]]
name = "spi-dma"
required-features = ["rm0433"]

[[example]]
name = "spi-dma-rtic"
required-features = ["rm0433","rt"]
108 changes: 108 additions & 0 deletions examples/dma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//! Example of Memory to Memory Transfer with the DMA

#![allow(clippy::transmute_ptr_to_ptr)]
#![deny(warnings)]
#![no_main]
#![no_std]

use core::{mem, mem::MaybeUninit};

use cortex_m_rt::entry;
#[macro_use]
mod utilities;
use stm32h7xx_hal::{pac, prelude::*};

use stm32h7xx_hal::dma::{
dma::{DmaConfig, StreamsTuple},
traits::Direction,
MemoryToMemory, Transfer,
};

use log::info;

// DMA1/DMA2 cannot interact with our stack. Instead, buffers for use with the
// DMA must be placed somewhere that DMA1/DMA2 can access.
//
// The runtime does not initialise these SRAM banks.
#[link_section = ".sram4.buffers"]
static mut SOURCE_BUFFER: MaybeUninit<[u32; 20]> = MaybeUninit::uninit();
#[link_section = ".axisram.buffers"]
static mut TARGET_BUFFER: MaybeUninit<[u32; 20]> = MaybeUninit::uninit();

#[entry]
fn main() -> ! {
utilities::logger::init();
let dp = pac::Peripherals::take().unwrap();

// Constrain and Freeze power
info!("Setup PWR... ");
let pwr = dp.PWR.constrain();
let pwrcfg = example_power!(pwr).freeze();

// Constrain and Freeze clock
info!("Setup RCC... ");
let rcc = dp.RCC.constrain();
let ccdr = rcc
.sys_ck(400.mhz())
.pll1_q_ck(200.mhz())
.freeze(pwrcfg, &dp.SYSCFG);

// True RNG
let mut rng = dp.RNG.constrain(ccdr.peripheral.RNG, &ccdr.clocks);

info!("");
info!("stm32h7xx-hal example - Memory to Memory DMA");
info!("");

// Initialise the source buffer with truly random data, without taking any
// references to uninitialisated memory
let source_buffer: &'static mut [u32; 20] = {
let buf: &mut [MaybeUninit<u32>; 20] =
unsafe { mem::transmute(&mut SOURCE_BUFFER) };

for value in buf.iter_mut() {
unsafe {
value.as_mut_ptr().write(rng.gen().unwrap());
}
}
unsafe { mem::transmute(buf) }
};
// Save a copy on the stack so we can check it later
let source_buffer_cloned = *source_buffer;

// Setup DMA
//
// We need to specify the transfer size with a type annotation

let streams = StreamsTuple::new(dp.DMA1, ccdr.peripheral.DMA1);

let config = DmaConfig::default()
.memory_increment(true) // destination mem
.peripheral_increment(true) // source mem
.fifo_enable(true);

let mut transfer: Transfer<_, _, MemoryToMemory<u32>, _, _> =
Transfer::init(
streams.4,
MemoryToMemory::new(),
unsafe { mem::transmute(&mut TARGET_BUFFER) }, // Uninitialised memory
Some(source_buffer),
config,
);

transfer.start(|_| {});

// Wait for transfer to complete
while !transfer.get_transfer_complete_flag() {}

// Now the target memory is actually initialised
let target_buffer: &'static mut [u32; 20] =
unsafe { mem::transmute(&mut TARGET_BUFFER) };

// Comparison check
assert_eq!(&source_buffer_cloned, target_buffer);

info!("Memory to Memory DMA completed successfully");

loop {}
}
133 changes: 133 additions & 0 deletions examples/i2c4_bdma.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//! I2C4 in low power mode.
//!
//!

#![allow(clippy::transmute_ptr_to_ptr)]
#![deny(warnings)]
#![no_std]
#![no_main]

use core::{mem, mem::MaybeUninit};

#[macro_use]
mod utilities;

use stm32h7xx_hal::dma::{
bdma::{BdmaConfig, StreamsTuple},
PeripheralToMemory, Transfer,
};

use stm32h7xx_hal::prelude::*;
use stm32h7xx_hal::{i2c, pac, pac::interrupt, rcc::LowPowerMode};

use cortex_m_rt::entry;

use log::info;

// The BDMA can only interact with SRAM4.
//
// The runtime does not initialise this SRAM bank
#[link_section = ".sram4.buffers"]
static mut BUFFER: MaybeUninit<[u8; 10]> = MaybeUninit::uninit();

#[entry]
fn main() -> ! {
utilities::logger::init();
let cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().expect("Cannot take peripherals");

// Run D3 / SRD domain
dp.PWR.cpucr.modify(|_, w| w.run_d3().set_bit());

let pwr = dp.PWR.constrain();
let pwrcfg = example_power!(pwr).freeze();

// RCC
let rcc = dp.RCC.constrain();
let ccdr = rcc
.sys_ck(400.mhz())
// D3 / SRD domain
.hclk(200.mhz()) // rcc_hclk4
.pclk4(50.mhz()) // rcc_pclk4
.freeze(pwrcfg, &dp.SYSCFG);

// GPIO
let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);

// Configure the SCL and the SDA pin for our I2C bus
let scl = gpiod.pd12.into_alternate_af4().set_open_drain();
let sda = gpiod.pd13.into_alternate_af4().set_open_drain();

let mut i2c = dp.I2C4.i2c(
(scl, sda),
100.khz(),
ccdr.peripheral.I2C4.low_power(LowPowerMode::Autonomous),
&ccdr.clocks,
);

// Use RX DMA
i2c.rx_dma(true);

// Listen for the end of i2c transactions
i2c.clear_irq(i2c::Event::Stop);
i2c.listen(i2c::Event::Stop);
unsafe {
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::I2C4_EV);
}

// Setup the DMA transfer on stream 0
#[cfg(not(feature = "rm0455"))]
let streams = StreamsTuple::new(
dp.BDMA,
ccdr.peripheral.BDMA.low_power(LowPowerMode::Autonomous),
);
#[cfg(feature = "rm0455")]
let streams = StreamsTuple::new(
dp.BDMA2,
ccdr.peripheral.BDMA.low_power(LowPowerMode::Autonomous),
);

let config = BdmaConfig::default().memory_increment(true);

// We need to specify the direction with a type annotation
let mut transfer: Transfer<_, _, PeripheralToMemory, _, _> = Transfer::init(
streams.0,
i2c,
unsafe { &mut BUFFER }, // uninitialised memory
None,
config,
);

transfer.start(|i2c| {
// This closure runs right after enabling the stream

// Issue the first part of an I2C transaction to read data from a
// touchscreen

// Write register index
i2c.write(0xBA >> 1, &[0x41, 0xE4]).unwrap();

// Start a read of 10 bytes
i2c.master_read(0xBA >> 1, 10, i2c::Stop::Automatic);
});

// Enter CStop mode on wfi
let mut scb = cp.SCB;
scb.set_sleepdeep();

loop {
cortex_m::asm::wfi();
}
}

#[interrupt]
fn I2C4_EV() {
info!("I2C transfer complete!");

// Look at BUFFER, which we expect to be initialised
let buffer: &'static mut [u8; 10] = unsafe { mem::transmute(&mut BUFFER) };

assert_eq!(buffer[0], 0xBE);

loop {}
}
Loading