stm32f303xc/
flash.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Embedded Flash Memory Controller
6//!
7//! Used for reading, writing and erasing the flash and the option bytes.
8//! Erase and write operations have hardware interrupt support, while read
9//! operations use pseudo interrupts in the form of deferred calls. The
10//! programming interface only allows halfword(u16) writes.
11//!
12//! Option bytes should be used with caution, especially those concerning
13//! read and write protection. For example, erasing the option bytes
14//! enables by default readout protection.
15
16use core::cell::Cell;
17use core::ops::{Index, IndexMut};
18use kernel::deferred_call::{DeferredCall, DeferredCallClient};
19use kernel::hil;
20use kernel::utilities::cells::OptionalCell;
21use kernel::utilities::cells::TakeCell;
22use kernel::utilities::cells::VolatileCell;
23use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
24use kernel::utilities::registers::register_bitfields;
25use kernel::utilities::registers::{ReadOnly, ReadWrite, WriteOnly};
26use kernel::utilities::StaticRef;
27use kernel::ErrorCode;
28
29const FLASH_BASE: StaticRef<FlashRegisters> =
30    unsafe { StaticRef::new(0x40022000 as *const FlashRegisters) };
31
32#[repr(C)]
33struct FlashRegisters {
34    /// Flash access control register
35    /// Address offset 0x00
36    pub acr: ReadWrite<u32, AccessControl::Register>,
37    /// Flash key register
38    /// Address offset 0x04
39    pub kr: WriteOnly<u32, Key::Register>,
40    /// Flash option key register
41    /// Address offset 0x08
42    pub okr: WriteOnly<u32, Key::Register>,
43    /// Flash status register
44    /// Address offset 0x0C
45    pub sr: ReadWrite<u32, Status::Register>,
46    /// Flash control register
47    /// Address offset 0x10
48    pub cr: ReadWrite<u32, Control::Register>,
49    /// Flash address register
50    /// Address offset 0x14
51    pub ar: WriteOnly<u32, Address::Register>,
52    /// Reserved
53    _reserved: u32,
54    /// Flash option byte register
55    /// Address offset 0x1C
56    pub obr: ReadOnly<u32, OptionByte::Register>,
57    /// Flash write protection register
58    /// Address offset 0x20
59    pub wrpr: ReadOnly<u32, WriteProtect::Register>,
60}
61
62register_bitfields! [u32,
63    AccessControl [
64        /// Prefetch buffer status
65        PRFTBS OFFSET(5) NUMBITS(1) [],
66        /// Prefetch buffer enable
67        PRFTBE OFFSET(4) NUMBITS(1) [],
68        /// Flash half cycle access enable
69        HLFCYA OFFSET(3) NUMBITS(1) [],
70        /// Represents the ratio of the HCLK period to the Flash access time
71        LATENCY OFFSET(0) NUMBITS(3) [
72            /// If 0 < HCLK <= 24MHz
73            ZeroWaitState = 0,
74            /// If 24MHz < HCLK <= 48MHz
75            OneWaitState = 1,
76            /// If 48MHz < HCLK <= 72MHz
77            TwoWaitState = 2
78        ]
79    ],
80    Key [
81        /// Flash or option byte key
82        /// Represents the keys to unlock the flash or the option
83        /// bytes write enable
84        KEYR OFFSET(0) NUMBITS(32) []
85    ],
86    Status [
87        /// End of operation
88        /// Set by the hardware when a flash operation (programming or erase)
89        /// is completed.
90        EOP OFFSET(5) NUMBITS(1) [],
91        /// Write protection error
92        /// Set by the hardware when programming a write-protected
93        /// address of the flash memory.
94        WRPRTERR OFFSET(4) NUMBITS(1) [],
95        /// Programming error
96        /// Set by the hardware when an address to be programmed contains a
97        /// value different from 0xFFFF before programming.
98        /// Note that the STRT bit in Control register should be reset when
99        /// the operation finishes or and error occurs.
100        PGERR OFFSET(2) NUMBITS(1) [],
101        /// Busy
102        /// Indicates that a flash operation is in progress. This is set on
103        /// the beginning of a Flash operation and reset when the operation
104        /// finishes or an error occurs.
105        BSY OFFSET(0) NUMBITS(1) []
106    ],
107    Control [
108        /// Force option byte loading
109        /// When set, this bit forces the option byte reloading.
110        /// This generates a system reset.
111        OBLLAUNCH OFFSET(13) NUMBITS(1) [],
112        /// End of operation interrupt enable
113        /// This enables the interrupt generation when the EOP bit in the
114        /// Status register is set.
115        EOPIE OFFSET(12) NUMBITS(1) [],
116        /// Error interrupt enable
117        /// This bit enables the interrupt generation on an errror when PGERR
118        /// or WRPRTERR are set in the Status register
119        ERRIE OFFSET(10) NUMBITS(1) [],
120        /// Option bytes write enable
121        /// When set, the option bytes can be programmed. This bit is set on
122        /// on writing the correct key sequence to the OptionKey register.
123        OPTWRE OFFSET(9) NUMBITS(1) [],
124        /// When set, it indicates that the Flash is locked. This bit is reset
125        /// by hardware after detecting the unlock sequence.
126        LOCK OFFSET(7) NUMBITS(1) [],
127        /// This bit triggers and ERASE operation when set. This bit is only
128        /// set by software and reset when the BSY bit is reset.
129        STRT OFFSET(6) NUMBITS(1) [],
130        /// Option byte erase chosen
131        OPTER OFFSET(5) NUMBITS(1) [],
132        /// Option byte programming chosen
133        OPTPG OFFSET(4) NUMBITS(1) [],
134        /// Mass erase of all user pages chosen
135        MER OFFSET(2) NUMBITS(1) [],
136        /// Page erase chosen
137        PER OFFSET(1) NUMBITS(1) [],
138        /// Flash programming chosen
139        PG OFFSET(0) NUMBITS(1) []
140    ],
141    Address [
142        /// Flash address
143        /// Chooses the address to program when programming is selected
144        /// or a page to erase when Page Erase is selected.
145        /// Note that write access to this register is blocked when the
146        /// BSY bit in the Status register is set.
147        FAR OFFSET(0) NUMBITS(32) []
148    ],
149    OptionByte [
150        DATA1 OFFSET(24) NUMBITS(8) [],
151        DATA0 OFFSET(16) NUMBITS(8) [],
152        /// This allows the user to enable the SRAM hardware parity check.
153        /// Disabled by default.
154        SRAMPE OFFSET(14) NUMBITS(1) [
155            /// Parity check enabled
156            ENABLED = 0,
157            /// Parity check diasbled
158            DISABLED = 1
159        ],
160        /// This bit selects the analog monitoring on the VDDA power source
161        VDDAMONITOR OFFSET(13) NUMBITS(1) [
162            /// VDDA power supply supervisor disabled
163            DISABLED = 0,
164            /// VDDA power supply supervisor enabled
165            ENABLED = 1
166        ],
167        /// Together with the BOOT0, this bit selects Boot mode from the main
168        /// Flash memory, SRAM or System memory
169        NBOOT1 OFFSET(12) NUMBITS(1) [],
170        NRSTSTDBY OFFSET(10) NUMBITS(1) [
171            /// Reset generated when entering Standby mode
172            RST = 0,
173            /// No reset generated
174            NRST = 1
175        ],
176        NRSTSTOP OFFSET(9) NUMBITS(1) [
177            /// Reset generated when entering Stop mode
178            RST = 0,
179            /// No reset generated
180            NRST = 1
181        ],
182        /// Chooses watchdog type
183        WDGSW OFFSET(8) NUMBITS(1) [
184            /// Hardware watchdog
185            HARDWARE = 0,
186            /// Software watchdog
187            SOFTWARE = 1
188        ],
189        /// Read protection Level status
190        RDPRT OFFSET(1) NUMBITS(2) [
191            /// Read protection level 0 (ST production setup)
192            LVL0 = 0,
193            /// Read protection level 1
194            LVL1 = 1,
195            /// Read protection level 2
196            LVL2 = 3
197        ],
198        /// Option byte Load error
199        /// When set, this indicates that the loaded option byte and its
200        /// complement do not match. The corresponding byte and its complement
201        /// are read as 0xFF in the OptionByte or WriteProtect register
202        OPTERR OFFSET(1) NUMBITS(1) []
203    ],
204    WriteProtect [
205        /// Write protect
206        /// This register contains the write-protection option
207        /// bytes loaded by the OBL
208        WRP OFFSET(0) NUMBITS(32) []
209    ]
210];
211
212const PAGE_SIZE: usize = 2048;
213
214/// Address of the first flash page.
215const PAGE_START: usize = 0x08000000;
216
217/// Address of the first option byte.
218const OPT_START: usize = 0x1FFFF800;
219
220/// Used for unlocking the flash or the option bytes.
221const KEY1: u32 = 0x45670123;
222const KEY2: u32 = 0xCDEF89AB;
223
224/// This is a wrapper around a u8 array that is sized to a single page for the
225/// stm32f303xc. Users of this module must pass an object of this type to use the
226/// `hil::flash::Flash` interface.
227///
228/// An example looks like:
229///
230/// ```rust
231/// # extern crate stm32f303xc;
232/// # use stm32f303xc::flash::StmF303Page;
233/// # use kernel::static_init;
234///
235/// let pagebuffer = unsafe { static_init!(StmF303Page, StmF303Page::default()) };
236/// ```
237pub struct StmF303Page(pub [u8; PAGE_SIZE]);
238
239impl Default for StmF303Page {
240    fn default() -> Self {
241        Self([0; PAGE_SIZE])
242    }
243}
244
245impl StmF303Page {
246    fn len(&self) -> usize {
247        self.0.len()
248    }
249}
250
251impl Index<usize> for StmF303Page {
252    type Output = u8;
253
254    fn index(&self, idx: usize) -> &u8 {
255        &self.0[idx]
256    }
257}
258
259impl IndexMut<usize> for StmF303Page {
260    fn index_mut(&mut self, idx: usize) -> &mut u8 {
261        &mut self.0[idx]
262    }
263}
264
265impl AsMut<[u8]> for StmF303Page {
266    fn as_mut(&mut self) -> &mut [u8] {
267        &mut self.0
268    }
269}
270
271#[derive(Clone, Copy, PartialEq)]
272pub enum FlashState {
273    Ready,       // Entry state.
274    Read,        // Read procedure.
275    Write,       // Programming procedure.
276    Erase,       // Erase procedure.
277    WriteOption, // Option bytes programming procedure.
278    EraseOption, // Option bytes erase procedure.
279}
280
281pub struct Flash {
282    registers: StaticRef<FlashRegisters>,
283    client: OptionalCell<&'static dyn hil::flash::Client<Flash>>,
284    buffer: TakeCell<'static, StmF303Page>,
285    state: Cell<FlashState>,
286    write_counter: Cell<usize>,
287    page_number: Cell<usize>,
288    deferred_call: DeferredCall,
289}
290
291impl Flash {
292    pub fn new() -> Flash {
293        Flash {
294            registers: FLASH_BASE,
295            client: OptionalCell::empty(),
296            buffer: TakeCell::empty(),
297            state: Cell::new(FlashState::Ready),
298            write_counter: Cell::new(0),
299            page_number: Cell::new(0),
300            deferred_call: DeferredCall::new(),
301        }
302    }
303
304    /// Enables hardware interrupts.
305    pub fn enable(&self) {
306        self.registers.cr.modify(Control::EOPIE::SET);
307        self.registers.cr.modify(Control::ERRIE::SET);
308    }
309
310    pub fn is_locked(&self) -> bool {
311        self.registers.cr.is_set(Control::LOCK)
312    }
313
314    pub fn unlock(&self) {
315        self.registers.kr.write(Key::KEYR.val(KEY1));
316        self.registers.kr.write(Key::KEYR.val(KEY2));
317    }
318
319    pub fn lock(&self) {
320        self.registers.cr.modify(Control::LOCK::SET);
321    }
322
323    pub fn unlock_option(&self) {
324        self.registers.okr.write(Key::KEYR.val(KEY1));
325        self.registers.okr.write(Key::KEYR.val(KEY2));
326    }
327
328    pub fn lock_option(&self) {
329        self.registers.cr.modify(Control::OPTWRE::CLEAR);
330    }
331
332    /// Forces option byte reloading. Also generates a system reset.
333    pub fn load_option(&self) {
334        self.registers.cr.modify(Control::OBLLAUNCH::SET);
335    }
336
337    pub fn handle_interrupt(&self) {
338        if self.registers.sr.is_set(Status::EOP) {
339            // Cleared by writing a 1.
340            self.registers.sr.modify(Status::EOP::SET);
341
342            match self.state.get() {
343                FlashState::Write => {
344                    self.write_counter.set(self.write_counter.get() + 2);
345
346                    if self.write_counter.get() == PAGE_SIZE {
347                        self.registers.cr.modify(Control::PG::CLEAR);
348                        self.state.set(FlashState::Ready);
349                        self.write_counter.set(0);
350
351                        self.client.map(|client| {
352                            self.buffer.take().map(|buffer| {
353                                client.write_complete(buffer, Ok(()));
354                            });
355                        });
356                    } else {
357                        self.program_halfword();
358                    }
359                }
360                FlashState::Erase => {
361                    if self.registers.cr.is_set(Control::PER) {
362                        self.registers.cr.modify(Control::PER::CLEAR);
363                    }
364
365                    if self.registers.cr.is_set(Control::MER) {
366                        self.registers.cr.modify(Control::MER::CLEAR);
367                    }
368
369                    self.state.set(FlashState::Ready);
370                    self.client.map(|client| {
371                        client.erase_complete(Ok(()));
372                    });
373                }
374                FlashState::WriteOption => {
375                    self.registers.cr.modify(Control::OPTPG::CLEAR);
376                    self.state.set(FlashState::Ready);
377
378                    self.client.map(|client| {
379                        self.buffer.take().map(|buffer| {
380                            client.write_complete(buffer, Ok(()));
381                        });
382                    });
383                }
384                FlashState::EraseOption => {
385                    self.registers.cr.modify(Control::OPTER::CLEAR);
386                    self.state.set(FlashState::Ready);
387
388                    self.client.map(|client| {
389                        client.erase_complete(Ok(()));
390                    });
391                }
392                _ => {}
393            }
394        }
395
396        if self.state.get() == FlashState::Read {
397            self.state.set(FlashState::Ready);
398            self.client.map(|client| {
399                self.buffer.take().map(|buffer| {
400                    client.read_complete(buffer, Ok(()));
401                });
402            });
403        }
404
405        if self.registers.sr.is_set(Status::WRPRTERR) {
406            // Cleared by writing a 1.
407            self.registers.sr.modify(Status::WRPRTERR::SET);
408
409            match self.state.get() {
410                FlashState::Write => {
411                    self.registers.cr.modify(Control::PG::CLEAR);
412                    self.client.map(|client| {
413                        self.buffer.take().map(|buffer| {
414                            client.write_complete(buffer, Err(hil::flash::Error::FlashError));
415                        });
416                    });
417                }
418                FlashState::Erase => {
419                    self.client.map(|client| {
420                        client.erase_complete(Err(hil::flash::Error::FlashError));
421                    });
422                }
423                _ => {}
424            }
425
426            self.state.set(FlashState::Ready);
427        }
428
429        if self.registers.sr.is_set(Status::PGERR) {
430            // Cleared by writing a 1.
431            self.registers.sr.modify(Status::PGERR::SET);
432
433            match self.state.get() {
434                FlashState::Write => {
435                    self.registers.cr.modify(Control::PG::CLEAR);
436                    self.client.map(|client| {
437                        self.buffer.take().map(|buffer| {
438                            client.write_complete(buffer, Err(hil::flash::Error::FlashError));
439                        });
440                    });
441                }
442                FlashState::WriteOption => {
443                    self.registers.cr.modify(Control::OPTPG::CLEAR);
444                    self.client.map(|client| {
445                        self.buffer.take().map(|buffer| {
446                            client.write_complete(buffer, Err(hil::flash::Error::FlashError));
447                        });
448                    });
449                }
450                FlashState::Erase => {
451                    self.client.map(|client| {
452                        client.erase_complete(Err(hil::flash::Error::FlashError));
453                    });
454                }
455                _ => {}
456            }
457
458            self.state.set(FlashState::Ready);
459        }
460    }
461
462    pub fn program_halfword(&self) {
463        self.buffer.take().map(|buffer| {
464            let i = self.write_counter.get();
465
466            let halfword: u16 = (buffer[i] as u16) << 0 | (buffer[i + 1] as u16) << 8;
467            let page_addr = PAGE_START + self.page_number.get() * PAGE_SIZE;
468            let address = page_addr + i;
469            let location = unsafe { &*(address as *const VolatileCell<u16>) };
470            location.set(halfword);
471
472            self.buffer.replace(buffer);
473        });
474    }
475
476    pub fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> {
477        if page_number > 127 {
478            return Err(ErrorCode::INVAL);
479        }
480
481        if self.is_locked() {
482            self.unlock();
483        }
484
485        self.enable();
486        self.state.set(FlashState::Erase);
487
488        // Choose page erase mode.
489        self.registers.cr.modify(Control::PER::SET);
490        self.registers
491            .ar
492            .write(Address::FAR.val((PAGE_START + page_number * PAGE_SIZE) as u32));
493        self.registers.cr.modify(Control::STRT::SET);
494
495        Ok(())
496    }
497
498    pub fn erase_all(&self) -> Result<(), ErrorCode> {
499        if self.is_locked() {
500            self.unlock();
501        }
502
503        self.enable();
504        self.state.set(FlashState::Erase);
505
506        // Choose mass erase mode.
507        self.registers.cr.modify(Control::MER::SET);
508        self.registers.cr.modify(Control::STRT::SET);
509
510        Ok(())
511    }
512
513    pub fn write_page(
514        &self,
515        page_number: usize,
516        buffer: &'static mut StmF303Page,
517    ) -> Result<(), (ErrorCode, &'static mut StmF303Page)> {
518        if page_number > 127 {
519            return Err((ErrorCode::INVAL, buffer));
520        }
521
522        if self.is_locked() {
523            self.unlock();
524        }
525
526        self.enable();
527        self.state.set(FlashState::Write);
528
529        // Choose programming mode.
530        self.registers.cr.modify(Control::PG::SET);
531
532        self.buffer.replace(buffer);
533        self.page_number.set(page_number);
534        self.program_halfword();
535
536        Ok(())
537    }
538
539    pub fn read_page(
540        &self,
541        page_number: usize,
542        buffer: &'static mut StmF303Page,
543    ) -> Result<(), (ErrorCode, &'static mut StmF303Page)> {
544        if page_number > 127 {
545            return Err((ErrorCode::INVAL, buffer));
546        }
547
548        let mut byte: *const u8 = (PAGE_START + page_number * PAGE_SIZE) as *const u8;
549        unsafe {
550            for i in 0..buffer.len() {
551                buffer[i] = *byte;
552                byte = byte.offset(1);
553            }
554        }
555
556        self.buffer.replace(buffer);
557        self.state.set(FlashState::Read);
558        self.deferred_call.set();
559
560        Ok(())
561    }
562
563    /// Allows programming the 8 option bytes:
564    /// 0: RDP, 1: USER, 2: DATA0, 3:DATA1, 4. WRP0, 5: WRP1, 6.WRP2, 7. WRP3
565    pub fn write_option(&self, byte_number: usize, value: u8) -> Result<(), ErrorCode> {
566        if byte_number > 7 {
567            return Err(ErrorCode::INVAL);
568        }
569
570        if self.is_locked() {
571            self.unlock();
572        }
573
574        self.unlock_option();
575        self.enable();
576        self.state.set(FlashState::WriteOption);
577
578        // Choose option byte programming mode.
579        self.registers.cr.modify(Control::OPTPG::SET);
580
581        let address = OPT_START + byte_number * 2;
582        let location = unsafe { &*(address as *const VolatileCell<u16>) };
583        let halfword: u16 = value as u16;
584        location.set(halfword);
585
586        Ok(())
587    }
588
589    pub fn erase_option(&self) -> Result<(), ErrorCode> {
590        if self.is_locked() {
591            self.unlock();
592        }
593
594        self.unlock_option();
595        self.enable();
596        self.state.set(FlashState::EraseOption);
597
598        // Choose option byte erase mode.
599        self.registers.cr.modify(Control::OPTER::SET);
600        self.registers.cr.modify(Control::STRT::SET);
601
602        Ok(())
603    }
604}
605
606impl DeferredCallClient for Flash {
607    fn register(&'static self) {
608        self.deferred_call.register(self);
609    }
610
611    fn handle_deferred_call(&self) {
612        self.handle_interrupt();
613    }
614}
615
616impl<C: hil::flash::Client<Self>> hil::flash::HasClient<'static, C> for Flash {
617    fn set_client(&self, client: &'static C) {
618        self.client.set(client);
619    }
620}
621
622impl hil::flash::Flash for Flash {
623    type Page = StmF303Page;
624
625    fn read_page(
626        &self,
627        page_number: usize,
628        buf: &'static mut Self::Page,
629    ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
630        self.read_page(page_number, buf)
631    }
632
633    fn write_page(
634        &self,
635        page_number: usize,
636        buf: &'static mut Self::Page,
637    ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
638        self.write_page(page_number, buf)
639    }
640
641    fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> {
642        self.erase_page(page_number)
643    }
644}