aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/stm32l432/.cargo/config.toml13
-rw-r--r--examples/stm32l432/Cargo.toml30
-rw-r--r--examples/stm32l432/README.md30
-rw-r--r--examples/stm32l432/build.rs5
-rw-r--r--examples/stm32l432/src/bin/qspi_mmap.rs274
5 files changed, 352 insertions, 0 deletions
diff --git a/examples/stm32l432/.cargo/config.toml b/examples/stm32l432/.cargo/config.toml
new file mode 100644
index 000000000..0a42c584b
--- /dev/null
+++ b/examples/stm32l432/.cargo/config.toml
@@ -0,0 +1,13 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3#runner = "probe-rs run --chip STM32L475VGT6"
4#runner = "probe-rs run --chip STM32L475VG"
5#runner = "probe-rs run --chip STM32L4S5QI"
6runner = "probe-rs run --chip STM32L432KCUx --connect-under-reset --speed 3300"
7
8
9[build]
10target = "thumbv7em-none-eabi"
11
12[env]
13DEFMT_LOG = "trace"
diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml
new file mode 100644
index 000000000..460561b36
--- /dev/null
+++ b/examples/stm32l432/Cargo.toml
@@ -0,0 +1,30 @@
1[package]
2edition = "2021"
3name = "embassy-stm32l4-examples"
4version = "0.1.1"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32l4s5vi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l432kc", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = [ "defmt" ] }
11embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt" ] }
12embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "tick-hz-32_768" ] }
13defmt = "0.3"
14defmt-rtt = "0.4"
15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0"
18embedded-hal = "0.2.6"
19embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
20embedded-hal-async = { version = "1.0" }
21embedded-hal-bus = { version = "0.1", features = ["async"] }
22panic-probe = { version = "0.3", features = ["print-defmt"] }
23
24[profile.release]
25debug = 2
26
27[[bin]]
28name = "qspi_mmap"
29path = "src/bin/qspi_mmap.rs"
30test = false
diff --git a/examples/stm32l432/README.md b/examples/stm32l432/README.md
new file mode 100644
index 000000000..3dac97f03
--- /dev/null
+++ b/examples/stm32l432/README.md
@@ -0,0 +1,30 @@
1
2# Examples for STM32L432 family
3
4Examples in this repo should work with [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) board.
5
6Run individual examples with
7```
8cargo run --bin <module-name>
9```
10for example
11```
12cargo run --bin blinky
13```
14
15
16
17## Checklist before running examples
18You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
19
20* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L432KCU6 it should be `probe-rs run --chip STM32L432KCUx`. (use `probe-rs chip list` to find your chip)
21* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L432KCU6 it should be `stm32l432kc`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip.
22* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
23* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
24
25If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
26
27* Which example you are trying to run
28* Which chip and board you are using
29
30Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/stm32l432/build.rs b/examples/stm32l432/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32l432/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32l432/src/bin/qspi_mmap.rs b/examples/stm32l432/src/bin/qspi_mmap.rs
new file mode 100644
index 000000000..86a20eb3d
--- /dev/null
+++ b/examples/stm32l432/src/bin/qspi_mmap.rs
@@ -0,0 +1,274 @@
1#![no_std]
2#![no_main]
3#![allow(dead_code)]
4/// This example demonstrates how to use the QSPI peripheral in both indirect-mode and memory-mapped mode.
5/// If you want to test this example, please pay attention to flash pins and check flash device datasheet
6/// to make sure operations in this example are compatible with your device, especially registers I/O operations.
7use defmt::info;
8use embassy_stm32::mode;
9use embassy_stm32::qspi::enums::{
10 AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, MemorySize, QspiWidth,
11};
12use embassy_stm32::qspi::{self, Instance, TransferConfig};
13pub struct FlashMemory<I: Instance> {
14 qspi: qspi::Qspi<'static, I, mode::Async>,
15}
16use embassy_executor::Spawner;
17use embassy_time::Timer;
18use {defmt_rtt as _, panic_probe as _};
19
20const MEMORY_PAGE_SIZE: usize = 256;
21const CMD_READ_SR: u8 = 0x05;
22const CMD_READ_CR: u8 = 0x35;
23const CMD_QUAD_READ: u8 = 0x6B;
24const CMD_QUAD_WRITE_PG: u8 = 0x32;
25const CMD_READ_ID: u8 = 0x9F;
26const CMD_READ_MID: u8 = 0x90;
27const CMD_READ_UUID: u8 = 0x4B;
28const CMD_ENABLE_RESET: u8 = 0x66;
29const CMD_RESET: u8 = 0x99;
30const CMD_WRITE_ENABLE: u8 = 0x06;
31const CMD_SECTOR_ERASE: u8 = 0x20;
32
33const CMD_WRITE_SR: u8 = 0x01;
34
35impl<I: Instance> FlashMemory<I> {
36 pub fn new(qspi: qspi::Qspi<'static, I, mode::Async>) -> Self {
37 let mut memory = Self { qspi };
38
39 memory.reset_memory();
40 memory.enable_quad();
41
42 memory
43 }
44 fn enable_quad(&mut self) {
45 let sr = self.read_sr_lsb();
46 let cr = self.read_sr_msb();
47
48 self.write_sr(sr, cr | 0x02);
49 }
50 fn read_register(&mut self, cmd: u8) -> u8 {
51 let mut buffer = [0; 1];
52 let transaction = TransferConfig {
53 iwidth: QspiWidth::SING,
54 awidth: QspiWidth::NONE,
55 dwidth: QspiWidth::SING,
56 instruction: cmd,
57 address: None,
58 dummy: DummyCycles::_0,
59 };
60 self.qspi.blocking_read(&mut buffer, transaction);
61 buffer[0]
62 }
63
64 fn write_register(&mut self, cmd: u8, value: u8) {
65 let buffer = [value; 1];
66 let transaction: TransferConfig = TransferConfig {
67 iwidth: QspiWidth::SING,
68 awidth: QspiWidth::NONE,
69 dwidth: QspiWidth::SING,
70 instruction: cmd,
71 address: None,
72 dummy: DummyCycles::_0,
73 };
74 self.qspi.blocking_write(&buffer, transaction);
75 }
76 pub fn write_sr(&mut self, lsb: u8, msb: u8) {
77 let buffer = [lsb, msb];
78 let transaction: TransferConfig = TransferConfig {
79 iwidth: QspiWidth::SING,
80 awidth: QspiWidth::NONE,
81 dwidth: QspiWidth::SING,
82 instruction: CMD_WRITE_SR,
83 address: None,
84 dummy: DummyCycles::_0,
85 };
86 self.qspi.blocking_write(&buffer, transaction);
87 }
88
89 pub fn read_sr_lsb(&mut self) -> u8 {
90 self.read_register(CMD_READ_SR)
91 }
92 pub fn read_sr_msb(&mut self) -> u8 {
93 self.read_register(CMD_READ_CR)
94 }
95
96 pub fn reset_memory(&mut self) {
97 self.exec_command(CMD_ENABLE_RESET);
98 self.exec_command(CMD_RESET);
99 self.wait_write_finish();
100 }
101 fn exec_command(&mut self, cmd: u8) {
102 let transaction = TransferConfig {
103 iwidth: QspiWidth::SING,
104 awidth: QspiWidth::NONE,
105 dwidth: QspiWidth::NONE,
106 instruction: cmd,
107 address: None,
108 dummy: DummyCycles::_0,
109 };
110 self.qspi.blocking_command(transaction);
111 }
112 fn wait_write_finish(&mut self) {
113 while (self.read_sr_lsb() & 0x01) != 0 {}
114 }
115
116 pub fn read_mid(&mut self) -> [u8; 2] {
117 let mut buffer = [0; 2];
118 let transaction: TransferConfig = TransferConfig {
119 iwidth: QspiWidth::SING,
120 awidth: QspiWidth::SING,
121 dwidth: QspiWidth::SING,
122 instruction: CMD_READ_MID,
123 address: Some(0),
124 dummy: DummyCycles::_0,
125 };
126 self.qspi.blocking_read(&mut buffer, transaction);
127 buffer
128 }
129 pub fn read_uuid(&mut self) -> [u8; 16] {
130 let mut buffer = [0; 16];
131 let transaction: TransferConfig = TransferConfig {
132 iwidth: QspiWidth::SING,
133 awidth: QspiWidth::SING,
134 dwidth: QspiWidth::SING,
135 instruction: CMD_READ_UUID,
136 address: Some(0),
137 dummy: DummyCycles::_8,
138 };
139 self.qspi.blocking_read(&mut buffer, transaction);
140 buffer
141 }
142 pub fn read_id(&mut self) -> [u8; 3] {
143 let mut buffer = [0; 3];
144 let transaction: TransferConfig = TransferConfig {
145 iwidth: QspiWidth::SING,
146 awidth: QspiWidth::NONE,
147 dwidth: QspiWidth::SING,
148 instruction: CMD_READ_ID,
149 address: None,
150 dummy: DummyCycles::_0,
151 };
152 self.qspi.blocking_read(&mut buffer, transaction);
153 buffer
154 }
155
156 pub fn enable_mmap(&mut self) {
157 let transaction: TransferConfig = TransferConfig {
158 iwidth: QspiWidth::SING,
159 awidth: QspiWidth::SING,
160 dwidth: QspiWidth::QUAD,
161 instruction: CMD_QUAD_READ,
162 address: Some(0),
163 dummy: DummyCycles::_8,
164 };
165 self.qspi.enable_memory_map(&transaction);
166 }
167 fn perform_erase(&mut self, addr: u32, cmd: u8) {
168 let transaction = TransferConfig {
169 iwidth: QspiWidth::SING,
170 awidth: QspiWidth::SING,
171 dwidth: QspiWidth::NONE,
172 instruction: cmd,
173 address: Some(addr),
174 dummy: DummyCycles::_0,
175 };
176 self.enable_write();
177 self.qspi.blocking_command(transaction);
178 self.wait_write_finish();
179 }
180 pub fn enable_write(&mut self) {
181 self.exec_command(CMD_WRITE_ENABLE);
182 }
183 pub fn erase_sector(&mut self, addr: u32) {
184 self.perform_erase(addr, CMD_SECTOR_ERASE);
185 }
186 fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) {
187 assert!(
188 (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32,
189 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}",
190 len,
191 addr
192 );
193
194 let transaction = TransferConfig {
195 iwidth: QspiWidth::SING,
196 awidth: QspiWidth::SING,
197 dwidth: QspiWidth::QUAD,
198 instruction: CMD_QUAD_WRITE_PG,
199 address: Some(addr),
200 dummy: DummyCycles::_0,
201 };
202 self.enable_write();
203 if use_dma {
204 self.qspi.blocking_write_dma(buffer, transaction);
205 } else {
206 self.qspi.blocking_write(buffer, transaction);
207 }
208 self.wait_write_finish();
209 }
210 pub fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) {
211 let mut left = buffer.len();
212 let mut place = addr;
213 let mut chunk_start = 0;
214
215 while left > 0 {
216 let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize;
217 let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left };
218 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)];
219 self.write_page(place, chunk, chunk_size, use_dma);
220 place += chunk_size as u32;
221 left -= chunk_size;
222 chunk_start += chunk_size;
223 }
224 }
225
226 pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) {
227 let transaction = TransferConfig {
228 iwidth: QspiWidth::SING,
229 awidth: QspiWidth::SING,
230 dwidth: QspiWidth::QUAD,
231 instruction: CMD_QUAD_READ,
232 address: Some(addr),
233 dummy: DummyCycles::_8,
234 };
235 if use_dma {
236 self.qspi.blocking_read_dma(buffer, transaction);
237 } else {
238 self.qspi.blocking_read(buffer, transaction);
239 }
240 }
241}
242
243const MEMORY_ADDR: u32 = 0x00000000 as u32;
244
245#[embassy_executor::main]
246async fn main(_spawner: Spawner) {
247 let p = embassy_stm32::init(Default::default());
248
249 let config = qspi::Config {
250 memory_size: MemorySize::_16MiB,
251 address_size: AddressSize::_24bit,
252 prescaler: 200,
253 cs_high_time: ChipSelectHighTime::_1Cycle,
254 fifo_threshold: FIFOThresholdLevel::_16Bytes,
255 };
256 let driver = qspi::Qspi::new_bank1(p.QUADSPI, p.PB1, p.PB0, p.PA7, p.PA6, p.PA3, p.PA2, p.DMA2_CH7, config);
257 let mut flash = FlashMemory::new(driver);
258 let mut wr_buf = [0u8; 256];
259 for i in 0..32 {
260 wr_buf[i] = i as u8;
261 }
262 let mut rd_buf = [0u8; 32];
263 flash.erase_sector(MEMORY_ADDR);
264 flash.write_memory(MEMORY_ADDR, &wr_buf, false);
265 flash.read_memory(MEMORY_ADDR, &mut rd_buf, false);
266
267 info!("data read from indirect mode: {}", rd_buf);
268 flash.enable_mmap();
269 let qspi_base = unsafe { core::slice::from_raw_parts(0x9000_0000 as *const u8, 32) };
270 info!("data read from mmap: {}", qspi_base);
271 loop {
272 Timer::after_millis(1000).await;
273 }
274}