Skip to main content

ra_hal/clock/
ra4m1.rs

1//! RA4M1 specific clock configuration.
2
3use fugit::MegahertzU32;
4
5use crate::clock::{CLOCK_STATUS, ClockConfig, ClockStatus, HocoFrequency, SystemClockSource};
6use crate::pac::{
7    self,
8    system::vals::{Cksel, Fck, Hcfrq1, Hcstp, Ick, Opcm, Pcka, Pckb, Pckc, Pckd, Sodrv},
9};
10use crate::write_protect::ProtectedPeripheral as _;
11
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13#[derive(Debug, Clone)]
14pub enum UsbClockSource {
15    Pll,
16    Hoco,
17}
18
19/// PLL input source.
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21#[derive(Debug, Clone)]
22pub enum PllInput {
23    /// Main Clock Oscillator
24    Mosc,
25}
26
27/// PLL frequency divider. § 8.6.3, § 8.6
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29#[allow(missing_docs)]
30#[derive(Debug, Clone)]
31pub enum PllOutDiv {
32    Div2,
33    Div4,
34}
35
36/// PLL frequency multiplier. § 8.6.3, § 8.6
37#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38#[allow(missing_docs)]
39#[derive(Debug, Clone)]
40#[repr(u32)]
41pub enum PllOutMul {
42    Mul8,
43    Mul9,
44    Mul10,
45    Mul11,
46    Mul12,
47    Mul13,
48    Mul14,
49    Mul15,
50    Mul16,
51    Mul17,
52    Mul18,
53    Mul19,
54    Mul20,
55    Mul21,
56    Mul22,
57    Mul23,
58    Mul24,
59    Mul25,
60    Mul26,
61    Mul27,
62    Mul28,
63    Mul29,
64    Mul30,
65    Mul31,
66}
67
68impl Default for ClockConfig {
69    /// Config assumes EK-RA4M1.
70    fn default() -> Self {
71        Self {
72            system: SystemClockSource::Hoco,
73            hoco: HocoFrequency::_48mhz,
74            mosc: None,
75            sosc: false,
76            pll: None,
77            usb: Some(UsbClockSource::Hoco),
78        }
79    }
80}
81
82pub(crate) fn init(config: ClockConfig) -> Result<(), ()> {
83    let system = pac::SYSTEM;
84
85    #[cfg(feature = "diag")]
86    {
87        use crate::ResetCause;
88
89        let reset_status_0 = system.rstsr0().read();
90        let reset_status_1 = system.rstsr1().read();
91
92        let reset_cause: ResetCause;
93        if reset_status_0.porf() {
94            reset_cause = ResetCause::PowerOn;
95        } else if reset_status_0.lvd0rf() || reset_status_0.lvd1rf() || reset_status_0.lvd2rf() {
96            reset_cause = ResetCause::LowVoltage;
97        } else if reset_status_1.wdtrf() || reset_status_1.iwdtrf() {
98            reset_cause = ResetCause::Watchdog;
99        } else if reset_status_1.rperf()
100            || reset_status_1.reerf()
101            || reset_status_1.bussrf()
102            || reset_status_1.busmrf()
103        {
104            reset_cause = ResetCause::HadwareError;
105        } else if reset_status_1.sperf() {
106            reset_cause = ResetCause::StackPointer;
107        } else if reset_status_1.swrf() {
108            reset_cause = ResetCause::SoftwareReset;
109        } else {
110            reset_cause = ResetCause::Unknown;
111        }
112
113        debug!("Reset reason: {}", reset_cause);
114    }
115
116    // #[cfg(feature = "strict-assert")]
117    // let fmifrt_base = pac::FMIFRT_BASE;
118    // Sanity check.  The manual states that this should be fixed.
119    // #[cfg(feature = "strict-assert")]
120    // assert_eq!(
121    //     pac::fmifrt_base::vals::ExpectedBase::RA4M1.to_bits(),
122    //     fmifrt_base.base().read().base()
123    // );
124
125    trace!(
126        "HOCO: wait={}, status={}",
127        system.hocowtcr().read(),
128        system.hococr().read()
129    );
130
131    system.protected_write(|| {
132        // Writing to the HOCOCR2 is prohibited when the HOCOCR.HCSTP bit is 0 (the HOCO operates).
133        let should_configure = match system.hococr().read().hcstp() {
134            Hcstp::Start => {
135                let frq = system.hococr2().read().hcfrqw();
136                let should_configure = frq != config.hoco.into();
137                if should_configure {
138                    system.hococr().write(|w| w.set_hcstp(Hcstp::Stop));
139                }
140                should_configure
141            }
142            Hcstp::Stop => true,
143        };
144
145        if should_configure {
146            system.hococr2().write(|r| r.set_hcfrqw(config.hoco.into()));
147            system.hococr().write(|w| w.set_hcstp(Hcstp::Start));
148        }
149
150        if config.sosc {
151            system.somcr().write(|r| r.set_sodrv(Sodrv::_00));
152            system.sosccr().write(|r| r.set_sostp(false));
153            // TODO: Set oscillator stabilization time.
154            while system.sosccr().read().sostp() {}
155        }
156
157        let hoco_freq = system.hococr2().read().hcfrqw();
158
159        // High speed mode needed for ICLK > 12 MHz.  Currently there are no features to select
160        // ICLK <= 12 MHz so just enable high speed mode unconditionally.
161        // Table 48.18
162        trace!("Setting high speed mode on");
163        system.opccr().write(|w| w.set_opcm(Opcm::HighSpeed));
164
165        while system.opccr().read().opcmtsf() {}
166
167        // Wait states needed for ICLK > 32 MHz
168        if hoco_freq == Hcfrq1::_48mhz || hoco_freq == Hcfrq1::_64mhz {
169            trace!("Setting SYSTEM_MEMWAIT to 1");
170            system.memwait().write(|w| w.set_memwait(true));
171        }
172
173        // Use HOCO as clock source
174        system.sckscr().write(|w| w.set_cksel(Cksel::Hoco));
175
176        #[cfg(feature = "cache")]
177        {
178            let fcache = pac::FCACHE;
179            fcache.fcacheiv().write(|r| r.set_fcacheiv(true));
180
181            while fcache.fcacheiv().read().fcacheiv() {
182                asm::nop();
183            }
184
185            fcache.fcachee().write(|r| r.set_fcacheen(true));
186
187            info!("SYSTEM: fcache enabled");
188        }
189        #[cfg(not(feature = "cache"))]
190        {
191            let fcache = pac::FCACHE;
192            fcache.fcacheiv().write(|r| r.set_fcacheiv(true));
193            fcache.fcachee().write(|r| r.set_fcacheen(false));
194            trace!("SYSTEM: fcache disabled");
195        }
196
197        // Max frequencies Table 8.2, p130
198        // ICLK = 48 MHz
199        // FCLK = 32 MHz
200        // PCKLA = 48 MHz
201        // PCLKB = 32 MHz
202        // PCLKC = 64 MHz
203        // PCLKD = 64 MHz
204        match hoco_freq {
205            Hcfrq1::_32mhz => system.sckdivcr().modify(|w| {
206                // 32 MHz
207                w.set_ick(Ick::Div1);
208                // 32 MHz
209                w.set_fck(Fck::Div1);
210                // 32 MHz
211                w.set_pcka(Pcka::Div1);
212                // 32 MHz
213                w.set_pckb(Pckb::Div1);
214                // 32 MHz
215                w.set_pckc(Pckc::Div1);
216                // 32 MHz
217                w.set_pckd(Pckd::Div1);
218            }),
219            Hcfrq1::_48mhz => system.sckdivcr().modify(|w| {
220                // 48 MHz
221                w.set_ick(Ick::Div1);
222                // 24 MHz
223                w.set_fck(Fck::Div2);
224                // 48 MHz
225                w.set_pcka(Pcka::Div1);
226                // 24 MHz
227                w.set_pckb(Pckb::Div2);
228                // 48 MHz
229                w.set_pckc(Pckc::Div1);
230                // 48 MHz
231                w.set_pckd(Pckd::Div1);
232            }),
233            // Faster peripheral clocks, slower CPU clock
234            Hcfrq1::_64mhz => system.sckdivcr().modify(|w| {
235                // 32 MHz
236                w.set_ick(Ick::Div2);
237                // 32 MHz
238                w.set_fck(Fck::Div2);
239                // 32 MHz
240                w.set_pcka(Pcka::Div2);
241                // 32 MHz
242                w.set_pckb(Pckb::Div2);
243                // 64 MHz
244                w.set_pckc(Pckc::Div1);
245                // 64 MHz
246                w.set_pckd(Pckd::Div1);
247            }),
248            _ => unimplemented!(),
249        }
250
251        if let Some(UsbClockSource::Hoco) = config.usb {
252            // Also use HOCO as USB clock source.
253            system.usbckcr().write(|w| w.set_usbclksel(true));
254        }
255    });
256
257    {
258        let system = pac::SYSTEM;
259
260        let hoco = system.hococr2().read().hcfrqw();
261        let hoco = match hoco {
262            Hcfrq1::_24mhz => MegahertzU32::from_raw(24),
263            Hcfrq1::_32mhz => MegahertzU32::from_raw(32),
264            Hcfrq1::_48mhz => MegahertzU32::from_raw(48),
265            Hcfrq1::_64mhz => MegahertzU32::from_raw(64),
266            _ => unimplemented!(),
267        }
268        .convert();
269
270        let prescaler = system.sckdivcr().read();
271
272        let system = match prescaler.ick() {
273            Ick::Div1 => hoco,
274            Ick::Div2 => hoco / 2,
275            Ick::Div4 => hoco / 4,
276            Ick::Div8 => hoco / 8,
277            Ick::Div16 => hoco / 16,
278            Ick::Div32 => hoco / 32,
279            Ick::Div64 => hoco / 64,
280            Ick::_RESERVED_7 => unimplemented!("Invalid sckdivcr.ick"),
281        };
282
283        let flash = match prescaler.fck() {
284            Fck::Div1 => hoco,
285            Fck::Div2 => hoco / 2,
286            Fck::Div4 => hoco / 4,
287            Fck::Div8 => hoco / 8,
288            Fck::Div16 => hoco / 16,
289            Fck::Div32 => hoco / 32,
290            Fck::Div64 => hoco / 64,
291            Fck::_RESERVED_7 => unimplemented!("Invalid sckdivcr.fck"),
292        };
293
294        let peripheral_a = match prescaler.pcka() {
295            Pcka::Div1 => hoco,
296            Pcka::Div2 => hoco / 2,
297            Pcka::Div4 => hoco / 4,
298            Pcka::Div8 => hoco / 8,
299            Pcka::Div16 => hoco / 16,
300            Pcka::Div32 => hoco / 32,
301            Pcka::Div64 => hoco / 64,
302            Pcka::_RESERVED_7 => unimplemented!("Invalid sckdivcr.pcka"),
303        };
304
305        let peripheral_b = match prescaler.pckb() {
306            Pckb::Div1 => hoco,
307            Pckb::Div2 => hoco / 2,
308            Pckb::Div4 => hoco / 4,
309            Pckb::Div8 => hoco / 8,
310            Pckb::Div16 => hoco / 16,
311            Pckb::Div32 => hoco / 32,
312            Pckb::Div64 => hoco / 64,
313            Pckb::_RESERVED_7 => unimplemented!("Invalid sckdivcr.pckb"),
314        };
315
316        let peripheral_c = match prescaler.pckc() {
317            Pckc::Div1 => hoco,
318            Pckc::Div2 => hoco / 2,
319            Pckc::Div4 => hoco / 4,
320            Pckc::Div8 => hoco / 8,
321            Pckc::Div16 => hoco / 16,
322            Pckc::Div32 => hoco / 32,
323            Pckc::Div64 => hoco / 64,
324            Pckc::_RESERVED_7 => unimplemented!("Invalid sckdivcr.pckc"),
325        };
326
327        let peripheral_d = match prescaler.pckd() {
328            Pckd::Div1 => hoco,
329            Pckd::Div2 => hoco / 2,
330            Pckd::Div4 => hoco / 4,
331            Pckd::Div8 => hoco / 8,
332            Pckd::Div16 => hoco / 16,
333            Pckd::Div32 => hoco / 32,
334            Pckd::Div64 => hoco / 64,
335            Pckd::_RESERVED_7 => unimplemented!("Invalid sckdivcr.pckd"),
336        };
337
338        // TODO: Calculate PLL status
339        let pll = None;
340
341        let usb = match config.usb {
342            Some(UsbClockSource::Hoco) => Some(hoco),
343            Some(UsbClockSource::Pll) => pll,
344            None => None,
345        };
346
347        CLOCK_STATUS
348            .init(ClockStatus {
349                hoco,
350                system,
351                flash,
352                peripheral_a,
353                peripheral_b,
354                peripheral_c,
355                peripheral_d,
356                master: hoco,
357                pll,
358                mosc: config.mosc,
359                sosc: config.sosc,
360                usb,
361            })
362            .or(Err(()))
363    }
364}