aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/modules/ROOT/pages/faq.adoc12
-rw-r--r--examples/stm32h7/build.rs30
-rw-r--r--examples/stm32h7/memory.x14
-rw-r--r--examples/stm32h7/src/bin/spi_bdma.rs78
4 files changed, 132 insertions, 2 deletions
diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc
index 6cb7233c1..a074594cc 100644
--- a/docs/modules/ROOT/pages/faq.adoc
+++ b/docs/modules/ROOT/pages/faq.adoc
@@ -279,6 +279,14 @@ If you see errors that look like this:
279DMA: error on BDMA@1234ABCD channel 4 279DMA: error on BDMA@1234ABCD channel 4
280---- 280----
281 281
282You likely need to set up your linker script to define a special region for this area, and copy data to that region before using with BDMA. 282You need to set up your linker script to define a special region for this area, and copy data to that region before using with BDMA.
283 283
284TODO: show how to do that 284General steps:
285
2861. Find out which memory region BDMA has access to. You can get this information from the bus matrix and the memory mapping table in the STM32 datasheet.
2872. Add the memory region to `memory.x`, you can modify the generated one from https://github.com/embassy-rs/stm32-data-generated/tree/main/data/chips.
2883. You might need to modify `build.rs` to make cargo pick up the modified `memory.x`.
2894. In your code, access the defined memory region using `#[link_section = ".xxx"]`
2905. Copy data to that region before using BDMA.
291
292See link:/examples/stm32h7/src/bin/spi_bdma.rs[this example] for more details.
diff --git a/examples/stm32h7/build.rs b/examples/stm32h7/build.rs
index 8cd32d7ed..b9bb661f0 100644
--- a/examples/stm32h7/build.rs
+++ b/examples/stm32h7/build.rs
@@ -1,4 +1,34 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
1fn main() { 16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
2 println!("cargo:rustc-link-arg-bins=--nmagic"); 32 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x"); 33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
diff --git a/examples/stm32h7/memory.x b/examples/stm32h7/memory.x
new file mode 100644
index 000000000..e5ab1f62c
--- /dev/null
+++ b/examples/stm32h7/memory.x
@@ -0,0 +1,14 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 2048K /* BANK_1 + BANK_2 */
4 RAM : ORIGIN = 0x24000000, LENGTH = 512K /* SRAM */
5 RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */
6}
7
8SECTIONS
9{
10 .ram_d3 :
11 {
12 *(.ram_d3)
13 } > RAM_D3
14} \ No newline at end of file
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs
new file mode 100644
index 000000000..2fc37fc22
--- /dev/null
+++ b/examples/stm32h7/src/bin/spi_bdma.rs
@@ -0,0 +1,78 @@
1#![no_std]
2#![no_main]
3
4use core::fmt::Write;
5use core::str::from_utf8;
6
7use cortex_m_rt::entry;
8use defmt::*;
9use embassy_executor::Executor;
10use embassy_stm32::mode::Async;
11use embassy_stm32::time::mhz;
12use embassy_stm32::{peripherals, spi, Config};
13use heapless::String;
14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _};
16
17// Defined in memory.x
18#[link_section = ".ram_d3"]
19static mut RAM_D3: [u8; 64 * 1024] = [0u8; 64 * 1024];
20
21#[embassy_executor::task]
22async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI6, Async>) {
23 let read_buffer = unsafe { &mut RAM_D3[0..128] };
24 let write_buffer = unsafe { &mut RAM_D3[128..256] };
25
26 for n in 0u32.. {
27 let mut write: String<128> = String::new();
28 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
29 let read_buffer = &mut read_buffer[..write.len()];
30 let write_buffer = &mut write_buffer[..write.len()];
31 // copy data to write_buffer which is located in D3 domain, accessable by BDMA
32 write_buffer.clone_from_slice(write.as_bytes());
33
34 spi.transfer(read_buffer, write_buffer).await.ok();
35 info!("read via spi+dma: {}", from_utf8(read_buffer).unwrap());
36 }
37}
38
39static EXECUTOR: StaticCell<Executor> = StaticCell::new();
40
41#[entry]
42fn main() -> ! {
43 info!("Hello World!");
44
45 let mut config = Config::default();
46 {
47 use embassy_stm32::rcc::*;
48 config.rcc.hsi = Some(HSIPrescaler::DIV1);
49 config.rcc.csi = true;
50 config.rcc.pll1 = Some(Pll {
51 source: PllSource::HSI,
52 prediv: PllPreDiv::DIV4,
53 mul: PllMul::MUL50,
54 divp: Some(PllDiv::DIV2),
55 divq: Some(PllDiv::DIV8), // used by SPI3. 100Mhz.
56 divr: None,
57 });
58 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
59 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
60 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
61 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
62 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
63 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
64 config.rcc.voltage_scale = VoltageScale::Scale1;
65 }
66 let p = embassy_stm32::init(config);
67
68 let mut spi_config = spi::Config::default();
69 spi_config.frequency = mhz(1);
70
71 let spi = spi::Spi::new(p.SPI6, p.PA5, p.PA7, p.PA6, p.BDMA_CH1, p.BDMA_CH0, spi_config);
72
73 let executor = EXECUTOR.init(Executor::new());
74
75 executor.run(|spawner| {
76 unwrap!(spawner.spawn(main_task(spi)));
77 })
78}