tm4c129x_hal/
sysctl.rs

1//! # System Control
2//!
3//! The SYSCTL peripheral controls clocks and power.
4//!
5//! The TM4C129x can be clocked from the Main Oscillator or the PLL, through a
6//! divider. The Main Oscillator can be either the internal 16 MHz precision
7//! oscillator, a 4 MHz derivation of the same, or an external crystal.
8//!
9//! SYSCTL includes the following registers:
10//!
11//! * Device ID (class, major, minor, family, package, temperature range, )
12//! * Brown-out reset control
13//! * Brown-out/PLL interrupt control
14//! * Reset cause
15//! * Run-time clock configuration
16//! * GPIO high-performance bus control
17//! * System Properties
18//! * Registers to indicate whether peripherals are present
19//! * Registers to reset peripherals
20//! * Registers to enable/disable clocking of peripherals
21//!
22//! See the LM4F120 datasheet, page 228 for a full list.
23
24pub use tm4c_hal::sysctl::*;
25
26use crate::{
27    bb,
28    time::{Hertz, U32Ext},
29};
30use cortex_m::asm::nop;
31
32/// Constrained SYSCTL peripheral.
33pub struct Sysctl {
34    /// Power control methods will require `&mut this.power_control` to
35    /// prevent them from running concurrently.
36    pub power_control: PowerControl,
37    /// Clock configuration will consume this and give you `Clocks`.
38    pub clock_setup: ClockSetup,
39}
40
41/// Used to gate access to the run-time power control features of the chip.
42#[non_exhaustive]
43pub struct PowerControl {}
44
45/// Used to configure the clock generators.
46#[non_exhaustive]
47pub struct ClockSetup {
48    /// The system oscillator configuration
49    pub oscillator: Oscillator,
50}
51
52/// Selects the system oscillator source
53#[derive(Clone, Copy)]
54pub enum Oscillator {
55    /// Use the main oscillator (with the given crystal), into the PLL or a
56    /// clock divider
57    Main(CrystalFrequency, SystemClock),
58    /// Use the 16 MHz precision internal oscillator, into the PLL or a clock
59    /// divider
60    PrecisionInternal(SystemClock),
61    /// Use the 33 kHz internal oscillator, divided by the given value.
62    LowFrequencyInternal(Divider),
63}
64
65/// Selects the source for the system clock
66#[derive(Clone, Copy)]
67pub enum SystemClock {
68    /// Clock the system direct from the system oscillator
69    UseOscillator(Divider),
70    /// Clock the system from the PLL (which is driven by the system
71    /// oscillator), divided down from 400MHz to the given frequency.
72    UsePll(PllOutputFrequency),
73}
74
75/// Selects which crystal is fitted to the XOSC pins.
76#[derive(Clone, Copy)]
77pub enum CrystalFrequency {
78    /// 4 MHz
79    _4mhz,
80    /// 4.096 MHz
81    _4_09mhz,
82    /// 4.9152 MHz
83    _4_91mhz,
84    /// 5 MHz
85    _5mhz,
86    /// 5.12 MHz
87    _5_12mhz,
88    /// 6 MHz
89    _6mhz,
90    /// 6.144 MHz
91    _6_14mhz,
92    /// 7.3728 MHz
93    _7_37mhz,
94    /// 8 MHz
95    _8mhz,
96    /// 8.192 MHz
97    _8_19mhz,
98    /// 10 MHz
99    _10mhz,
100    /// 12 MHz
101    _12mhz,
102    /// 12.288 MHz
103    _12_2mhz,
104    /// 13.56 MHz
105    _13_5mhz,
106    /// 14.31818 MHz
107    _14_3mhz,
108    /// 16 MHz
109    _16mhz,
110    /// 16.384 MHz
111    _16_3mhz,
112    /// 18.0 MHz (USB)
113    _18mhz,
114    /// 20.0 MHz (USB)
115    _20mhz,
116    /// 24.0 MHz (USB)
117    _24mhz,
118    /// 25.0 MHz (USB)
119    _25mhz,
120}
121
122impl Into<Hertz> for CrystalFrequency {
123    fn into(self) -> Hertz {
124        Hertz(match self {
125            CrystalFrequency::_4mhz => 4_000_000,
126            CrystalFrequency::_4_09mhz => 4_090_000,
127            CrystalFrequency::_4_91mhz => 4_910_000,
128            CrystalFrequency::_5mhz => 5_000_000,
129            CrystalFrequency::_5_12mhz => 5_120_000,
130            CrystalFrequency::_6mhz => 6_000_000,
131            CrystalFrequency::_6_14mhz => 6_140_000,
132            CrystalFrequency::_7_37mhz => 7_370_000,
133            CrystalFrequency::_8mhz => 8_000_000,
134            CrystalFrequency::_8_19mhz => 8_190_000,
135            CrystalFrequency::_10mhz => 10_000_000,
136            CrystalFrequency::_12mhz => 12_000_000,
137            CrystalFrequency::_12_2mhz => 12_200_000,
138            CrystalFrequency::_13_5mhz => 13_500_000,
139            CrystalFrequency::_14_3mhz => 14_300_000,
140            CrystalFrequency::_16mhz => 16_000_000,
141            CrystalFrequency::_16_3mhz => 16_300_000,
142            CrystalFrequency::_18mhz => 18_000_000,
143            CrystalFrequency::_20mhz => 20_000_000,
144            CrystalFrequency::_24mhz => 24_000_000,
145            CrystalFrequency::_25mhz => 25_000_000,
146        })
147    }
148}
149
150/// Selects what to divide the PLL's 400MHz down to.
151#[derive(Clone, Copy)]
152pub enum PllOutputFrequency {
153    /// 120 MHz
154    _120mhz,
155    /// 60 MHz
156    _60mhz,
157    /// 48 MHz
158    _48mhz,
159    /// 30 MHz
160    _30mhz,
161    /// 24 MHz
162    _24mhz,
163    /// 12 MHz
164    _12mhz,
165    /// 6 MHz
166    _6mhz,
167}
168
169impl Into<Hertz> for PllOutputFrequency {
170    fn into(self) -> Hertz {
171        Hertz(match self {
172            PllOutputFrequency::_120mhz => 120_000_000,
173            PllOutputFrequency::_60mhz => 60_000_000,
174            PllOutputFrequency::_48mhz => 48_000_000,
175            PllOutputFrequency::_30mhz => 30_000_000,
176            PllOutputFrequency::_24mhz => 24_000_000,
177            PllOutputFrequency::_12mhz => 12_000_000,
178            PllOutputFrequency::_6mhz => 6_000_000,
179        })
180    }
181}
182
183/// Selects how much to divide the system oscillator down.
184#[derive(Clone, Copy)]
185pub enum Divider {
186    /// Divide by 1
187    _1 = 1,
188    /// Divide by 2
189    _2 = 2,
190    /// Divide by 3
191    _3 = 3,
192    /// Divide by 4
193    _4 = 4,
194    /// Divide by 5
195    _5 = 5,
196    /// Divide by 6
197    _6 = 6,
198    /// Divide by 7
199    _7 = 7,
200    /// Divide by 8
201    _8 = 8,
202    /// Divide by 9
203    _9 = 9,
204    /// Divide by 10
205    _10 = 10,
206    /// Divide by 11
207    _11 = 11,
208    /// Divide by 12
209    _12 = 12,
210    /// Divide by 13
211    _13 = 13,
212    /// Divide by 14
213    _14 = 14,
214    /// Divide by 15
215    _15 = 15,
216    /// Divide by 16
217    _16 = 16,
218}
219
220/// List of peripherals that can be enabled or disabled
221#[derive(Copy, Clone)]
222pub enum Domain {
223    /// Watchdog 1
224    Watchdog1,
225    /// Watchdog 0
226    Watchdog0,
227    /// 32/16-bit Timer 5
228    Timer5,
229    /// 32/16-bit Timer 4
230    Timer4,
231    /// 32/16-bit Timer 3
232    Timer3,
233    /// 32/16-bit Timer 2
234    Timer2,
235    /// 32/16-bit Timer 1
236    Timer1,
237    /// 32/16-bit Timer 0
238    Timer0,
239    /// Gpio Q
240    GpioQ,
241    /// Gpio P
242    GpioP,
243    /// Gpio N
244    GpioN,
245    /// Gpio M
246    GpioM,
247    /// Gpio L
248    GpioL,
249    /// Gpio K
250    GpioK,
251    /// Gpio J
252    GpioJ,
253    /// Gpio H
254    GpioH,
255    /// Gpio G
256    GpioG,
257    /// Gpio F
258    GpioF,
259    /// GPIO E
260    GpioE,
261    /// GPIO D
262    GpioD,
263    /// GPIO C
264    GpioC,
265    /// GPIO B
266    GpioB,
267    /// GPIO A
268    GpioA,
269    /// µDMA
270    MicroDma,
271    /// Hibernation
272    Hibernation,
273    /// UART 7
274    Uart7,
275    /// UART 6
276    Uart6,
277    /// UART 5
278    Uart5,
279    /// UART 4
280    Uart4,
281    /// UART 3
282    Uart3,
283    /// UART 2
284    Uart2,
285    /// UART 1
286    Uart1,
287    /// UART 0
288    Uart0,
289    /// SSI 3
290    Ssi3,
291    /// SSI 2
292    Ssi2,
293    /// SSI 1
294    Ssi1,
295    /// SSI 0
296    Ssi0,
297    /// I2C 3
298    I2c3,
299    /// I2C 2
300    I2c2,
301    /// I2C 1
302    I2c1,
303    /// I2C 0
304    I2c0,
305    /// USB
306    Usb,
307    /// CAN
308    Can,
309    /// ADC 1
310    Adc1,
311    /// ADC 0
312    Adc0,
313    /// Analog Comparator
314    AnalogComparator,
315    /// EEPROM
316    Eeprom,
317    /// PWM0
318    Pwm0,
319    /// PWM1
320    Pwm1,
321    /// EMAC0
322    Emac0,
323    /// EPHY0
324    Ephy0,
325}
326
327/// Reset a peripheral
328pub fn reset(_lock: &PowerControl, pd: Domain) {
329    // We use bit-banding to make an atomic write, so this is safe
330    let p = unsafe { &*tm4c129x::SYSCTL::ptr() };
331    match pd {
332        Domain::Watchdog1 => unsafe {
333            bb::toggle_bit(&p.srwd, 1);
334            bb::spin_bit(&p.prwd, 1);
335        },
336        Domain::Watchdog0 => unsafe {
337            bb::toggle_bit(&p.srwd, 0);
338            bb::spin_bit(&p.prwd, 0);
339        },
340        Domain::Timer5 => unsafe {
341            bb::toggle_bit(&p.srtimer, 5);
342            bb::spin_bit(&p.prtimer, 5);
343        },
344        Domain::Timer4 => unsafe {
345            bb::toggle_bit(&p.srtimer, 4);
346            bb::spin_bit(&p.prtimer, 4);
347        },
348        Domain::Timer3 => unsafe {
349            bb::toggle_bit(&p.srtimer, 3);
350            bb::spin_bit(&p.prtimer, 3);
351        },
352        Domain::Timer2 => unsafe {
353            bb::toggle_bit(&p.srtimer, 2);
354            bb::spin_bit(&p.prtimer, 2);
355        },
356        Domain::Timer1 => unsafe {
357            bb::toggle_bit(&p.srtimer, 1);
358            bb::spin_bit(&p.prtimer, 1);
359        },
360        Domain::Timer0 => unsafe {
361            bb::toggle_bit(&p.srtimer, 0);
362            bb::spin_bit(&p.prtimer, 0);
363        },
364        Domain::GpioQ => unsafe {
365            bb::toggle_bit(&p.srgpio, 14);
366            bb::spin_bit(&p.prgpio, 14);
367        },
368        Domain::GpioP => unsafe {
369            bb::toggle_bit(&p.srgpio, 13);
370            bb::spin_bit(&p.prgpio, 13);
371        },
372        Domain::GpioN => unsafe {
373            bb::toggle_bit(&p.srgpio, 12);
374            bb::spin_bit(&p.prgpio, 12);
375        },
376        Domain::GpioM => unsafe {
377            bb::toggle_bit(&p.srgpio, 11);
378            bb::spin_bit(&p.prgpio, 11);
379        },
380        Domain::GpioL => unsafe {
381            bb::toggle_bit(&p.srgpio, 10);
382            bb::spin_bit(&p.prgpio, 10);
383        },
384        Domain::GpioK => unsafe {
385            bb::toggle_bit(&p.srgpio, 9);
386            bb::spin_bit(&p.prgpio, 9);
387        },
388        Domain::GpioJ => unsafe {
389            bb::toggle_bit(&p.srgpio, 8);
390            bb::spin_bit(&p.prgpio, 8);
391        },
392        Domain::GpioH => unsafe {
393            bb::toggle_bit(&p.srgpio, 7);
394            bb::spin_bit(&p.prgpio, 7);
395        },
396        Domain::GpioG => unsafe {
397            bb::toggle_bit(&p.srgpio, 6);
398            bb::spin_bit(&p.prgpio, 6);
399        },
400        Domain::GpioF => unsafe {
401            bb::toggle_bit(&p.srgpio, 5);
402            bb::spin_bit(&p.prgpio, 5);
403        },
404        Domain::GpioE => unsafe {
405            bb::toggle_bit(&p.srgpio, 4);
406            bb::spin_bit(&p.prgpio, 4);
407        },
408        Domain::GpioD => unsafe {
409            bb::toggle_bit(&p.srgpio, 3);
410            bb::spin_bit(&p.prgpio, 3);
411        },
412        Domain::GpioC => unsafe {
413            bb::toggle_bit(&p.srgpio, 2);
414            bb::spin_bit(&p.prgpio, 2);
415        },
416        Domain::GpioB => unsafe {
417            bb::toggle_bit(&p.srgpio, 1);
418            bb::spin_bit(&p.prgpio, 1);
419        },
420        Domain::GpioA => unsafe {
421            bb::toggle_bit(&p.srgpio, 0);
422            bb::spin_bit(&p.prgpio, 0);
423        },
424        Domain::MicroDma => unsafe {
425            bb::toggle_bit(&p.srdma, 0);
426            bb::spin_bit(&p.prdma, 0);
427        },
428        Domain::Hibernation => unsafe {
429            bb::toggle_bit(&p.srhib, 0);
430            bb::spin_bit(&p.prhib, 0);
431        },
432        Domain::Uart7 => unsafe {
433            bb::toggle_bit(&p.sruart, 7);
434            bb::spin_bit(&p.pruart, 7);
435        },
436        Domain::Uart6 => unsafe {
437            bb::toggle_bit(&p.sruart, 6);
438            bb::spin_bit(&p.pruart, 6);
439        },
440        Domain::Uart5 => unsafe {
441            bb::toggle_bit(&p.sruart, 5);
442            bb::spin_bit(&p.pruart, 5);
443        },
444        Domain::Uart4 => unsafe {
445            bb::toggle_bit(&p.sruart, 4);
446            bb::spin_bit(&p.pruart, 4);
447        },
448        Domain::Uart3 => unsafe {
449            bb::toggle_bit(&p.sruart, 3);
450            bb::spin_bit(&p.pruart, 3);
451        },
452        Domain::Uart2 => unsafe {
453            bb::toggle_bit(&p.sruart, 2);
454            bb::spin_bit(&p.pruart, 2);
455        },
456        Domain::Uart1 => unsafe {
457            bb::toggle_bit(&p.sruart, 1);
458            bb::spin_bit(&p.pruart, 1);
459        },
460        Domain::Uart0 => unsafe {
461            bb::toggle_bit(&p.sruart, 0);
462            bb::spin_bit(&p.pruart, 0);
463        },
464        Domain::Ssi3 => unsafe {
465            bb::toggle_bit(&p.srssi, 3);
466            bb::spin_bit(&p.prssi, 3);
467        },
468        Domain::Ssi2 => unsafe {
469            bb::toggle_bit(&p.srssi, 2);
470            bb::spin_bit(&p.prssi, 2);
471        },
472        Domain::Ssi1 => unsafe {
473            bb::toggle_bit(&p.srssi, 1);
474            bb::spin_bit(&p.prssi, 1);
475        },
476        Domain::Ssi0 => unsafe {
477            bb::toggle_bit(&p.srssi, 0);
478            bb::spin_bit(&p.prssi, 0);
479        },
480        Domain::I2c3 => unsafe {
481            bb::toggle_bit(&p.sri2c, 3);
482            bb::spin_bit(&p.pri2c, 3);
483        },
484        Domain::I2c2 => unsafe {
485            bb::toggle_bit(&p.sri2c, 2);
486            bb::spin_bit(&p.pri2c, 2);
487        },
488        Domain::I2c1 => unsafe {
489            bb::toggle_bit(&p.sri2c, 1);
490            bb::spin_bit(&p.pri2c, 1);
491        },
492        Domain::I2c0 => unsafe {
493            bb::toggle_bit(&p.sri2c, 0);
494            bb::spin_bit(&p.pri2c, 0);
495        },
496        Domain::Usb => unsafe {
497            bb::toggle_bit(&p.srusb, 0);
498            bb::spin_bit(&p.prusb, 0);
499        },
500        Domain::Can => unsafe {
501            bb::toggle_bit(&p.srcan, 0);
502            bb::spin_bit(&p.prcan, 0);
503        },
504        Domain::Adc1 => unsafe {
505            bb::toggle_bit(&p.sradc, 1);
506            bb::spin_bit(&p.pradc, 1);
507        },
508        Domain::Adc0 => unsafe {
509            bb::toggle_bit(&p.sradc, 0);
510            bb::spin_bit(&p.pradc, 0);
511        },
512        Domain::AnalogComparator => unsafe {
513            bb::toggle_bit(&p.sracmp, 0);
514            bb::spin_bit(&p.pracmp, 0);
515        },
516        Domain::Eeprom => unsafe {
517            bb::toggle_bit(&p.sreeprom, 0);
518            bb::spin_bit(&p.preeprom, 0);
519        },
520        Domain::Pwm0 => unsafe {
521            bb::toggle_bit(&p.srpwm, 0);
522            bb::spin_bit(&p.prpwm, 0);
523        },
524        Domain::Pwm1 => unsafe {
525            bb::toggle_bit(&p.srpwm, 1);
526            bb::spin_bit(&p.prpwm, 1);
527        },
528        Domain::Emac0 => unsafe {
529            bb::toggle_bit(&p.sremac, 0);
530            bb::spin_bit(&p.premac, 0);
531        },
532        Domain::Ephy0 => unsafe {
533            bb::toggle_bit(&p.srephy, 0);
534            bb::spin_bit(&p.prephy, 0);
535        },
536    }
537}
538
539/// Activate or De-Activate clocks and power to the given peripheral in the
540/// given run mode.
541///
542/// We take a reference to PowerControl as a permission check. We don't need
543/// an &mut reference as we use atomic writes in the bit-banding area so it's
544/// interrupt safe.
545pub fn control_power(_lock: &PowerControl, pd: Domain, run_mode: RunMode, state: PowerState) {
546    let on = match state {
547        PowerState::On => true,
548        PowerState::Off => false,
549    };
550    match run_mode {
551        RunMode::Run => control_run_power(pd, on),
552        RunMode::Sleep => control_sleep_power(pd, on),
553        RunMode::DeepSleep => control_deep_sleep_power(pd, on),
554    }
555    // Section 5.2.6 - "There must be a delay of 3 system clocks after a
556    // peripheral module clock is enabled in the RCGC register before any
557    // module registers are accessed."
558    nop();
559    nop();
560    nop();
561}
562
563fn control_run_power(pd: Domain, on: bool) {
564    // We use bit-banding to make an atomic write, so this is safe
565    let p = unsafe { &*tm4c129x::SYSCTL::ptr() };
566    match pd {
567        Domain::Watchdog1 => unsafe { bb::change_bit(&p.rcgcwd, 1, on) },
568        Domain::Watchdog0 => unsafe { bb::change_bit(&p.rcgcwd, 0, on) },
569        Domain::Timer5 => unsafe { bb::change_bit(&p.rcgctimer, 5, on) },
570        Domain::Timer4 => unsafe { bb::change_bit(&p.rcgctimer, 4, on) },
571        Domain::Timer3 => unsafe { bb::change_bit(&p.rcgctimer, 3, on) },
572        Domain::Timer2 => unsafe { bb::change_bit(&p.rcgctimer, 2, on) },
573        Domain::Timer1 => unsafe { bb::change_bit(&p.rcgctimer, 1, on) },
574        Domain::Timer0 => unsafe { bb::change_bit(&p.rcgctimer, 0, on) },
575        Domain::GpioQ => unsafe { bb::change_bit(&p.rcgcgpio, 14, on) },
576        Domain::GpioP => unsafe { bb::change_bit(&p.rcgcgpio, 13, on) },
577        Domain::GpioN => unsafe { bb::change_bit(&p.rcgcgpio, 12, on) },
578        Domain::GpioM => unsafe { bb::change_bit(&p.rcgcgpio, 11, on) },
579        Domain::GpioL => unsafe { bb::change_bit(&p.rcgcgpio, 10, on) },
580        Domain::GpioK => unsafe { bb::change_bit(&p.rcgcgpio, 9, on) },
581        Domain::GpioJ => unsafe { bb::change_bit(&p.rcgcgpio, 8, on) },
582        Domain::GpioH => unsafe { bb::change_bit(&p.rcgcgpio, 7, on) },
583        Domain::GpioG => unsafe { bb::change_bit(&p.rcgcgpio, 6, on) },
584        Domain::GpioF => unsafe { bb::change_bit(&p.rcgcgpio, 5, on) },
585        Domain::GpioE => unsafe { bb::change_bit(&p.rcgcgpio, 4, on) },
586        Domain::GpioD => unsafe { bb::change_bit(&p.rcgcgpio, 3, on) },
587        Domain::GpioC => unsafe { bb::change_bit(&p.rcgcgpio, 2, on) },
588        Domain::GpioB => unsafe { bb::change_bit(&p.rcgcgpio, 1, on) },
589        Domain::GpioA => unsafe { bb::change_bit(&p.rcgcgpio, 0, on) },
590        Domain::MicroDma => unsafe { bb::change_bit(&p.rcgcdma, 0, on) },
591        Domain::Hibernation => unsafe { bb::change_bit(&p.rcgchib, 0, on) },
592        Domain::Uart7 => unsafe { bb::change_bit(&p.rcgcuart, 7, on) },
593        Domain::Uart6 => unsafe { bb::change_bit(&p.rcgcuart, 6, on) },
594        Domain::Uart5 => unsafe { bb::change_bit(&p.rcgcuart, 5, on) },
595        Domain::Uart4 => unsafe { bb::change_bit(&p.rcgcuart, 4, on) },
596        Domain::Uart3 => unsafe { bb::change_bit(&p.rcgcuart, 3, on) },
597        Domain::Uart2 => unsafe { bb::change_bit(&p.rcgcuart, 2, on) },
598        Domain::Uart1 => unsafe { bb::change_bit(&p.rcgcuart, 1, on) },
599        Domain::Uart0 => unsafe { bb::change_bit(&p.rcgcuart, 0, on) },
600        Domain::Ssi3 => unsafe { bb::change_bit(&p.rcgcssi, 3, on) },
601        Domain::Ssi2 => unsafe { bb::change_bit(&p.rcgcssi, 2, on) },
602        Domain::Ssi1 => unsafe { bb::change_bit(&p.rcgcssi, 1, on) },
603        Domain::Ssi0 => unsafe { bb::change_bit(&p.rcgcssi, 0, on) },
604        Domain::I2c3 => unsafe { bb::change_bit(&p.rcgci2c, 3, on) },
605        Domain::I2c2 => unsafe { bb::change_bit(&p.rcgci2c, 2, on) },
606        Domain::I2c1 => unsafe { bb::change_bit(&p.rcgci2c, 1, on) },
607        Domain::I2c0 => unsafe { bb::change_bit(&p.rcgci2c, 0, on) },
608        Domain::Usb => unsafe { bb::change_bit(&p.rcgcusb, 0, on) },
609        Domain::Can => unsafe { bb::change_bit(&p.rcgccan, 0, on) },
610        Domain::Adc1 => unsafe { bb::change_bit(&p.rcgcadc, 1, on) },
611        Domain::Adc0 => unsafe { bb::change_bit(&p.rcgcadc, 0, on) },
612        Domain::AnalogComparator => unsafe { bb::change_bit(&p.rcgcacmp, 0, on) },
613        Domain::Eeprom => unsafe { bb::change_bit(&p.rcgceeprom, 0, on) },
614        Domain::Pwm0 => unsafe { bb::change_bit(&p.rcgcpwm, 0, on) },
615        Domain::Pwm1 => unsafe { bb::change_bit(&p.rcgcpwm, 1, on) },
616        Domain::Emac0 => unsafe { bb::change_bit(&p.rcgcemac, 0, on) },
617        Domain::Ephy0 => unsafe { bb::change_bit(&p.rcgcephy, 0, on) },
618    }
619}
620
621fn control_sleep_power(pd: Domain, on: bool) {
622    // We use bit-banding to make an atomic write, so this is safe
623    let p = unsafe { &*tm4c129x::SYSCTL::ptr() };
624    match pd {
625        Domain::Watchdog1 => unsafe { bb::change_bit(&p.scgcwd, 1, on) },
626        Domain::Watchdog0 => unsafe { bb::change_bit(&p.scgcwd, 0, on) },
627        Domain::Timer5 => unsafe { bb::change_bit(&p.scgctimer, 5, on) },
628        Domain::Timer4 => unsafe { bb::change_bit(&p.scgctimer, 4, on) },
629        Domain::Timer3 => unsafe { bb::change_bit(&p.scgctimer, 3, on) },
630        Domain::Timer2 => unsafe { bb::change_bit(&p.scgctimer, 2, on) },
631        Domain::Timer1 => unsafe { bb::change_bit(&p.scgctimer, 1, on) },
632        Domain::Timer0 => unsafe { bb::change_bit(&p.scgctimer, 0, on) },
633        Domain::GpioQ => unsafe { bb::change_bit(&p.scgcgpio, 14, on) },
634        Domain::GpioP => unsafe { bb::change_bit(&p.scgcgpio, 13, on) },
635        Domain::GpioN => unsafe { bb::change_bit(&p.scgcgpio, 12, on) },
636        Domain::GpioM => unsafe { bb::change_bit(&p.scgcgpio, 11, on) },
637        Domain::GpioL => unsafe { bb::change_bit(&p.scgcgpio, 10, on) },
638        Domain::GpioK => unsafe { bb::change_bit(&p.scgcgpio, 9, on) },
639        Domain::GpioJ => unsafe { bb::change_bit(&p.scgcgpio, 8, on) },
640        Domain::GpioH => unsafe { bb::change_bit(&p.scgcgpio, 7, on) },
641        Domain::GpioG => unsafe { bb::change_bit(&p.scgcgpio, 6, on) },
642        Domain::GpioF => unsafe { bb::change_bit(&p.scgcgpio, 5, on) },
643        Domain::GpioE => unsafe { bb::change_bit(&p.scgcgpio, 4, on) },
644        Domain::GpioD => unsafe { bb::change_bit(&p.scgcgpio, 3, on) },
645        Domain::GpioC => unsafe { bb::change_bit(&p.scgcgpio, 2, on) },
646        Domain::GpioB => unsafe { bb::change_bit(&p.scgcgpio, 1, on) },
647        Domain::GpioA => unsafe { bb::change_bit(&p.scgcgpio, 0, on) },
648        Domain::MicroDma => unsafe { bb::change_bit(&p.scgcdma, 0, on) },
649        Domain::Hibernation => unsafe { bb::change_bit(&p.scgchib, 0, on) },
650        Domain::Uart7 => unsafe { bb::change_bit(&p.scgcuart, 7, on) },
651        Domain::Uart6 => unsafe { bb::change_bit(&p.scgcuart, 6, on) },
652        Domain::Uart5 => unsafe { bb::change_bit(&p.scgcuart, 5, on) },
653        Domain::Uart4 => unsafe { bb::change_bit(&p.scgcuart, 4, on) },
654        Domain::Uart3 => unsafe { bb::change_bit(&p.scgcuart, 3, on) },
655        Domain::Uart2 => unsafe { bb::change_bit(&p.scgcuart, 2, on) },
656        Domain::Uart1 => unsafe { bb::change_bit(&p.scgcuart, 1, on) },
657        Domain::Uart0 => unsafe { bb::change_bit(&p.scgcuart, 0, on) },
658        Domain::Ssi3 => unsafe { bb::change_bit(&p.scgcssi, 3, on) },
659        Domain::Ssi2 => unsafe { bb::change_bit(&p.scgcssi, 2, on) },
660        Domain::Ssi1 => unsafe { bb::change_bit(&p.scgcssi, 1, on) },
661        Domain::Ssi0 => unsafe { bb::change_bit(&p.scgcssi, 0, on) },
662        Domain::I2c3 => unsafe { bb::change_bit(&p.scgci2c, 3, on) },
663        Domain::I2c2 => unsafe { bb::change_bit(&p.scgci2c, 2, on) },
664        Domain::I2c1 => unsafe { bb::change_bit(&p.scgci2c, 1, on) },
665        Domain::I2c0 => unsafe { bb::change_bit(&p.scgci2c, 0, on) },
666        Domain::Usb => unsafe { bb::change_bit(&p.scgcusb, 0, on) },
667        Domain::Can => unsafe { bb::change_bit(&p.scgccan, 0, on) },
668        Domain::Adc1 => unsafe { bb::change_bit(&p.scgcadc, 1, on) },
669        Domain::Adc0 => unsafe { bb::change_bit(&p.scgcadc, 0, on) },
670        Domain::AnalogComparator => unsafe { bb::change_bit(&p.scgcacmp, 0, on) },
671        Domain::Eeprom => unsafe { bb::change_bit(&p.scgceeprom, 0, on) },
672        Domain::Pwm0 => unsafe { bb::change_bit(&p.scgcpwm, 0, on) },
673        Domain::Pwm1 => unsafe { bb::change_bit(&p.scgcpwm, 1, on) },
674        Domain::Emac0 => unsafe { bb::change_bit(&p.scgcemac, 0, on) },
675        Domain::Ephy0 => unsafe { bb::change_bit(&p.scgcephy, 0, on) },
676    }
677}
678
679fn control_deep_sleep_power(pd: Domain, on: bool) {
680    // We use bit-banding to make an atomic write, so this is safe
681    let p = unsafe { &*tm4c129x::SYSCTL::ptr() };
682    match pd {
683        Domain::Watchdog1 => unsafe { bb::change_bit(&p.dcgcwd, 1, on) },
684        Domain::Watchdog0 => unsafe { bb::change_bit(&p.dcgcwd, 0, on) },
685        Domain::Timer5 => unsafe { bb::change_bit(&p.dcgctimer, 5, on) },
686        Domain::Timer4 => unsafe { bb::change_bit(&p.dcgctimer, 4, on) },
687        Domain::Timer3 => unsafe { bb::change_bit(&p.dcgctimer, 3, on) },
688        Domain::Timer2 => unsafe { bb::change_bit(&p.dcgctimer, 2, on) },
689        Domain::Timer1 => unsafe { bb::change_bit(&p.dcgctimer, 1, on) },
690        Domain::Timer0 => unsafe { bb::change_bit(&p.dcgctimer, 0, on) },
691        Domain::GpioQ => unsafe { bb::change_bit(&p.dcgcgpio, 14, on) },
692        Domain::GpioP => unsafe { bb::change_bit(&p.dcgcgpio, 13, on) },
693        Domain::GpioN => unsafe { bb::change_bit(&p.dcgcgpio, 12, on) },
694        Domain::GpioM => unsafe { bb::change_bit(&p.dcgcgpio, 11, on) },
695        Domain::GpioL => unsafe { bb::change_bit(&p.dcgcgpio, 10, on) },
696        Domain::GpioK => unsafe { bb::change_bit(&p.dcgcgpio, 9, on) },
697        Domain::GpioJ => unsafe { bb::change_bit(&p.dcgcgpio, 8, on) },
698        Domain::GpioH => unsafe { bb::change_bit(&p.dcgcgpio, 7, on) },
699        Domain::GpioG => unsafe { bb::change_bit(&p.dcgcgpio, 6, on) },
700        Domain::GpioF => unsafe { bb::change_bit(&p.dcgcgpio, 5, on) },
701        Domain::GpioE => unsafe { bb::change_bit(&p.dcgcgpio, 4, on) },
702        Domain::GpioD => unsafe { bb::change_bit(&p.dcgcgpio, 3, on) },
703        Domain::GpioC => unsafe { bb::change_bit(&p.dcgcgpio, 2, on) },
704        Domain::GpioB => unsafe { bb::change_bit(&p.dcgcgpio, 1, on) },
705        Domain::GpioA => unsafe { bb::change_bit(&p.dcgcgpio, 0, on) },
706        Domain::MicroDma => unsafe { bb::change_bit(&p.dcgcdma, 0, on) },
707        Domain::Hibernation => unsafe { bb::change_bit(&p.dcgchib, 0, on) },
708        Domain::Uart7 => unsafe { bb::change_bit(&p.dcgcuart, 7, on) },
709        Domain::Uart6 => unsafe { bb::change_bit(&p.dcgcuart, 6, on) },
710        Domain::Uart5 => unsafe { bb::change_bit(&p.dcgcuart, 5, on) },
711        Domain::Uart4 => unsafe { bb::change_bit(&p.dcgcuart, 4, on) },
712        Domain::Uart3 => unsafe { bb::change_bit(&p.dcgcuart, 3, on) },
713        Domain::Uart2 => unsafe { bb::change_bit(&p.dcgcuart, 2, on) },
714        Domain::Uart1 => unsafe { bb::change_bit(&p.dcgcuart, 1, on) },
715        Domain::Uart0 => unsafe { bb::change_bit(&p.dcgcuart, 0, on) },
716        Domain::Ssi3 => unsafe { bb::change_bit(&p.dcgcssi, 3, on) },
717        Domain::Ssi2 => unsafe { bb::change_bit(&p.dcgcssi, 2, on) },
718        Domain::Ssi1 => unsafe { bb::change_bit(&p.dcgcssi, 1, on) },
719        Domain::Ssi0 => unsafe { bb::change_bit(&p.dcgcssi, 0, on) },
720        Domain::I2c3 => unsafe { bb::change_bit(&p.dcgci2c, 3, on) },
721        Domain::I2c2 => unsafe { bb::change_bit(&p.dcgci2c, 2, on) },
722        Domain::I2c1 => unsafe { bb::change_bit(&p.dcgci2c, 1, on) },
723        Domain::I2c0 => unsafe { bb::change_bit(&p.dcgci2c, 0, on) },
724        Domain::Usb => unsafe { bb::change_bit(&p.dcgcusb, 0, on) },
725        Domain::Can => unsafe { bb::change_bit(&p.dcgccan, 0, on) },
726        Domain::Adc1 => unsafe { bb::change_bit(&p.dcgcadc, 1, on) },
727        Domain::Adc0 => unsafe { bb::change_bit(&p.dcgcadc, 0, on) },
728        Domain::AnalogComparator => unsafe { bb::change_bit(&p.dcgcacmp, 0, on) },
729        Domain::Eeprom => unsafe { bb::change_bit(&p.dcgceeprom, 0, on) },
730        Domain::Pwm0 => unsafe { bb::change_bit(&p.dcgcpwm, 0, on) },
731        Domain::Pwm1 => unsafe { bb::change_bit(&p.dcgcpwm, 1, on) },
732        Domain::Emac0 => unsafe { bb::change_bit(&p.dcgcemac, 0, on) },
733        Domain::Ephy0 => unsafe { bb::change_bit(&p.dcgcephy, 0, on) },
734    }
735}
736
737/// Extension trait that constrains the `SYSCTL` peripheral
738pub trait SysctlExt {
739    /// Constrains the `SYSCTL` peripheral so it plays nicely with the other
740    /// abstractions
741    fn constrain(self) -> Sysctl;
742}
743
744impl SysctlExt for tm4c129x::SYSCTL {
745    fn constrain(self) -> Sysctl {
746        Sysctl {
747            power_control: PowerControl {},
748            clock_setup: ClockSetup {
749                oscillator: Oscillator::PrecisionInternal(SystemClock::UseOscillator(Divider::_1)),
750            },
751        }
752    }
753}
754
755impl ClockSetup {
756    /// Fix the clock configuration and produce a record of the configuration
757    /// so that other modules can calibrate themselves (e.g. the UARTs).
758    pub fn freeze(self) -> Clocks {
759        // We own the SYSCTL at this point - no one else can be running.
760        let p = unsafe { &*tm4c129x::SYSCTL::ptr() };
761
762        let osc: Hertz;
763        let sysclk: Hertz;
764
765        match self.oscillator {
766            // The default
767            Oscillator::PrecisionInternal(SystemClock::UseOscillator(div)) => {
768                // 1. Once POR has completed, the PIOSC is acting as the system clock.
769                osc = 16_000_000.hz();
770                sysclk = (osc.0 / (div as u32)).hz();
771
772                p.rsclkcfg.modify(|_, w| {
773                    w.osysdiv().bits(div as u16 - 1);
774
775                    w
776                });
777            }
778            Oscillator::PrecisionInternal(SystemClock::UsePll(output_frequency)) => {
779                osc = 16_000_000.hz();
780                sysclk = output_frequency.into();
781
782                // 6. Write the PLLFREQ0 and PLLFREQ1 registers with the values of Q, N, MINT,
783                // and MFRAC to the configure the desired VCO frequency setting.
784                // Crystal, MINT, MINT, N, Ref MHZ, Pll MHZ
785
786                p.rsclkcfg.modify(|_, w| w.pllsrc().piosc());
787
788                p.pllfreq0.modify(|_, w| {
789                    w.pllpwr().set_bit();
790
791                    w.mfrac().bits(0);
792                    w.mint().bits(30);
793
794                    w
795                });
796
797                p.pllfreq1.modify(|_, w| {
798                    w.q().bits(0);
799                    w.n().bits(0);
800
801                    w
802                });
803
804                p.rsclkcfg.modify(|_, w| w.newfreq().set_bit());
805
806                let (xbcht, xbce, xws) = match sysclk.0 {
807                    f if f <= 16_000_000 => (0, true, 0),
808                    f if f <= 40_000_000 => (2, false, 1),
809                    f if f <= 60_000_000 => (3, false, 2),
810                    f if f <= 80_000_000 => (4, false, 3),
811                    f if f <= 100_000_000 => (5, false, 4),
812                    f if f <= 120_000_000 => (6, false, 5),
813                    _ => unreachable!(),
814                };
815
816                // 7. Write the MEMTIM0 register to correspond to the new system clock setting.
817                p.memtim0.modify(|_, w| {
818                    unsafe {
819                        w.fbcht().bits(xbcht);
820                        w.ebcht().bits(xbcht);
821
822                        w.fbce().bit(xbce);
823                        w.ebce().bit(xbce);
824
825                        w.fws().bits(xws);
826                        w.ews().bits(xws);
827                    }
828
829                    w
830                });
831
832                // 8. Wait for the PLLSTAT register to indicate the PLL has reached lock at the
833                // new operating point (or that a timeout period has passed and lock has failed,
834                // in which case an error condition exists and this sequence is abandoned and
835                // error processing is initiated).
836                while p.pllstat.read().lock().bit_is_clear() {
837                    cortex_m::asm::nop();
838                }
839
840                // 9. Write the RSCLKCFG register's PSYSDIV value, set the USEPLL bit to
841                // enabled, and MEMTIMU bit.
842                p.rsclkcfg.modify(|_, w| {
843                    w.usepll().set_bit();
844                    w.memtimu().set_bit();
845                    w.psysdiv().bits((480_000_000 / sysclk.0 - 1) as u16);
846
847                    w
848                });
849            }
850
851            Oscillator::Main(crystal_frequency, SystemClock::UseOscillator(div)) => {
852                osc = crystal_frequency.into();
853                sysclk = (osc.0 / (div as u32)).hz();
854
855                // 2. Power up the MOSC by clearing the NOXTAL bit in the MOSCCTL register.
856                p.moscctl.modify(|_, w| {
857                    w.oscrng().set_bit();
858
859                    w.noxtal().clear_bit();
860                    w.pwrdn().clear_bit();
861
862                    w
863                });
864
865                let (xbcht, xbce, xws) = match sysclk.0 {
866                    f if f < 16_000_000 => (0, true, 0),
867                    f if f < 40_000_000 => (2, false, 1),
868                    _ => unreachable!(),
869                };
870
871                // 7. Write the MEMTIM0 register to correspond to the new system clock
872                p.memtim0.modify(|_, w| {
873                    unsafe {
874                        w.fbcht().bits(xbcht);
875                        w.ebcht().bits(xbcht);
876
877                        w.fbce().bit(xbce);
878                        w.ebce().bit(xbce);
879
880                        w.fws().bits(xws);
881                        w.ews().bits(xws);
882                    }
883
884                    w
885                });
886
887                // If single-ended MOSC mode is required, the MOSC is ready to use. If crystal
888                // mode is required, clear the PWRDN bit and wait for the MOSCPUPRIS bit to be
889                // set in the Raw Interrupt Status (RIS), indicating MOSC crystal mode is ready.
890                while p.ris.read().moscpupris().bit_is_clear() {
891                    cortex_m::asm::nop();
892                }
893
894                // 4. Set the OSCSRC field to 0x3 in the RSCLKCFG register at offset 0x0B0.
895                p.rsclkcfg.modify(|_, w| {
896                    w.oscsrc().mosc();
897                    w.memtimu().set_bit();
898
899                    w.osysdiv().bits(div as u16 - 1);
900
901                    w
902                });
903            }
904
905            Oscillator::Main(crystal_frequency, SystemClock::UsePll(output_frequency)) => {
906                osc = crystal_frequency.into();
907                sysclk = output_frequency.into();
908
909                // 2. Power up the MOSC by clearing the NOXTAL bit in the MOSCCTL register.
910                p.moscctl.modify(|_, w| {
911                    w.oscrng().set_bit();
912
913                    w.noxtal().clear_bit();
914                    w.pwrdn().clear_bit();
915
916                    w
917                });
918
919                // If single-ended MOSC mode is required, the MOSC is ready to use. If crystal
920                // mode is required, clear the PWRDN bit and wait for the MOSCPUPRIS bit to be
921                // set in the Raw Interrupt Status (RIS), indicating MOSC crystal mode is ready.
922                while p.ris.read().moscpupris().bit_is_clear() {
923                    cortex_m::asm::nop();
924                }
925
926                // 6. Write the PLLFREQ0 and PLLFREQ1 registers with the values of Q, N, MINT,
927                // and MFRAC to the configure the desired VCO frequency setting.
928                // Crystal, MINT, MINT, N, Ref MHZ, Pll MHZ
929
930                p.rsclkcfg.modify(|_, w| w.pllsrc().mosc());
931
932                p.pllfreq1.modify(|_, w| {
933                    w.q().bits(0);
934                    w.n().bits(4);
935
936                    w
937                });
938
939                p.pllfreq0.modify(|_, w| {
940                    w.mfrac().bits(0);
941                    w.mint().bits(96);
942
943                    w
944                });
945
946                p.pllfreq0.modify(|_, w| w.pllpwr().set_bit());
947
948                // 8. Wait for the PLLSTAT register to indicate the PLL has reached lock at the
949                // new operating point (or that a timeout period has passed and lock has failed,
950                // in which case an error condition exists and this sequence is abandoned and
951                // error processing is initiated).
952
953                while p.pllstat.read().lock().bit_is_clear() {
954                    cortex_m::asm::nop();
955                }
956
957                let (xbcht, xbce, xws) = match sysclk.0 {
958                    f if f <= 16_000_000 => (0, true, 0),
959                    f if f <= 40_000_000 => (2, false, 1),
960                    f if f <= 60_000_000 => (3, false, 2),
961                    f if f <= 80_000_000 => (4, false, 3),
962                    f if f <= 100_000_000 => (5, false, 4),
963                    f if f <= 120_000_000 => (6, false, 5),
964                    _ => unreachable!(),
965                };
966
967                // 7. Write the MEMTIM0 register to correspond to the new system clock setting.
968                p.memtim0.modify(|_, w| {
969                    unsafe {
970                        w.fbcht().bits(xbcht);
971                        w.ebcht().bits(xbcht);
972
973                        w.fbce().bit(xbce);
974                        w.ebce().bit(xbce);
975
976                        w.fws().bits(xws);
977                        w.ews().bits(xws);
978                    }
979
980                    w
981                });
982
983                // 9. Write the RSCLKCFG register's PSYSDIV value, set the USEPLL bit to
984                // enabled, and MEMTIMU bit.
985                p.rsclkcfg.modify(|_, w| {
986                    w.usepll().set_bit();
987                    w.memtimu().set_bit();
988                    w.psysdiv().bits((480_000_000 / sysclk.0 - 1) as u16);
989
990                    w
991                });
992            }
993
994            Oscillator::LowFrequencyInternal(_div) => unimplemented!(),
995        }
996
997        Clocks { osc, sysclk }
998    }
999}
1000
1001impl PowerControl {}
1002
1003/// This module is all about identifying the physical chip we're running on.
1004pub mod chip_id {
1005    pub use tm4c_hal::sysctl::chip_id::*;
1006
1007    /// Read DID0 and DID1 to discover what sort of
1008    /// TM4C129 this is.
1009    pub fn get() -> Result<ChipId, Error> {
1010        // This is safe as it's read only
1011        let p = unsafe { &*tm4c129x::SYSCTL::ptr() };
1012        let did0 = p.did0.read();
1013        if did0.ver().bits() != 0x01 {
1014            return Err(Error::UnknownDid0Ver(did0.ver().bits()));
1015        }
1016        let device_class = match did0.class().bits() {
1017            0x05 => DeviceClass::StellarisBlizzard,
1018            0x0a => DeviceClass::Snowflake,
1019            _ => DeviceClass::Unknown,
1020        };
1021        let major = did0.maj().bits();
1022        let minor = did0.min().bits();
1023        let did1 = p.did1.read();
1024        if did1.ver().bits() != 0x01 {
1025            // Stellaris LM3F (0x00) is not supported
1026            return Err(Error::UnknownDid1Ver(did1.ver().bits()));
1027        }
1028        let part_no = match did1.prtno().bits() {
1029            0x1F => PartNo::Tm4c1294ncpdt,
1030            45 => PartNo::Tm4c129encpdt,
1031            e => PartNo::Unknown(e),
1032        };
1033        let pin_count = match did1.pincnt().bits() {
1034            0 => PinCount::_28,
1035            1 => PinCount::_48,
1036            2 => PinCount::_100,
1037            3 => PinCount::_64,
1038            4 => PinCount::_144,
1039            5 => PinCount::_157,
1040            6 => PinCount::_168,
1041            _ => PinCount::Unknown,
1042        };
1043        let temp_range = match did1.temp().bits() {
1044            0 => TempRange::Commercial,
1045            1 => TempRange::Industrial,
1046            2 => TempRange::Extended,
1047            3 => TempRange::IndustrialOrExtended,
1048            _ => TempRange::Unknown,
1049        };
1050        let package = match did1.pkg().bits() {
1051            0 => Package::Soic,
1052            1 => Package::Lqfp,
1053            2 => Package::Bga,
1054            _ => Package::Unknown,
1055        };
1056        let rohs_compliant = did1.rohs().bit_is_set();
1057        let qualification = match did1.qual().bits() {
1058            0 => Qualification::EngineeringSample,
1059            1 => Qualification::PilotProduction,
1060            2 => Qualification::FullyQualified,
1061            _ => Qualification::Unknown,
1062        };
1063        Ok(ChipId {
1064            device_class,
1065            major,
1066            minor,
1067            pin_count,
1068            temp_range,
1069            package,
1070            rohs_compliant,
1071            qualification,
1072            part_no,
1073        })
1074    }
1075}
1076
1077// End of file