tm4c123x_hal/
sysctl.rs

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