1use alloc::{format, string::String};
8use core::fmt;
9use core::ops::RangeInclusive;
10
11use crate::arm::Cortex;
12use crate::arm::ap::Idr;
13use crate::arm::ap::{IDR_AHB_AP_CORTEX_M3, IDR_AHB_AP_CORTEX_M4};
14use crate::arm::dp::IdCode;
15
16const STM32F1_FLASH_BASE: u32 = 0x0800_0000;
18const STM32F4_FLASH_BASE: u32 = 0x0800_0000;
19
20const STM32F4_RAM_BASE: u32 = 0x2000_0000;
22const STM32F1_RAM_BASE: u32 = 0x2000_0000;
23
24const GPIOX_MODER_OFFSET: u32 = 0x00;
26const GPIOX_OTYPER_OFFSET: u32 = 0x04;
27const GPIOX_OSPEEDR_OFFSET: u32 = 0x08;
28const GPIOX_PUPDR_OFFSET: u32 = 0x0C;
29const GPIOX_IDR_OFFSET: u32 = 0x10;
30const GPIOX_ODR_OFFSET: u32 = 0x14;
31const GPIOX_BSRR_OFFSET: u32 = 0x18;
32const GPIOX_LCKR_OFFSET: u32 = 0x1C;
33const GPIOX_AFRL_OFFSET: u32 = 0x20;
34const GPIOX_AFRH_OFFSET: u32 = 0x24;
35
36const STM32F4_GPIOA_REG_BASE: u32 = 0x4002_0000;
38pub const STM32F4_GPIOA_MODER: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_MODER_OFFSET;
39pub const STM32F4_GPIOA_OTYPER: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_OTYPER_OFFSET;
40pub const STM32F4_GPIOA_OSPEEDR: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_OSPEEDR_OFFSET;
41pub const STM32F4_GPIOA_PUPDR: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_PUPDR_OFFSET;
42pub const STM32F4_GPIOA_IDR: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_IDR_OFFSET;
43pub const STM32F4_GPIOA_ODR: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_ODR_OFFSET;
44pub const STM32F4_GPIOA_BSRR: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_BSRR_OFFSET;
45pub const STM32F4_GPIOA_LCKR: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_LCKR_OFFSET;
46pub const STM32F4_GPIOA_AFRL: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_AFRL_OFFSET;
47pub const STM32F4_GPIOA_AFRH: u32 = STM32F4_GPIOA_REG_BASE + GPIOX_AFRH_OFFSET;
48
49const STM32F4_GPIOB_REG_BASE: u32 = 0x4002_0400;
51pub const STM32F4_GPIOB_MODER: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_MODER_OFFSET;
52pub const STM32F4_GPIOB_OTYPER: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_OTYPER_OFFSET;
53pub const STM32F4_GPIOB_OSPEEDR: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_OSPEEDR_OFFSET;
54pub const STM32F4_GPIOB_PUPDR: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_PUPDR_OFFSET;
55pub const STM32F4_GPIOB_IDR: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_IDR_OFFSET;
56pub const STM32F4_GPIOB_ODR: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_ODR_OFFSET;
57pub const STM32F4_GPIOB_BSRR: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_BSRR_OFFSET;
58pub const STM32F4_GPIOB_LCKR: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_LCKR_OFFSET;
59pub const STM32F4_GPIOB_AFRL: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_AFRL_OFFSET;
60pub const STM32F4_GPIOB_AFRH: u32 = STM32F4_GPIOB_REG_BASE + GPIOX_AFRH_OFFSET;
61
62const STM32F4_GPIOC_REG_BASE: u32 = 0x4002_0800;
64pub const STM32F4_GPIOC_MODER: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_MODER_OFFSET;
65pub const STM32F4_GPIOC_OTYPER: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_OTYPER_OFFSET;
66pub const STM32F4_GPIOC_OSPEEDR: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_OSPEEDR_OFFSET;
67pub const STM32F4_GPIOC_PUPDR: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_PUPDR_OFFSET;
68pub const STM32F4_GPIOC_IDR: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_IDR_OFFSET;
69pub const STM32F4_GPIOC_ODR: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_ODR_OFFSET;
70pub const STM32F4_GPIOC_BSRR: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_BSRR_OFFSET;
71pub const STM32F4_GPIOC_LCKR: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_LCKR_OFFSET;
72pub const STM32F4_GPIOC_AFRL: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_AFRL_OFFSET;
73pub const STM32F4_GPIOC_AFRH: u32 = STM32F4_GPIOC_REG_BASE + GPIOX_AFRH_OFFSET;
74
75const STM32F4_GPIOD_REG_BASE: u32 = 0x4002_0C00;
77pub const STM32F4_GPIOD_MODER: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_MODER_OFFSET;
78pub const STM32F4_GPIOD_OTYPER: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_OTYPER_OFFSET;
79pub const STM32F4_GPIOD_OSPEEDR: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_OSPEEDR_OFFSET;
80pub const STM32F4_GPIOD_PUPDR: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_PUPDR_OFFSET;
81pub const STM32F4_GPIOD_IDR: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_IDR_OFFSET;
82pub const STM32F4_GPIOD_ODR: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_ODR_OFFSET;
83pub const STM32F4_GPIOD_BSRR: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_BSRR_OFFSET;
84pub const STM32F4_GPIOD_LCKR: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_LCKR_OFFSET;
85pub const STM32F4_GPIOD_AFRL: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_AFRL_OFFSET;
86pub const STM32F4_GPIOD_AFRH: u32 = STM32F4_GPIOD_REG_BASE + GPIOX_AFRH_OFFSET;
87
88const STM32F4_GPIOE_REG_BASE: u32 = 0x4002_1000;
90pub const STM32F4_GPIOE_MODER: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_MODER_OFFSET;
91pub const STM32F4_GPIOE_OTYPER: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_OTYPER_OFFSET;
92pub const STM32F4_GPIOE_OSPEEDR: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_OSPEEDR_OFFSET;
93pub const STM32F4_GPIOE_PUPDR: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_PUPDR_OFFSET;
94pub const STM32F4_GPIOE_IDR: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_IDR_OFFSET;
95pub const STM32F4_GPIOE_ODR: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_ODR_OFFSET;
96pub const STM32F4_GPIOE_BSRR: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_BSRR_OFFSET;
97pub const STM32F4_GPIOE_LCKR: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_LCKR_OFFSET;
98pub const STM32F4_GPIOE_AFRL: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_AFRL_OFFSET;
99pub const STM32F4_GPIOE_AFRH: u32 = STM32F4_GPIOE_REG_BASE + GPIOX_AFRH_OFFSET;
100
101pub const STM32F4_MODER_OUTPUT: u32 = 0b01;
103pub const STM32F4_MODER_INPUT: u32 = 0b00;
104pub const STM32F4_MODER_AF: u32 = 0b10;
105pub const STM32F4_MODER_ANALOG: u32 = 0b11;
106pub const STM32F4_MODER_MASK: u32 = 0b11;
107
108pub const STM32F4_PUPDR_NONE: u32 = 0b00;
110pub const STM32F4_PUPDR_PU: u32 = 0b01;
111pub const STM32F4_PUPDR_PD: u32 = 0b10;
112pub const STM32F4_PUPDR_MASK: u32 = 0b11;
113
114const STM32F4_FLASH_REG_BASE: u32 = 0x4002_3C00;
116
117pub struct Stm32F4FlashCr;
121
122impl Stm32F4FlashCr {
123 pub const ADDRESS: u32 = STM32F4_FLASH_REG_BASE + 0x10;
125
126 pub const LOCK_BIT: u32 = 31;
128 pub const ERRIE_BIT: u32 = 25;
129 pub const EOPIE_BIT: u32 = 24;
130 pub const STRT_BIT: u32 = 16;
131 pub const MER_BIT: u32 = 2;
132 pub const SER_BIT: u32 = 1;
133 pub const PG_BIT: u32 = 0;
134
135 pub const SNB_SHIFT: u32 = 3;
137 pub const PSIZE_SHIFT: u32 = 8;
138
139 pub const SNB_MASK: u32 = 0b1111;
141 pub const PSIZE_MASK: u32 = 0b11;
142
143 pub const PSIZE_X8: u32 = 0b00;
146 pub const PSIZE_X16: u32 = 0b01;
147 pub const PSIZE_X32: u32 = 0b10;
148 pub const PSIZE_X64: u32 = 0b11;
149}
150
151pub struct Stm32F4FlashSr(u32);
156
157impl Stm32F4FlashSr {
158 pub const ADDRESS: u32 = STM32F4_FLASH_REG_BASE + 0x0C;
160
161 pub const EOP_BIT: u32 = 0;
163 pub const OPERR_BIT: u32 = 1;
164 pub const WRPERR_BIT: u32 = 4;
165 pub const PGAERR_BIT: u32 = 5;
166 pub const PGPERR_BIT: u32 = 6;
167 pub const PGSERR_BIT: u32 = 7;
168 pub const RDERR_BIT: u32 = 8;
169 pub const BSY_BIT: u32 = 16;
170
171 pub fn busy(&self) -> bool {
173 (self.0 >> Self::BSY_BIT) & 1 != 0
174 }
175
176 pub fn errors(&self) -> bool {
178 let error_mask = (1 << Self::OPERR_BIT)
179 | (1 << Self::WRPERR_BIT)
180 | (1 << Self::PGAERR_BIT)
181 | (1 << Self::PGPERR_BIT)
182 | (1 << Self::PGSERR_BIT)
183 | (1 << Self::RDERR_BIT);
184 self.0 & error_mask != 0
185 }
186}
187
188impl From<u32> for Stm32F4FlashSr {
189 fn from(value: u32) -> Self {
190 Self(value)
191 }
192}
193
194impl From<Stm32F4FlashSr> for u32 {
195 fn from(sr: Stm32F4FlashSr) -> Self {
196 sr.0
197 }
198}
199
200impl fmt::Display for Stm32F4FlashSr {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 write!(f, "0x{:08X}", self.0)
203 }
204}
205
206pub struct Stm32F4FlashKeyr;
210
211impl Stm32F4FlashKeyr {
212 pub const ADDRESS: u32 = STM32F4_FLASH_REG_BASE + 0x04;
214
215 pub const KEY1: u32 = 0x45670123;
217 pub const KEY2: u32 = 0xCDEF89AB;
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq)]
222pub enum StmFamily {
223 F4,
225
226 F1,
228
229 Unknown,
231}
232
233impl StmFamily {
234 pub fn known(&self) -> bool {
236 !matches!(self, StmFamily::Unknown)
237 }
238}
239
240impl fmt::Display for StmFamily {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 match self {
243 StmFamily::F4 => write!(f, "STM32F4"),
244 StmFamily::F1 => write!(f, "STM32F1"),
245 StmFamily::Unknown => write!(f, "Unknown"),
246 }
247 }
248}
249
250#[allow(non_camel_case_types)]
252#[derive(Debug, Clone, Copy, PartialEq, Eq)]
253pub enum StmLine {
254 F401BC,
256
257 F401DE,
259
260 F411,
262
263 F427_F437,
265
266 F413_F423,
268
269 F4x5,
271
272 F446,
274
275 F103,
277
278 Unknown,
280}
281
282impl StmLine {
283 pub fn ram_size_bytes(&self) -> Option<u32> {
288 self.ram_size_kb().map(|size| size * 1024)
289 }
290
291 pub fn ram_size_kb(&self) -> Option<u32> {
296 match self {
297 StmLine::F401BC => Some(96),
298 StmLine::F401DE => Some(96),
299 StmLine::F411 => Some(128),
300 StmLine::F427_F437 => Some(192),
301 StmLine::F413_F423 => Some(256),
302 StmLine::F4x5 => Some(128),
303 StmLine::F446 => Some(128),
304 StmLine::F103 => Some(20),
305 StmLine::Unknown => None,
306 }
307 }
308
309 pub fn ccm_ram_size_bytes(&self) -> Option<u32> {
311 self.ccm_ram_size_kb().map(|size| size * 1024)
312 }
313
314 pub fn ccm_ram_size_kb(&self) -> Option<u32> {
316 match self {
317 StmLine::F401BC => None,
318 StmLine::F401DE => None,
319 StmLine::F411 => None,
320 StmLine::F427_F437 => None,
321 StmLine::F413_F423 => None,
322 StmLine::F4x5 => Some(64),
323 StmLine::F446 => None,
324 StmLine::F103 => None,
325 StmLine::Unknown => None,
326 }
327 }
328}
329
330impl fmt::Display for StmLine {
331 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332 match self {
333 StmLine::F401BC => write!(f, "STM32F401B/C"),
334 StmLine::F401DE => write!(f, "STM32F401D/E"),
335 StmLine::F4x5 => write!(f, "STM32F405/415/07/17"),
336 StmLine::F411 => write!(f, "STM32F411"),
337 StmLine::F413_F423 => write!(f, "STM32F413/423"),
338 StmLine::F427_F437 => write!(f, "STM32F427/437"),
339 StmLine::F446 => write!(f, "STM32F446"),
340 StmLine::F103 => write!(f, "STM32F103"),
341 StmLine::Unknown => write!(f, "Unknown STM32"),
342 }
343 }
344}
345
346#[derive(Debug, Clone, Copy, PartialEq, Eq)]
362pub struct StmDeviceId {
363 raw: u32,
364}
365
366impl StmDeviceId {
367 pub const ADDRESS: u32 = 0xE004_2000;
369
370 pub fn new(raw: u32) -> Self {
372 Self { raw }
373 }
374
375 pub fn raw(&self) -> u32 {
377 self.raw
378 }
379
380 pub fn revision(&self) -> u16 {
382 ((self.raw >> 16) & 0xFFFF) as u16
383 }
384
385 pub fn device_id(&self) -> u16 {
387 (self.raw & 0xFFF) as u16
388 }
389
390 pub fn family(&self) -> StmFamily {
392 match self.device_id() {
393 0x423 | 0x433 | 0x431 | 0x413 | 0x419 | 0x463 | 0x421 => StmFamily::F4,
394 0x412 | 0x410 | 0x414 | 0x430 | 0x418 => StmFamily::F1,
395 _ => StmFamily::Unknown,
396 }
397 }
398
399 pub fn line(&self) -> StmLine {
401 match self.device_id() {
402 0x423 => StmLine::F401BC,
403 0x433 => StmLine::F401DE,
404 0x431 => StmLine::F411,
405 0x413 => StmLine::F4x5,
406 0x419 => StmLine::F427_F437,
407 0x463 => StmLine::F413_F423,
408 0x421 => StmLine::F446,
409 0x410 => StmLine::F103,
410 _ => StmLine::Unknown,
411 }
412 }
413
414 pub fn revision_str(&self) -> &'static str {
417 match self.line() {
418 StmLine::F401BC | StmLine::F401DE => match self.revision() {
419 0x1000 => "A",
420 0x1001 => "1/Z",
421 _ => "unknown",
422 },
423 StmLine::F411 => match self.revision() {
424 0x1000 => "A/1/Z",
425 _ => "unknown",
426 },
427 StmLine::F4x5 => match self.revision() {
428 0x1000 => "A",
430 0x1001 => "Z",
431 0x1003 => "1",
432 0x1007 => "2",
433 0x100F => "Y/4",
434 0x101F => "5/6",
435 _ => "unknown",
436 },
437 StmLine::F427_F437 => match self.revision() {
438 0x1000 => "A",
439 0x1003 => "Y",
440 0x2001 => "3",
441 0x2003 => "4/5/B",
442 _ => "unknown",
443 },
444 StmLine::F413_F423 => match self.revision() {
445 0x1000 => "A/1",
446 _ => "unknown",
447 },
448 StmLine::F446 => match self.revision() {
449 0x1000 => "A/1",
450 _ => "unknown",
451 },
452 StmLine::F103 => match self.revision() {
453 0x0000 => "A",
454 0x2000 => "B",
455 0x2001 => "Z",
456 0x2003 => "1/2/3/X/Y",
457 _ => "unknown",
458 },
459 StmLine::Unknown => "unknown",
460 }
461 }
462
463 pub fn is_known_device(&self) -> bool {
465 !matches!(self.line(), StmLine::Unknown)
466 }
467}
468
469impl From<u32> for StmDeviceId {
470 fn from(raw: u32) -> Self {
471 Self::new(raw)
472 }
473}
474
475impl fmt::Display for StmDeviceId {
476 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477 if f.alternate() {
478 write!(
479 f,
480 "STM32 Device ID: 0x{:08X} ({} {})",
481 self.raw(),
482 self.line(),
483 self.revision_str()
484 )
485 } else {
486 write!(f, "{}", self.line())
487 }
488 }
489}
490
491impl fmt::LowerHex for StmDeviceId {
492 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493 write!(f, "0x{:08x}", self.raw)
494 }
495}
496
497impl fmt::UpperHex for StmDeviceId {
498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499 write!(f, "0x{:08X}", self.raw)
500 }
501}
502
503#[derive(Debug, Clone, Copy, PartialEq, Eq)]
508pub struct StmUniqueId {
509 uid: [u32; 3],
510}
511
512impl StmUniqueId {
513 pub const STM32F4_INITIAL_ADDRESS: u32 = 0x1FFF_7A10;
514 pub const STM32F1_INITIAL_ADDRESS: u32 = 0x1FFF_F7E8;
515
516 pub fn addr_from_family(family: StmFamily) -> Option<u32> {
519 match family {
520 StmFamily::F4 => Some(Self::STM32F4_INITIAL_ADDRESS),
521 StmFamily::F1 => Some(Self::STM32F1_INITIAL_ADDRESS),
522 StmFamily::Unknown => None,
523 }
524 }
525
526 pub fn new(uid: [u32; 3]) -> Self {
529 Self { uid }
530 }
531
532 pub fn x_y(&self) -> u32 {
536 self.uid[0]
537 }
538
539 pub fn x(&self) -> u16 {
541 (self.x_y() & 0xFFFF) as u16
542 }
543
544 pub fn y(&self) -> u16 {
546 ((self.x_y() >> 16) & 0xFFFF) as u16
547 }
548
549 pub fn wafer(&self) -> u8 {
552 (self.uid[1] & 0xFF) as u8
553 }
554
555 pub fn lot(&self) -> [u8; 7] {
557 let uid1_bytes = self.uid[1].to_le_bytes();
558 let uid2_bytes = self.uid[2].to_le_bytes();
559
560 [
561 uid2_bytes[3], uid2_bytes[2], uid2_bytes[1], uid2_bytes[0], uid1_bytes[3], uid1_bytes[2], uid1_bytes[1], ]
569 }
570
571 pub fn wafer_str(&self) -> String {
573 let byte = self.wafer();
574 format!("0x{byte:02X}")
575 }
576
577 pub fn lot_str(&self) -> String {
579 let bytes = self.lot();
580
581 let mut result = String::new();
582 for &byte in &bytes {
583 if byte.is_ascii_graphic() {
584 result.push(byte as char);
585 } else {
586 result.push('.')
587 }
588 }
589 result
590 }
591
592 pub fn raw(&self) -> [u32; 3] {
594 self.uid
595 }
596}
597
598impl fmt::Display for StmUniqueId {
599 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
600 write!(
601 f,
602 "UID[95:0]: 0x{:08X}{:08X}{:08X} Lot: {} Wafer: {} X/Y: {}/{}",
603 self.raw()[2],
604 self.raw()[1],
605 self.raw()[0],
606 self.lot_str(),
607 self.wafer_str(),
608 self.x(),
609 self.y(),
610 )
611 }
612}
613
614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
619pub struct StmFlashSize {
620 raw: u16,
621}
622
623impl StmFlashSize {
624 pub const STM32F4_ADDRESS_OF_U16: u32 = 0x1FFF_7A20;
628 pub const STM32F1_ADDRESS_OF_U16: u32 = 0x1FFF_F7E0;
629
630 pub fn addr_from_family(family: StmFamily) -> Option<u32> {
633 match family {
634 StmFamily::F4 => Some(Self::STM32F4_ADDRESS_OF_U16),
635 StmFamily::F1 => Some(Self::STM32F1_ADDRESS_OF_U16),
636 StmFamily::Unknown => None,
637 }
638 }
639
640 pub fn new(raw: u16) -> Self {
642 Self { raw }
643 }
644
645 pub fn raw(&self) -> u16 {
647 self.raw
648 }
649
650 pub fn size_bytes(&self) -> u32 {
652 (self.raw as u32) * 1024
653 }
654
655 pub fn size_kb(&self) -> u32 {
657 self.raw as u32
658 }
659}
660
661impl fmt::Display for StmFlashSize {
662 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
663 write!(f, "Flash Size: {} KB", self.size_kb())
664 }
665}
666
667#[derive(Debug, Clone, Copy, PartialEq, Eq)]
669pub struct StmDetails {
670 mcu: StmDeviceId,
672
673 idcode: IdCode,
675
676 uid: Option<StmUniqueId>,
678
679 flash_size: Option<StmFlashSize>,
681}
682
683impl StmDetails {
684 pub fn new(
686 mcu: StmDeviceId,
687 idcode: IdCode,
688 uid: Option<StmUniqueId>,
689 flash_size: Option<StmFlashSize>,
690 ) -> Self {
691 Self {
692 mcu,
693 idcode,
694 uid,
695 flash_size,
696 }
697 }
698
699 pub fn idcode(&self) -> &IdCode {
700 &self.idcode
701 }
702
703 pub fn get_cortex(&self) -> Option<Cortex> {
704 Cortex::from_idcode(self.idcode)
705 }
706
707 pub fn mcu(&self) -> &StmDeviceId {
709 &self.mcu
710 }
711
712 pub fn uid(&self) -> Option<StmUniqueId> {
714 self.uid
715 }
716
717 pub fn flash_size_bytes(&self) -> Option<u32> {
719 self.flash_size.map(|size| size.size_bytes())
720 }
721
722 pub fn flash_size_kb(&self) -> Option<StmFlashSize> {
724 self.flash_size
725 }
726
727 pub fn flash_base(&self) -> Option<u32> {
729 match self.mcu.family() {
730 StmFamily::F4 => Some(STM32F4_FLASH_BASE),
731 StmFamily::F1 => Some(STM32F1_FLASH_BASE),
732 StmFamily::Unknown => None,
733 }
734 }
735
736 pub fn ram_base(&self) -> Option<u32> {
738 match self.mcu.family() {
739 StmFamily::F4 => Some(STM32F4_RAM_BASE),
740 StmFamily::F1 => Some(STM32F1_RAM_BASE),
741 StmFamily::Unknown => None,
742 }
743 }
744
745 pub fn is_stm32f4(&self) -> bool {
747 matches!(self.mcu.family(), StmFamily::F4)
748 }
749
750 pub fn is_stm32f1(&self) -> bool {
752 matches!(self.mcu.family(), StmFamily::F1)
753 }
754
755 pub const MAX_SECTORS: u8 = 12;
757
758 const SECTOR_SIZES_BYTES: [u32; Self::MAX_SECTORS as usize] = [
761 16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024, 128 * 1024, 128 * 1024, 128 * 1024, 128 * 1024, 128 * 1024, 128 * 1024, 128 * 1024, 128 * 1024, ];
774
775 pub fn get_sector_size_bytes(&self, sector: u8) -> Option<u32> {
792 if !self.is_stm32f4() {
793 return None;
794 }
795
796 let value = if sector < Self::SECTOR_SIZES_BYTES.len() as u8 {
798 Self::SECTOR_SIZES_BYTES[sector as usize]
799 } else {
800 return None;
801 };
802
803 let flash_size = self.flash_size_bytes()? as usize;
806
807 let mut total_size: usize = 0;
810 for size in Self::SECTOR_SIZES_BYTES.iter().take(sector as usize + 1) {
811 total_size += *size as usize;
812 if total_size > flash_size {
813 return None; }
815 }
816 Some(value)
817 }
818
819 pub fn get_sector_size_kb(&self, sector: u8) -> Option<u32> {
834 self.get_sector_size_bytes(sector).map(|size| size / 1024)
835 }
836
837 pub fn get_sectors_from_word_range(
853 &self,
854 range: RangeInclusive<u32>,
855 sectors: &mut [u8; Self::MAX_SECTORS as usize],
856 ) -> Option<usize> {
857 if !self.is_stm32f4() {
858 return None;
859 }
860
861 let start_word = *range.start();
863 let start_bytes = start_word * 4;
864 let end_word = *range.end();
865 let end_bytes = end_word * 4;
866
867 if start_word > end_word {
869 return None; }
871 let flash_size = self.flash_size_bytes()?;
872 if end_bytes + 4 > flash_size {
873 return None; }
875
876 let mut sector_count = 0;
878 let mut current_address = 0u32;
879 let range_end_bytes = end_bytes + 3; for (sector_num, §or_size) in Self::SECTOR_SIZES_BYTES.iter().enumerate() {
882 let sector_start = current_address;
883 let sector_end = current_address + sector_size - 1;
884
885 if start_bytes <= sector_end && range_end_bytes >= sector_start {
887 sectors[sector_count] = sector_num as u8;
888 sector_count += 1;
889 }
890
891 current_address += sector_size;
892
893 if current_address > range_end_bytes {
895 break;
896 }
897 }
898
899 Some(sector_count)
900 }
901
902 pub fn expected_idr(&self) -> Option<Idr> {
908 if self.is_stm32f4() {
909 Some(IDR_AHB_AP_CORTEX_M4)
910 } else if self.is_stm32f1() {
911 Some(IDR_AHB_AP_CORTEX_M3)
912 } else {
913 None
914 }
915 }
916}
917
918impl fmt::Display for StmDetails {
919 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
920 if f.alternate() {
921 write!(f, "{:#}", self.mcu)?;
922
923 if let Some(flash_size) = self.flash_size {
924 write!(f, " {} KB", flash_size.size_kb())?;
925 } else {
926 write!(f, " Flash Size: unknown ")?;
927 };
928
929 if let Some(uid) = &self.uid {
930 write!(f, " {uid}")
931 } else {
932 write!(f, " UID: unknown ")
933 }
934 } else {
935 write!(f, "{}", self.mcu)
936 }
937 }
938}