atsam4_hal/
static_memory_controller.rs

1#![allow(clippy::upper_case_acronyms)]
2#![cfg(any(feature = "atsam4_c", feature = "atsam4e_e"))]
3
4use {
5    crate::clock::{Enabled, SmcClock},
6    crate::gpio::*,
7    crate::pac::{smc, SMC},
8    core::marker::PhantomData,
9    paste::paste,
10};
11
12// Chip Select Mode
13pub struct Uninitialized;
14pub struct Configured;
15
16#[derive(Copy, Clone, defmt::Format)]
17pub enum WaitMode {
18    Frozen,
19    Ready,
20}
21
22#[derive(Copy, Clone, defmt::Format)]
23pub enum PageSize {
24    FourBytes,
25    EightBytes,
26    SixteenBytes,
27    ThirtyTwoBytes,
28}
29
30#[derive(Copy, Clone, defmt::Format)]
31pub enum AccessMode {
32    ReadOnly,
33    WriteOnly,
34    ReadWrite,
35}
36
37pub struct ChipSelectConfiguration {
38    // 27.16 in SAM4E datasheet for details.
39
40    // Setup parameters
41    pub nwe_setup_length: u8,
42    pub ncs_write_setup_length: u8,
43    pub nrd_setup_length: u8,
44    pub ncs_read_setup_length: u8,
45
46    // Pulse parameters
47    pub nwe_pulse_length: u8,
48    pub ncs_write_pulse_length: u8,
49    pub nrd_pulse_length: u8,
50    pub ncs_read_pulse_length: u8,
51
52    pub nwe_total_cycle_length: u16,
53    pub nrd_total_cycle_length: u16,
54
55    pub access_mode: AccessMode,
56
57    pub wait_mode: Option<WaitMode>, // If some(), wait mode is as specified, otherwise disabled.
58
59    pub data_float_time: u8,
60
61    pub tdf_optimization: bool,
62    pub page_size: Option<PageSize>, // If some(), page mode is enabled with the given size.
63}
64
65macro_rules! chip_select {
66    (
67        $ChipSelectType:ident,
68        $cs:expr
69    ) => {
70        pub struct $ChipSelectType<MODE> {
71            _mode: PhantomData<MODE>,
72        }
73
74        paste! {
75            impl<MODE> $ChipSelectType<MODE> {
76                pub(crate) fn setup(&mut self) -> &smc::[<SETUP $cs>] {
77                    unsafe { &(*SMC::ptr()).[<setup $cs>] }
78                }
79
80                pub(crate) fn pulse(&mut self) -> &smc::[<PULSE $cs>] {
81                    unsafe { &(*SMC::ptr()).[<pulse $cs>] }
82                }
83
84                pub(crate) fn cycle(&mut self) -> &smc::[<CYCLE $cs>] {
85                    unsafe { &(*SMC::ptr()).[<cycle $cs>] }
86                }
87
88                pub(crate) fn mode(&mut self) -> &smc::[<MODE $cs>] {
89                    unsafe { &(*SMC::ptr()).[<mode $cs>] }
90                }
91
92                pub fn into_configured_state(mut self, config: &ChipSelectConfiguration) -> $ChipSelectType<Configured> {
93                    self.setup().write(|w| unsafe {
94                        w.nwe_setup().bits(config.nwe_setup_length).
95                          ncs_wr_setup().bits(config.ncs_write_setup_length).
96                          nrd_setup().bits(config.nrd_setup_length).
97                          ncs_rd_setup().bits(config.ncs_read_setup_length)
98                    });
99
100                    self.pulse().write(|w| unsafe {
101                        w.nwe_pulse().bits(config.nwe_pulse_length).
102                          ncs_wr_pulse().bits(config.ncs_write_pulse_length).
103                          nrd_pulse().bits(config.nrd_pulse_length).
104                          ncs_rd_pulse().bits(config.ncs_read_pulse_length)
105                    });
106
107                    self.cycle().write(|w| unsafe {
108                        w.nwe_cycle().bits(config.nwe_total_cycle_length).
109                          nrd_cycle().bits(config.nrd_total_cycle_length)
110                    });
111
112                    // WARNING: Mode register *must* be writen after the above registers in order to
113                    // 'validate' the new configuration.    See 27.11.3.1 in datasheet.
114                    self.mode().write(|w| unsafe {
115                        match config.access_mode {
116                            AccessMode::ReadOnly => w.read_mode().set_bit(),
117                            AccessMode::WriteOnly => w.write_mode().set_bit(),
118                            AccessMode::ReadWrite => w.read_mode().set_bit().write_mode().set_bit(),
119                        };
120
121                        if let Some(wait_mode) = config.wait_mode {
122                            let mode = match wait_mode {
123                                WaitMode::Frozen => 2,
124                                WaitMode::Ready => 3,
125                            };
126                            w.exnw_mode().bits(mode);
127                        }
128                        else {
129                            w.exnw_mode().bits(0);
130                        }
131
132                        w.tdf_cycles().bits(config.data_float_time);
133
134                        if (config.tdf_optimization) {
135                            w.tdf_mode().set_bit();
136                        }
137                        else {
138                            w.tdf_mode().clear_bit();
139                        }
140
141                        if let Some(page_size) = config.page_size {
142                            let value = match page_size {
143                                PageSize::FourBytes => 0,
144                                PageSize::EightBytes => 1,
145                                PageSize::SixteenBytes => 2,
146                                PageSize::ThirtyTwoBytes => 3,
147                            };
148
149                            w.pmen().set_bit().ps().bits(value);
150                        }
151                        else {
152                            w.pmen().clear_bit().ps().bits(0);
153                        }
154
155                        w
156                    });
157
158                    $ChipSelectType { _mode: PhantomData }
159                }
160            }
161        }
162    }
163}
164
165chip_select!(ChipSelect0, 0);
166chip_select!(ChipSelect1, 1);
167chip_select!(ChipSelect2, 2);
168chip_select!(ChipSelect3, 3);
169
170pub struct Smc {
171    pub chip_select0: ChipSelect0<Uninitialized>,
172    pub chip_select1: ChipSelect1<Uninitialized>,
173    pub chip_select2: ChipSelect2<Uninitialized>,
174    pub chip_select3: ChipSelect3<Uninitialized>,
175}
176
177pub enum NCS1 {
178    C15(Pc15<PfA>),
179
180    #[cfg(feature = "atsam4e")]
181    D18(Pd18<PfA>),
182}
183
184pub enum NCS3 {
185    C12(Pc12<PfA>),
186
187    #[cfg(feature = "atsam4e")]
188    D19(Pd19<PfA>),
189}
190
191type DataLines = (
192    Pc0<PfA>,
193    Pc1<PfA>,
194    Pc2<PfA>,
195    Pc3<PfA>,
196    Pc4<PfA>,
197    Pc5<PfA>,
198    Pc6<PfA>,
199    Pc7<PfA>,
200);
201
202type AddressLines = (
203    Pc18<PfA>,
204    Pc19<PfA>,
205    Pc20<PfA>,
206    Pc21<PfA>,
207    Pc22<PfA>,
208    Pc23<PfA>,
209    Pc24<PfA>,
210    Pc25<PfA>,
211    Pc26<PfA>,
212    Pc27<PfA>,
213    Pc28<PfA>,
214    Pc29<PfA>,
215    Pc30<PfA>,
216    Pc31<PfA>,
217    Pa18<PfC>,
218    Pa19<PfC>,
219    Pa20<PfC>,
220    Pa0<PfC>,
221    Pa1<PfC>,
222    Pa23<PfC>,
223    Pa24<PfC>,
224    Pc16<PfA>,
225    Pc17<PfA>,
226    Pa25<PfC>,
227);
228
229impl Smc {
230    pub fn new(
231        _clock: SmcClock<Enabled>,
232
233        _ncs1: NCS1,
234        _ncs3: NCS3,
235
236        _nrd: Pc11<PfA>,
237        _nwe: Pc8<PfA>,
238
239        _data_lines: DataLines,
240        _address_lines: AddressLines,
241    ) -> Self {
242        Smc {
243            chip_select0: ChipSelect0::<Uninitialized> { _mode: PhantomData },
244            chip_select1: ChipSelect1::<Uninitialized> { _mode: PhantomData },
245            chip_select2: ChipSelect2::<Uninitialized> { _mode: PhantomData },
246            chip_select3: ChipSelect3::<Uninitialized> { _mode: PhantomData },
247        }
248    }
249
250    pub fn base_address(&self, chip_select: u8) -> usize {
251        match chip_select {
252            0 => 0x6000_0000,
253            1 => 0x6100_0000,
254            2 => 0x6200_0000,
255            3 => 0x6300_0000,
256            _ => panic!("Unrecognized chip select provided: {}", chip_select),
257        }
258    }
259}