Skip to main content

gd32e2_hal/
fmc.rs

1//! Flash memory controller.
2//!
3//! The wait states are not set from here: they have to be raised before the
4//! system clock speeds up, so
5//! [`UnfrozenRcu::freeze`](crate::rcu::UnfrozenRcu::freeze) borrows this type
6//! and writes them itself.
7//!
8//! Erasing and programming need `CTL` unlocked, which happens for the body of
9//! [`Fmc::with_unlocked`] and no longer. The option bytes are covered too, as a
10//! block: [`OptionBytes`] is read, changed and written back whole, because
11//! erasing them takes every byte at once. A written block only takes effect on
12//! the next load, [`Fmc::reload_option_bytes`] or a power-up.
13//!
14//! ```ignore
15//! let mut fmc = dp.fmc.constrain();
16//! let config = ClockConfig::default().sysclk(SysClk::Pll(PllFreq::Mhz48));
17//! let mut rcu = dp.rcu.constrain().freeze(&mut fmc, config);
18//!
19//! fmc.with_unlocked(|f| {
20//!     f.erase_page(Page::P63)?;
21//!     f.program(Page::P63, 0, 0xDEAD_BEEF)
22//! })?;
23//! ```
24
25use crate::pac;
26
27/// Highest `hclk` each wait-state setting can be read at.
28const WS0_MAX_HCLK: u32 = 24_000_000;
29const WS1_MAX_HCLK: u32 = 48_000_000;
30const WS2_MAX_HCLK: u32 = 72_000_000;
31const UNLOCK_KEY1: u32 = 0x4567_0123;
32const UNLOCK_KEY2: u32 = 0xCDEF_89AB;
33
34const BASE: u32 = 0x0800_0000;
35const PAGE_SIZE: u32 = 0x400;
36/// Pages covered by one `OB_WP` bit (user manual, Table 2-4).
37const PAGES_PER_WP_BIT: u32 = 4;
38/// Bytes per programmed word, `PGW` being left at its reset width of 32 bits.
39const WORD_SIZE: u32 = 4;
40
41/// `OB_WP` with every group free, protection being active low.
42const WP_ALL_FREE: u32 = 0xFFFF_FFFF;
43/// Start of the option byte block (user manual, Table 2-3).
44const OB_BASE: u32 = 0x1FFF_F800;
45
46/// Bit positions inside `OB_USER` (user manual, Table 2-3). Bits 3 and 7 are
47/// reserved and are carried through untouched.
48const BIT_NWDG_SW: u8 = 0;
49const BIT_NRST_DPSLP: u8 = 1;
50const BIT_NRST_STDBY: u8 = 2;
51const BIT_BOOT1_N: u8 = 4;
52const BIT_VDDA_VISOR: u8 = 5;
53const BIT_SRAM_PARITY: u8 = 6;
54
55/// Packs two option bytes and their complements into one programmed word.
56///
57/// Every byte of the block is stored next to its inverse, which is what `OBERR`
58/// checks on load; the pair is written out here rather than left to the
59/// controller.
60fn ob_word(low: u8, high: u8) -> u32 {
61    let pair = |byte: u8| byte as u32 | ((!byte as u32) << 8);
62    pair(low) | (pair(high) << 16)
63}
64
65/// The `OB_WP` bit covering `page`, one bit standing for four pages.
66const fn wp_bit(page: Page) -> u32 {
67    let number = (page as u32 - BASE) / PAGE_SIZE;
68    1 << (number / PAGES_PER_WP_BIT)
69}
70
71/// Whether an `OB_WP` mask protects the group holding `page`; a protected group
72/// reads 0.
73const fn wp_protected(wp: u32, page: Page) -> bool {
74    wp & wp_bit(page) == 0
75}
76
77/// Reads one bit of `OB_USER`.
78const fn user_bit(user: u8, bit: u8) -> bool {
79    user & (1 << bit) != 0
80}
81
82/// Returns `OB_USER` with one bit set to `on`, the rest untouched.
83const fn set_user_bit(user: u8, bit: u8, on: bool) -> u8 {
84    if on {
85        user | (1 << bit)
86    } else {
87        user & !(1 << bit)
88    }
89}
90
91macro_rules! pages {
92    ($($n:literal),* $(,)?) => {
93        paste::paste! {
94            /// An erasable 1 KB page of the main flash.
95            ///
96            /// How many pages exist follows the flash of the part being built
97            /// for: 16, 32 or 64.
98            #[allow(missing_docs)]
99            #[derive(Clone, Copy, PartialEq, Eq)]
100            #[cfg_attr(feature = "defmt", derive(defmt::Format))]
101            #[repr(u32)]
102            pub enum Page {
103                $([<P $n>] = BASE + $n * PAGE_SIZE),*
104            }
105        }
106    };
107}
108
109#[cfg(chip_x4)]
110#[rustfmt::skip]
111pages!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
112
113#[cfg(chip_x6)]
114#[rustfmt::skip]
115pages!(
116    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
117    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
118);
119
120#[cfg(chip_x8)]
121#[rustfmt::skip]
122pages!(
123    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
124    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
125    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
126    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
127);
128
129/// An FMC event that can raise an interrupt.
130#[derive(Clone, Copy, PartialEq, Eq)]
131#[cfg_attr(feature = "defmt", derive(defmt::Format))]
132pub enum Event {
133    /// An erase or a program operation finished (`ENDIE`).
134    End,
135    /// An operation failed (`ERRIE`); which way is [`Fmc::take_error`].
136    Error,
137}
138
139/// What an erase or a program operation failed on.
140#[derive(Clone, Copy, PartialEq, Eq)]
141#[cfg_attr(feature = "defmt", derive(defmt::Format))]
142pub enum Error {
143    /// The page is protected by the option bytes.
144    WriteProtected,
145    /// The address is not aligned to the programming width.
146    ProgramAlignment,
147    /// The cell was not erased before programming.
148    Program,
149}
150
151/// How far the option bytes lock the flash against being read out.
152#[derive(Clone, Copy, PartialEq, Eq)]
153#[cfg_attr(feature = "defmt", derive(defmt::Format))]
154pub enum ProtectionLevel {
155    /// No protection: the debugger reads and writes the flash freely.
156    None,
157    /// Debugger access is refused. Leaving this level mass-erases the main
158    /// flash, so the contents cannot be recovered by lowering it.
159    Low,
160    /// As `Low`, and the option bytes themselves can no longer be erased or
161    /// reprogrammed — the part stays this way for good.
162    High,
163}
164
165impl ProtectionLevel {
166    /// The `OB_SPC` code standing for this level.
167    const fn spc(self) -> Spc {
168        match self {
169            ProtectionLevel::None => Spc::None,
170            ProtectionLevel::Low => Spc::Low,
171            ProtectionLevel::High => Spc::High,
172        }
173    }
174}
175
176/// The `OB_SPC` byte itself (user manual, Table 2-3).
177#[derive(Clone, Copy, PartialEq, Eq)]
178#[cfg_attr(feature = "defmt", derive(defmt::Format))]
179#[repr(u8)]
180enum Spc {
181    /// No protection.
182    None = 0xA5,
183    /// Low protection. Every code other than the two named here means this one
184    /// as well, so reading the byte back can yield a different number.
185    Low = 0x00,
186    /// High protection, which cannot be undone.
187    High = 0xCC,
188}
189
190/// Which free watchdog the part starts with (`nWDG_SW`).
191#[derive(Clone, Copy, PartialEq, Eq)]
192#[cfg_attr(feature = "defmt", derive(defmt::Format))]
193pub enum FreeWatchdog {
194    /// Started by hardware: the watchdog runs from reset and has to be fed from
195    /// the first instruction on.
196    Hardware,
197    /// Started by software, which is what
198    /// [`Fwdgt::start`](crate::watchdog::Fwdgt::start) expects.
199    Software,
200}
201
202/// What entering deep-sleep or standby does (`nRST_DPSLP`, `nRST_STDBY`).
203#[derive(Clone, Copy, PartialEq, Eq)]
204#[cfg_attr(feature = "defmt", derive(defmt::Format))]
205pub enum LowPowerEntry {
206    /// The part resets instead of entering the mode.
207    Reset,
208    /// The part enters the mode.
209    Enter,
210}
211
212/// The level `BOOT1` is taken to have (`BOOT1_n`, stored inverted).
213#[derive(Clone, Copy, PartialEq, Eq)]
214#[cfg_attr(feature = "defmt", derive(defmt::Format))]
215pub enum Boot1 {
216    /// `BOOT1` reads as 0.
217    Low,
218    /// `BOOT1` reads as 1.
219    High,
220}
221
222/// Whether the supply monitor watches VDDA (`VDDA_VISOR`).
223#[derive(Clone, Copy, PartialEq, Eq)]
224#[cfg_attr(feature = "defmt", derive(defmt::Format))]
225pub enum VddaMonitor {
226    /// Not watched.
227    Disabled,
228    /// Watched; the part is held in reset while VDDA is too low.
229    Enabled,
230}
231
232/// Whether the SRAM parity check is on (`SRAM_PARITY_CHECK`, stored inverted).
233#[derive(Clone, Copy, PartialEq, Eq)]
234#[cfg_attr(feature = "defmt", derive(defmt::Format))]
235pub enum SramParity {
236    /// Not checked.
237    Disabled,
238    /// Checked.
239    Enabled,
240}
241
242/// The option byte block as a whole, read with [`Fmc::read_option_bytes`] and
243/// written back with [`UnlockedFmc::write_option_bytes`].
244///
245/// Writing goes through the whole block because erasing does: option bytes lose
246/// every byte at once, so a single field cannot be changed on its own. Read the
247/// block, change what you need, write it back.
248#[derive(Clone, Copy, PartialEq, Eq)]
249#[cfg_attr(feature = "defmt", derive(defmt::Format))]
250#[must_use]
251pub struct OptionBytes {
252    protection: ProtectionLevel,
253    user: u8,
254    data: u16,
255    wp: u32,
256}
257
258impl Default for OptionBytes {
259    /// The state the part leaves the factory in: no protection, and every other
260    /// byte erased.
261    fn default() -> Self {
262        Self {
263            protection: ProtectionLevel::None,
264            user: 0xFF,
265            data: 0xFFFF,
266            wp: WP_ALL_FREE,
267        }
268    }
269}
270
271impl OptionBytes {
272    /// Leaves the flash readable by a debugger.
273    pub const fn no_protection(mut self) -> Self {
274        self.protection = ProtectionLevel::None;
275        self
276    }
277    /// Refuses debugger access. Going back to
278    /// [`no_protection`](Self::no_protection) later mass-erases the main flash.
279    pub const fn protection_low(mut self) -> Self {
280        self.protection = ProtectionLevel::Low;
281        self
282    }
283    /// Refuses debugger access **for good**: after this the option bytes
284    /// themselves can no longer be erased or reprogrammed, so no later call can
285    /// undo it and the part keeps this setting for the rest of its life.
286    pub const fn protection_high_forever(mut self) -> Self {
287        self.protection = ProtectionLevel::High;
288        self
289    }
290    /// Picks which free watchdog the part starts with.
291    pub const fn free_watchdog(mut self, watchdog: FreeWatchdog) -> Self {
292        self.user = set_user_bit(
293            self.user,
294            BIT_NWDG_SW,
295            matches!(watchdog, FreeWatchdog::Software),
296        );
297        self
298    }
299    /// Says what entering deep-sleep does.
300    pub const fn deep_sleep(mut self, entry: LowPowerEntry) -> Self {
301        self.user = set_user_bit(
302            self.user,
303            BIT_NRST_DPSLP,
304            matches!(entry, LowPowerEntry::Enter),
305        );
306        self
307    }
308    /// Says what entering standby does.
309    pub const fn standby(mut self, entry: LowPowerEntry) -> Self {
310        self.user = set_user_bit(
311            self.user,
312            BIT_NRST_STDBY,
313            matches!(entry, LowPowerEntry::Enter),
314        );
315        self
316    }
317    /// Sets the level `BOOT1` is taken to have.
318    pub const fn boot1(mut self, boot1: Boot1) -> Self {
319        self.user = set_user_bit(self.user, BIT_BOOT1_N, matches!(boot1, Boot1::Low));
320        self
321    }
322    /// Turns the VDDA monitor on or off.
323    pub const fn vdda_monitor(mut self, monitor: VddaMonitor) -> Self {
324        self.user = set_user_bit(
325            self.user,
326            BIT_VDDA_VISOR,
327            matches!(monitor, VddaMonitor::Enabled),
328        );
329        self
330    }
331    /// Turns the SRAM parity check on or off.
332    pub const fn sram_parity(mut self, parity: SramParity) -> Self {
333        self.user = set_user_bit(
334            self.user,
335            BIT_SRAM_PARITY,
336            matches!(parity, SramParity::Disabled),
337        );
338        self
339    }
340    /// Sets the two user data bytes, which the silicon never reads itself.
341    pub const fn data(mut self, data: u16) -> Self {
342        self.data = data;
343        self
344    }
345    /// Closes `page` to erasing and programming.
346    ///
347    /// One `OB_WP` bit covers four pages, so this closes the three neighbours of
348    /// `page` along with it.
349    pub const fn protect(mut self, page: Page) -> Self {
350        self.wp &= !wp_bit(page);
351        self
352    }
353    /// Opens `page`, and with it the three pages sharing its `OB_WP` bit.
354    pub const fn unprotect(mut self, page: Page) -> Self {
355        self.wp |= wp_bit(page);
356        self
357    }
358
359    /// The protection level this block asks for.
360    pub const fn protection(&self) -> ProtectionLevel {
361        self.protection
362    }
363    /// Which free watchdog the part starts with.
364    pub const fn get_free_watchdog(&self) -> FreeWatchdog {
365        if user_bit(self.user, BIT_NWDG_SW) {
366            FreeWatchdog::Software
367        } else {
368            FreeWatchdog::Hardware
369        }
370    }
371    /// What entering deep-sleep does.
372    pub const fn get_deep_sleep(&self) -> LowPowerEntry {
373        if user_bit(self.user, BIT_NRST_DPSLP) {
374            LowPowerEntry::Enter
375        } else {
376            LowPowerEntry::Reset
377        }
378    }
379    /// What entering standby does.
380    pub const fn get_standby(&self) -> LowPowerEntry {
381        if user_bit(self.user, BIT_NRST_STDBY) {
382            LowPowerEntry::Enter
383        } else {
384            LowPowerEntry::Reset
385        }
386    }
387    /// The level `BOOT1` is taken to have.
388    pub const fn get_boot1(&self) -> Boot1 {
389        if user_bit(self.user, BIT_BOOT1_N) {
390            Boot1::Low
391        } else {
392            Boot1::High
393        }
394    }
395    /// Whether the VDDA monitor is on.
396    pub const fn get_vdda_monitor(&self) -> VddaMonitor {
397        if user_bit(self.user, BIT_VDDA_VISOR) {
398            VddaMonitor::Enabled
399        } else {
400            VddaMonitor::Disabled
401        }
402    }
403    /// Whether the SRAM parity check is on.
404    pub const fn get_sram_parity(&self) -> SramParity {
405        if user_bit(self.user, BIT_SRAM_PARITY) {
406            SramParity::Disabled
407        } else {
408            SramParity::Enabled
409        }
410    }
411    /// The two user data bytes.
412    pub const fn data_bytes(&self) -> u16 {
413        self.data
414    }
415    /// Whether this block closes `page` to erasing and programming.
416    pub const fn is_protected(&self, page: Page) -> bool {
417        wp_protected(self.wp, page)
418    }
419}
420
421/// The flash controller with `CTL` unlocked, borrowed for the body of
422/// [`Fmc::with_unlocked`] and locked again when that call returns.
423pub struct UnlockedFmc<'a> {
424    fmc: &'a mut Fmc,
425}
426
427impl UnlockedFmc<'_> {
428    fn lock(self) {
429        self.fmc.fmc.ctl().modify(|_, w| w.lk().lock());
430    }
431
432    /// Erases one page, blocking until it is done.
433    ///
434    /// The whole page reads back as `0xFF`; nothing here checks what the page
435    /// holds.
436    ///
437    /// # Errors
438    ///
439    /// [`Error::WriteProtected`] if `page` is write-protected.
440    pub fn erase_page(&mut self, page: Page) -> Result<(), Error> {
441        self.fmc.fmc.ctl().modify(|_, w| w.per().page_erase());
442        self.fmc.fmc.addr().write(|w| w.addr().bits(page as u32));
443        self.fmc.fmc.ctl().modify(|_, w| w.start().start());
444        let result = self.fmc.wait_busy();
445        self.fmc.fmc.ctl().modify(|_, w| w.per().clear_bit());
446        result
447    }
448    /// Erases the whole main flash, blocking until it is done.
449    ///
450    /// That includes the code running the call, so this only makes sense from
451    /// SRAM or from a debugger.
452    ///
453    /// # Errors
454    ///
455    /// [`Error::WriteProtected`] if any page is write-protected.
456    pub fn mass_erase(&mut self) -> Result<(), Error> {
457        self.fmc.fmc.ctl().modify(|_, w| w.mer().mass_erase());
458        self.fmc.fmc.ctl().modify(|_, w| w.start().start());
459        let result = self.fmc.wait_busy();
460        self.fmc.fmc.ctl().modify(|_, w| w.mer().clear_bit());
461        result
462    }
463    /// Programs one 32-bit word, `index` counting words from the start of
464    /// `page`, and blocks until it is done.
465    ///
466    /// Programming only clears bits, so the word has to be erased first.
467    ///
468    /// # Errors
469    ///
470    /// [`Error::WriteProtected`] if `page` is write-protected, [`Error::Program`]
471    /// if the word holds anything but `0xFFFF_FFFF`.
472    pub fn program(&mut self, page: Page, index: u8, word: u32) -> Result<(), Error> {
473        self.fmc.fmc.ctl().modify(|_, w| w.pg().program());
474        let addr = page as u32 + index as u32 * WORD_SIZE;
475        // The write itself is the command: `PG` makes the FMC latch the address
476        // and the data off the bus, so there is no `ADDR` and no `START` here.
477        // SAFETY: the address is in the flash and a multiple of four by
478        // construction — `Page` gives the base and 256 words is exactly what `u8`
479        // counts.
480        unsafe {
481            core::ptr::write_volatile(addr as *mut u32, word);
482        };
483        let result = self.fmc.wait_busy();
484        self.fmc.fmc.ctl().modify(|_, w| w.pg().clear_bit());
485        result
486    }
487
488    /// Erases the option byte block and programs `ob` in its place, blocking
489    /// until it is done.
490    ///
491    /// The whole block goes at once because erasing takes it all: read it with
492    /// [`Fmc::read_option_bytes`], change what you need, write it back.
493    ///
494    /// Nothing here takes effect until the option bytes are loaded again, by
495    /// [`Fmc::reload_option_bytes`] or by the next power-up.
496    ///
497    /// # Errors
498    ///
499    /// The first error the erase or the programming reports. The rest of the
500    /// call is skipped, leaving the block erased or partly programmed.
501    pub fn write_option_bytes(&mut self, ob: &OptionBytes) -> Result<(), Error> {
502        // `OBER` and `OBPG` answer to a second lock of their own.
503        self.fmc.fmc.obkey().write(|w| w.obkey().bits(UNLOCK_KEY1));
504        self.fmc.fmc.obkey().write(|w| w.obkey().bits(UNLOCK_KEY2));
505        self.fmc.fmc.ctl().modify(|_, w| w.obwen().set_bit());
506        let result = self
507            .erase_option_bytes()
508            .and_then(|()| self.program_option_bytes(ob));
509        self.fmc.fmc.ctl().modify(|_, w| w.obwen().disable());
510        result
511    }
512    /// Erases the whole option byte block, every byte going back to `0xFF`.
513    fn erase_option_bytes(&mut self) -> Result<(), Error> {
514        self.fmc
515            .fmc
516            .ctl()
517            .modify(|_, w| w.ober().option_byte_erase());
518        self.fmc.fmc.ctl().modify(|_, w| w.start().start());
519        let result = self.fmc.wait_busy();
520        self.fmc.fmc.ctl().modify(|_, w| w.ober().clear_bit());
521        result
522    }
523    /// Programs the erased block, one word per pair of option bytes.
524    fn program_option_bytes(&mut self, ob: &OptionBytes) -> Result<(), Error> {
525        let data = ob.data.to_le_bytes();
526        let wp = ob.wp.to_le_bytes();
527        let words = [
528            ob_word(ob.protection.spc() as u8, ob.user),
529            ob_word(data[0], data[1]),
530            ob_word(wp[0], wp[1]),
531            ob_word(wp[2], wp[3]),
532        ];
533
534        self.fmc
535            .fmc
536            .ctl()
537            .modify(|_, w| w.obpg().option_byte_programming());
538        let mut result = Ok(());
539        for (index, word) in words.iter().enumerate() {
540            let addr = OB_BASE + index as u32 * WORD_SIZE;
541            // As in `program`, the write is the command.
542            // SAFETY: the address is a word of the option byte block, which the
543            // loop cannot leave.
544            unsafe { core::ptr::write_volatile(addr as *mut u32, *word) };
545            result = self.fmc.wait_busy();
546            if result.is_err() {
547                break;
548            }
549        }
550        self.fmc.fmc.ctl().modify(|_, w| w.obpg().clear_bit());
551        result
552    }
553
554    /// Raises an interrupt on `event`, which still has to be unmasked in the
555    /// NVIC.
556    ///
557    /// The interrupt outlives [`Fmc::with_unlocked`]: locking `CTL` again leaves
558    /// it enabled.
559    ///
560    /// `ENDF` is a level, and it rises while a blocking operation still holds
561    /// the controller, so a handler has nothing to clear it with: mask the line
562    /// in the NVIC inside the handler, then unpend and unmask it once the call
563    /// has returned.
564    pub fn listen(&mut self, event: Event) {
565        self.fmc.fmc.ctl().modify(|_, w| match event {
566            Event::End => w.endie().enabled(),
567            Event::Error => w.errie().enabled(),
568        });
569    }
570    /// Stops `event` from raising an interrupt.
571    pub fn unlisten(&mut self, event: Event) {
572        self.fmc.fmc.ctl().modify(|_, w| match event {
573            Event::End => w.endie().disabled(),
574            Event::Error => w.errie().disabled(),
575        });
576    }
577}
578
579/// Owns the flash memory controller.
580pub struct Fmc {
581    fmc: pac::Fmc,
582}
583
584impl Fmc {
585    /// Blocks until the running operation ends, then clears `ENDF` and reports
586    /// how it went.
587    fn wait_busy(&mut self) -> Result<(), Error> {
588        while self.fmc.stat().read().busy().is_active() {}
589        self.clear_interrupt(Event::End);
590        match self.take_error() {
591            Some(error) => Err(error),
592            None => Ok(()),
593        }
594    }
595
596    fn unlock(&mut self) -> UnlockedFmc<'_> {
597        self.fmc.key().write(|w| w.key().bits(UNLOCK_KEY1));
598        self.fmc.key().write(|w| w.key().bits(UNLOCK_KEY2));
599        UnlockedFmc { fmc: self }
600    }
601
602    /// Unlocks `CTL`, runs `f`, locks it again, and returns what `f` returned.
603    ///
604    /// The unlocked handle cannot outlive the call, so the flash is never left
605    /// writable.
606    pub fn with_unlocked<R>(&mut self, f: impl FnOnce(&mut UnlockedFmc) -> R) -> R {
607        let mut unlocked = self.unlock();
608        let result = f(&mut unlocked);
609        unlocked.lock();
610        result
611    }
612
613    /// Returns the peripheral with its interrupts off.
614    pub fn release(mut self) -> pac::Fmc {
615        self.with_unlocked(|fmc| {
616            fmc.unlisten(Event::End);
617            fmc.unlisten(Event::Error);
618        });
619        self.fmc
620    }
621
622    /// Sets the wait states `hclk` can be read at, `hclk` given in Hz.
623    ///
624    /// Must run before the system clock rises and after it falls, so the flash
625    /// is never read faster than it responds.
626    pub(crate) fn set_ws(&mut self, hclk: u32) {
627        self.fmc.ws().modify(|_, w| {
628            if hclk <= WS0_MAX_HCLK {
629                w.wscnt().ws0()
630            } else if hclk <= WS1_MAX_HCLK {
631                w.wscnt().ws1()
632            } else if hclk <= WS2_MAX_HCLK {
633                w.wscnt().ws2()
634            } else {
635                unreachable!()
636            }
637        });
638    }
639
640    /// Whether the option bytes protect `page` from being erased or programmed.
641    ///
642    /// This is what stands behind [`Error::WriteProtected`]. Protection comes
643    /// in groups of four pages, so neighbours share the answer.
644    pub fn is_protected(&self, page: Page) -> bool {
645        wp_protected(self.fmc.wp().read().bits(), page)
646    }
647    /// The security protection level the option bytes ask for.
648    pub fn protection_level(&self) -> ProtectionLevel {
649        let plevel = self.fmc.obstat().read().plevel();
650        if plevel.is_none() {
651            ProtectionLevel::None
652        } else if plevel.is_low() {
653            ProtectionLevel::Low
654        } else {
655            ProtectionLevel::High
656        }
657    }
658    /// Whether the option bytes failed their checksum, in which case the
659    /// defaults were loaded instead of them.
660    pub fn option_error(&self) -> bool {
661        self.fmc.obstat().read().oberr().is_error()
662    }
663    /// The user option byte, raw;
664    /// [`read_option_bytes`](Self::read_option_bytes) decodes it.
665    pub fn user_option(&self) -> u8 {
666        self.fmc.obstat().read().ob_user().bits()
667    }
668    /// The two user data bytes of the option block, raw — the silicon attaches
669    /// no meaning to them.
670    pub fn data_option(&self) -> u16 {
671        self.fmc.obstat().read().ob_data().bits()
672    }
673    /// The product ID code, fixed in silicon and read-only.
674    pub fn product_id_code(&self) -> u32 {
675        self.fmc.pid().read().pid().bits()
676    }
677
678    /// The option bytes as they were loaded at reset.
679    ///
680    /// This is the block to change and hand to
681    /// [`UnlockedFmc::write_option_bytes`]; it reads what is in force, so a
682    /// block written since the last reset is not what comes back.
683    pub fn read_option_bytes(&self) -> OptionBytes {
684        OptionBytes {
685            protection: self.protection_level(),
686            user: self.user_option(),
687            data: self.data_option(),
688            wp: self.fmc.wp().read().bits(),
689        }
690    }
691
692    /// Reloads the option bytes, which resets the part and therefore never
693    /// returns.
694    ///
695    /// This is how a written block takes effect without cycling the power.
696    pub fn reload_option_bytes(&mut self) -> ! {
697        self.fmc.ctl().modify(|_, w| w.obrld().set_bit());
698        loop {
699            cortex_m::asm::nop();
700        }
701    }
702
703    /// Turns the prefetch buffer on or off; it comes up on after reset.
704    ///
705    /// Off, every fetch waits out the wait states of its own, which is slower on
706    /// average but takes the buffer out of the timing.
707    pub fn set_prefetch(&mut self, on: bool) {
708        self.fmc.ws().modify(|_, w| w.pfen().bit(on));
709    }
710    /// Whether the prefetch buffer is on.
711    pub fn is_prefetch_enabled(&self) -> bool {
712        self.fmc.ws().read().pfen().bit_is_set()
713    }
714
715    /// Returns the error the last operation ended with, clearing its flag.
716    pub fn take_error(&mut self) -> Option<Error> {
717        let stat = self.fmc.stat().read();
718        if stat.wperr().is_error() {
719            self.fmc.stat().write(|w| w.wperr().clear());
720            Some(Error::WriteProtected)
721        } else if stat.pgaerr().bit_is_set() {
722            self.fmc.stat().write(|w| w.pgaerr().bit(true));
723            Some(Error::ProgramAlignment)
724        } else if stat.pgerr().is_error() {
725            self.fmc.stat().write(|w| w.pgerr().clear());
726            Some(Error::Program)
727        } else {
728            None
729        }
730    }
731
732    /// Whether `event` currently raises an interrupt.
733    pub fn is_listening(&self, event: Event) -> bool {
734        let ctl = self.fmc.ctl().read();
735        match event {
736            Event::End => ctl.endie().is_enabled(),
737            Event::Error => ctl.errie().is_enabled(),
738        }
739    }
740
741    /// Clears the flag behind `event`, which is what stops it re-entering the
742    /// handler.
743    ///
744    /// For [`Event::Error`] this drops every error flag at once; use
745    /// [`take_error`](Self::take_error) instead to learn which one it was, it
746    /// clears the flag as well.
747    pub fn clear_interrupt(&mut self, event: Event) {
748        self.fmc.stat().write(|w| match event {
749            Event::End => w.endf().clear(),
750            Event::Error => w.wperr().clear().pgaerr().bit(true).pgerr().clear(),
751        });
752    }
753}
754
755/// Entry point on the raw peripheral.
756pub trait FmcExt {
757    /// Takes the peripheral.
758    ///
759    /// Nothing is written and no clock is gated — the flash controller is always
760    /// clocked.
761    fn constrain(self) -> Fmc;
762}
763
764impl FmcExt for pac::Fmc {
765    fn constrain(self) -> Fmc {
766        Fmc { fmc: self }
767    }
768}