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
12pub 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 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 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>, pub data_float_time: u8,
60
61 pub tdf_optimization: bool,
62 pub page_size: Option<PageSize>, }
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 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}