Skip to content

Commit 035f767

Browse files
authored
Merge pull request #83 from BridgeSource/flash_patches
Changes to Flash.rs
2 parents 4d3dc74 + f5fdae3 commit 035f767

File tree

2 files changed

+412
-23
lines changed

2 files changed

+412
-23
lines changed

examples/flash_with_rtic.rs

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
#![allow(unsafe_code)]
2+
#![allow(warnings)]
3+
#![allow(missing_docs)]
4+
#![allow(unused_variables)]
5+
#![no_main]
6+
#![no_std]
7+
8+
mod utils;
9+
10+
#[rtic::app(device = stm32g4xx_hal::stm32g4::stm32g474, peripherals = true)]
11+
mod app {
12+
use crate::utils::logger;
13+
use stm32g4xx_hal::flash::{FlashExt, FlashSize, FlashWriter, Parts};
14+
use stm32g4xx_hal::prelude::*;
15+
use stm32g4xx_hal::rcc::{PllConfig, RccExt};
16+
17+
const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;
18+
19+
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
20+
21+
// Resources shared between tasks
22+
#[shared]
23+
struct Shared {}
24+
25+
// Local resources to specific tasks (cannot be shared)
26+
#[local]
27+
struct Local {}
28+
29+
fn compare_arrays(a: &[u8], b: &[u8]) -> bool {
30+
if a.len() != b.len() {
31+
return false;
32+
}
33+
for i in 0..a.len() {
34+
if a[i] != b[i] {
35+
return false;
36+
}
37+
}
38+
true
39+
}
40+
41+
#[init]
42+
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
43+
let dp = cx.device;
44+
let cp = cx.core;
45+
46+
let rcc = dp.RCC.constrain();
47+
let mut pll_config = stm32g4xx_hal::rcc::PllConfig::default();
48+
49+
// Sysclock is based on PLL_R
50+
pll_config.mux = stm32g4xx_hal::rcc::PLLSrc::HSI; // 16MHz
51+
pll_config.n = stm32g4xx_hal::rcc::PllNMul::MUL_32;
52+
pll_config.m = stm32g4xx_hal::rcc::PllMDiv::DIV_2; // f(vco) = 16MHz*32/2 = 256MHz
53+
pll_config.r = Some(stm32g4xx_hal::rcc::PllRDiv::DIV_2); // f(sysclock) = 256MHz/2 = 128MHz
54+
55+
// Note to future self: The AHB clock runs the timers, among other things.
56+
// Please refer to the Clock Tree manual to determine if it is worth
57+
// changing to a lower speed for battery life savings.
58+
let mut clock_config = stm32g4xx_hal::rcc::Config::default()
59+
.pll_cfg(pll_config)
60+
.clock_src(stm32g4xx_hal::rcc::SysClockSrc::PLL);
61+
62+
// After clock configuration, the following should be true:
63+
// Sysclock is 128MHz
64+
// AHB clock is 128MHz
65+
// APB1 clock is 128MHz
66+
// APB2 clock is 128MHz
67+
// The ADC will ultimately be put into synchronous mode and will derive
68+
// its clock from the AHB bus clock, with a prescalar of 2 or 4.
69+
70+
let mut rcc = rcc.freeze(clock_config);
71+
72+
unsafe {
73+
let mut flash = &(*stm32g4xx_hal::stm32::FLASH::ptr());
74+
flash.acr.modify(|_, w| {
75+
w.latency().bits(0b1000) // 8 wait states
76+
});
77+
}
78+
79+
// *** FLASH Memory ***
80+
let one_byte = [0x12 as u8];
81+
let two_bytes = [0xAB, 0xCD as u8];
82+
let three_bytes = [0x12, 0x34, 0x56 as u8];
83+
let four_bytes = [0xAB, 0xCD, 0xEF, 0xBA as u8];
84+
let eight_bytes = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 as u8];
85+
let sixteen_bytes = [
86+
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
87+
0xDE, 0xF0 as u8,
88+
];
89+
let mut flash = dp.FLASH.constrain();
90+
let mut flash_writer = flash.writer::<2048>(FlashSize::Sz256K);
91+
92+
const FLASH_SPACING: u32 = 16; // Separate flash writes by 16 bytes
93+
const FLASH_EXAMPLE_START_ADDRESS: u32 = 0x1FC00;
94+
95+
logger::info!(
96+
"Erasing 128 bytes at address {}",
97+
FLASH_EXAMPLE_START_ADDRESS
98+
);
99+
flash_writer
100+
.erase(FLASH_EXAMPLE_START_ADDRESS, 128)
101+
.unwrap(); // Erase entire page
102+
103+
for i in 0..6 {
104+
match i {
105+
0 => {
106+
// This test should fail, as the data needs to be divisible by 8 and force padding is false
107+
let result = flash_writer.write(
108+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
109+
&one_byte,
110+
false,
111+
);
112+
assert!(result.is_err());
113+
assert_eq!(
114+
result.err().unwrap(),
115+
stm32g4xx_hal::flash::Error::ArrayMustBeDivisibleBy8
116+
);
117+
118+
// This test should pass, as the data needs to be divisible by 8 and force padding is true, so the one_byte array will be padded with 7 bytes of 0xFF
119+
let result = flash_writer.write(
120+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
121+
&one_byte,
122+
true,
123+
);
124+
assert!(result.is_ok());
125+
logger::info!(
126+
"Wrote 1 byte to address {}",
127+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING
128+
);
129+
}
130+
1 => {
131+
// This test should fail, as the data needs to be divisible by 8 and force padding is false
132+
let result = flash_writer.write(
133+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
134+
&two_bytes,
135+
false,
136+
);
137+
assert!(result.is_err());
138+
assert_eq!(
139+
result.err().unwrap(),
140+
stm32g4xx_hal::flash::Error::ArrayMustBeDivisibleBy8
141+
);
142+
143+
// This test should pass, as the data needs to be divisible by 8 and force padding is true, so the one_byte array will be padded with 7 bytes of 0xFF
144+
let result = flash_writer.write(
145+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
146+
&two_bytes,
147+
true,
148+
);
149+
assert!(result.is_ok());
150+
logger::info!(
151+
"Wrote 2 bytes to address {}",
152+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING
153+
);
154+
}
155+
2 => {
156+
// This test should fail, as the data needs to be divisible by 8 and force padding is false
157+
let result = flash_writer.write(
158+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
159+
&three_bytes,
160+
false,
161+
);
162+
assert!(result.is_err());
163+
assert_eq!(
164+
result.err().unwrap(),
165+
stm32g4xx_hal::flash::Error::ArrayMustBeDivisibleBy8
166+
);
167+
168+
// This test should pass, as the data needs to be divisible by 8 and force padding is true, so the one_byte array will be padded with 7 bytes of 0xFF
169+
let result = flash_writer.write(
170+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
171+
&three_bytes,
172+
true,
173+
);
174+
assert!(result.is_ok());
175+
logger::info!(
176+
"Wrote 3 bytes to address {}",
177+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING
178+
);
179+
}
180+
3 => {
181+
// This test should fail, as the data needs to be divisible by 8 and force padding is false
182+
let result = flash_writer.write(
183+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
184+
&four_bytes,
185+
false,
186+
);
187+
assert!(result.is_err());
188+
assert_eq!(
189+
result.err().unwrap(),
190+
stm32g4xx_hal::flash::Error::ArrayMustBeDivisibleBy8
191+
);
192+
193+
// This test should pass, as the data needs to be divisible by 8 and force padding is true, so the one_byte array will be padded with 7 bytes of 0xFF
194+
let result = flash_writer.write(
195+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
196+
&four_bytes,
197+
true,
198+
);
199+
assert!(result.is_ok());
200+
logger::info!(
201+
"Wrote 4 bytes to address {}",
202+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING
203+
);
204+
}
205+
4 => {
206+
flash_writer
207+
.write(
208+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
209+
&eight_bytes,
210+
false,
211+
)
212+
.unwrap();
213+
logger::info!(
214+
"Wrote 8 bytes to address {}",
215+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING
216+
);
217+
}
218+
5 => {
219+
flash_writer
220+
.write(FLASH_EXAMPLE_START_ADDRESS + i * 16, &sixteen_bytes, false)
221+
.unwrap();
222+
logger::info!(
223+
"Wrote 16 bytes to address {}",
224+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING
225+
);
226+
}
227+
_ => (),
228+
}
229+
}
230+
231+
logger::info!("Validating data written data by performing read and compare");
232+
233+
for i in 0..6 {
234+
match i {
235+
0 => {
236+
let bytes = flash_writer
237+
.read(FLASH_EXAMPLE_START_ADDRESS as u32, one_byte.len())
238+
.unwrap();
239+
assert!(compare_arrays(&bytes, &one_byte));
240+
logger::info!("Validated 1 byte data");
241+
}
242+
1 => {
243+
let bytes = flash_writer
244+
.read(
245+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
246+
two_bytes.len(),
247+
)
248+
.unwrap();
249+
assert!(compare_arrays(&bytes, &two_bytes));
250+
logger::info!("Validated 2 byte data");
251+
}
252+
2 => {
253+
let bytes = flash_writer
254+
.read(
255+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
256+
three_bytes.len(),
257+
)
258+
.unwrap();
259+
assert!(compare_arrays(&bytes, &three_bytes));
260+
logger::info!("Validated 3 byte data");
261+
}
262+
3 => {
263+
let bytes = flash_writer
264+
.read(
265+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
266+
four_bytes.len(),
267+
)
268+
.unwrap();
269+
assert!(compare_arrays(&bytes, &four_bytes));
270+
logger::info!("Validated 4 byte data");
271+
}
272+
4 => {
273+
let bytes = flash_writer
274+
.read(
275+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
276+
eight_bytes.len(),
277+
)
278+
.unwrap();
279+
assert!(compare_arrays(&bytes, &eight_bytes));
280+
logger::info!("Validated 8 byte data");
281+
}
282+
5 => {
283+
let bytes = flash_writer
284+
.read(
285+
FLASH_EXAMPLE_START_ADDRESS + i * FLASH_SPACING,
286+
sixteen_bytes.len(),
287+
)
288+
.unwrap();
289+
assert!(compare_arrays(&bytes, &sixteen_bytes));
290+
logger::info!("Validated 5 byte data");
291+
}
292+
_ => (),
293+
}
294+
}
295+
296+
logger::info!(
297+
"Finished flash example at address {}",
298+
FLASH_EXAMPLE_START_ADDRESS
299+
);
300+
301+
(
302+
// Initialization of shared resources
303+
Shared {},
304+
// Initialization of task local resources
305+
Local {},
306+
// Move the monotonic timer to the RTIC run-time, this enables
307+
// scheduling
308+
init::Monotonics(),
309+
)
310+
}
311+
312+
// Background task, runs whenever no other tasks are running
313+
#[idle]
314+
fn idle(mut cx: idle::Context) -> ! {
315+
loop {
316+
// Sleep until next interrupt
317+
cortex_m::asm::wfi();
318+
}
319+
}
320+
}

0 commit comments

Comments
 (0)