Skip to content

Commit b53fee6

Browse files
astapletonusbalbin
andauthored
gpdma: add GPDMA driver (#64)
This adds support for one-shot DMA transfers for all supported transfer types with linear addressing. It does not yet support linked list buffer loading, or support 2D addressing. Memory-to-memory transfers were quite thoroughly tested by the provided example, memory-to-peripheral and peripheral-to-memory transfers were tested with the SPI peripheral (working on a test branch). Peripheral-to-peripheral transfers are assumed to work given their similarity to memory-to-peripheral/peripheral-to-memory transfers, but will be properly tested at a later stage. The driver includes helper structs for peripheral transfers in the `gpdma::periph` module which handle the common operations for setting up one-directional and full-duplex transfers using one, or two channels, respectively. Transfer configuration is performed via `DmaConfig`. Additionally, the `transform` module includes support for configuring the data transformation pipeline supported by the GPDMA peripheral, only allowing relevant options to be supported based on the source and destination word sizes. --------- Co-authored-by: Albin Hedman <[email protected]>
1 parent 4a21d41 commit b53fee6

File tree

9 files changed

+2490
-0
lines changed

9 files changed

+2490
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ defmt = [
6666
cortex-m = { version = "^0.7.7", features = ["critical-section-single-core"] }
6767
stm32h5 = { package = "stm32h5", version = "0.16.0" }
6868
fugit = "0.3.7"
69+
embedded-dma = "0.2"
6970
embedded-hal = "1.0.0"
7071
defmt = { version = "1.0.0", optional = true }
7172
paste = "1.0.15"

examples/dma.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// #![deny(warnings)]
2+
#![no_main]
3+
#![no_std]
4+
5+
mod utilities;
6+
7+
use cortex_m::singleton;
8+
use cortex_m_rt::entry;
9+
use cortex_m_semihosting::debug;
10+
use stm32h5xx_hal::{
11+
gpdma::{config::transform::*, DmaConfig, DmaTransfer},
12+
pac,
13+
prelude::*,
14+
};
15+
16+
#[entry]
17+
fn main() -> ! {
18+
utilities::logger::init();
19+
20+
let dp = pac::Peripherals::take().unwrap();
21+
22+
let pwr = dp.PWR.constrain();
23+
let pwrcfg = pwr.vos0().freeze();
24+
25+
// Constrain and Freeze clock
26+
let rcc = dp.RCC.constrain();
27+
let ccdr = rcc.sys_ck(250.MHz()).freeze(pwrcfg, &dp.SBS);
28+
29+
let channels = dp.GPDMA1.channels(ccdr.peripheral.GPDMA1);
30+
31+
log::info!("u8 to u8");
32+
let src =
33+
singleton!(: [u8; 40] = core::array::from_fn(|i| i as u8)).unwrap();
34+
35+
let dest = singleton!(: [u8; 40] = [0u8; 40]).unwrap();
36+
37+
let mut channel = channels.0;
38+
let config = DmaConfig::new();
39+
let mut transfer =
40+
DmaTransfer::memory_to_memory(config, &mut channel, src, dest);
41+
transfer.start().unwrap();
42+
transfer.wait_for_transfer_complete().unwrap();
43+
let (src, dest) = transfer.free();
44+
assert_eq!(src, dest);
45+
46+
log::info!("u32 to u32 with data transform");
47+
let src = singleton!(: [u32; 10] = [0x12345678u32; 10]).unwrap();
48+
let dest = singleton!(: [u32; 10] = [0u32; 10]).unwrap();
49+
50+
let config = DmaConfig::new().with_data_transform(
51+
DataTransform::builder()
52+
.swap_destination_half_words()
53+
.swap_destination_half_word_byte_order(),
54+
);
55+
56+
let mut transfer =
57+
DmaTransfer::memory_to_memory(config, &mut channel, src, dest);
58+
59+
transfer.start().unwrap();
60+
transfer.wait_for_transfer_complete().unwrap();
61+
let (_, dest) = transfer.free();
62+
63+
let expected = [0x78563412; 10];
64+
assert_eq!(expected, *dest);
65+
66+
log::info!("u32 to u16 with truncate");
67+
let src = singleton!(: [u32; 10] = [0x12345678u32; 10]).unwrap();
68+
let dest = singleton!(: [u16; 20] = [0u16; 20]).unwrap();
69+
70+
let config = DmaConfig::new().with_data_transform(
71+
DataTransform::builder().left_align_right_truncate(),
72+
);
73+
let mut transfer =
74+
DmaTransfer::memory_to_memory(config, &mut channel, src, dest);
75+
76+
transfer.start().unwrap();
77+
transfer.wait_for_transfer_complete().unwrap();
78+
let (_, dest) = transfer.free();
79+
80+
let expected = [0x1234; 10];
81+
assert_eq!(expected, (*dest)[0..10]);
82+
83+
log::info!("u32 to u8 with unpack");
84+
let src = singleton!(: [u32; 10] = [0x12345678u32; 10]).unwrap();
85+
let dest = singleton!(: [u8; 40] = [0u8; 40]).unwrap();
86+
87+
let config =
88+
DmaConfig::new().with_data_transform(DataTransform::builder().unpack());
89+
let mut transfer =
90+
DmaTransfer::memory_to_memory(config, &mut channel, src, dest);
91+
92+
transfer.start().unwrap();
93+
transfer.wait_for_transfer_complete().unwrap();
94+
let (_, dest) = transfer.free();
95+
let expected = [0x78, 0x56, 0x34, 0x12];
96+
assert_eq!(expected, (*dest)[0..4]);
97+
assert_eq!(expected, (*dest)[36..40]);
98+
99+
log::info!("u8 to u32 with pack");
100+
let src = singleton!(: [u8; 40] = [0u8; 40]).unwrap();
101+
let dest = singleton!(: [u32; 10] = [0u32; 10]).unwrap();
102+
103+
for chunk in src.chunks_mut(4) {
104+
chunk.copy_from_slice(&[0x78, 0x56, 0x34, 0x12]);
105+
}
106+
107+
let config =
108+
DmaConfig::new().with_data_transform(DataTransform::builder().pack());
109+
let mut transfer =
110+
DmaTransfer::memory_to_memory(config, &mut channel, src, dest);
111+
112+
transfer.start().unwrap();
113+
transfer.wait_for_transfer_complete().unwrap();
114+
let (_, dest) = transfer.free();
115+
116+
let expected = [0x12345678; 10];
117+
assert_eq!(expected, *dest);
118+
assert_eq!(expected, *dest);
119+
120+
log::info!("All tests passed!");
121+
loop {
122+
debug::exit(debug::EXIT_SUCCESS)
123+
}
124+
}

0 commit comments

Comments
 (0)