Skip to main content

teensy4_bsp/
board.rs

1//! Pre-configured board resources.
2//!
3//! The `board` module conveniently exposes drivers and hardware resources.
4//! It configures peripheral clocks and power so that you can simply use the
5//! board's peripherals.
6//!
7//! # Getting started
8//!
9//! Create board resources depending on your board:
10//!
11//! - Teensy 4.0 boards should use [`t40`].
12//! - Teensy 4.1 boards should use [`t41`].
13//! - Teensy MicroMod boards should use [`tmm`].
14//!
15//! The produced resources are nearly the same, except for the pins.
16//!
17//! ```no_run
18//! use teensy4_bsp as bsp;
19//! use bsp::board;
20//!
21//! let resources = board::t40(board::instances());
22//! ```
23//!
24//! Resources take ownership of all peripheral instances `Instances`. Use [`instances()`] to
25//! acquire these once.
26//!
27//! > Note that if you're using RTIC, you can let the RTIC framework allocate
28//! > the instances. The examples included in this package demonstrate this pattern.
29//!
30//! # Resource categories
31//!
32//! The objects in [`Resources`] have two main categories:
33//!
34//! 1. ready-to-go drivers, like `gpt1` and `dma`, which are unlikely to change no matter your
35//!    hardware setup.
36//! 2. lower-level resources, like `pins` and `lpuart3`, which you can compose to create drivers
37//!    specific for your hardware setup.
38//!
39//! Given the Teensy 4's I/O flexibility, it would be difficult to expose all features as ready-to-go
40//! drivers. Instead, `board` tries to help you initialize drivers for your hardware
41//! setup. For example,
42//!
43//! - use [`led`] to prepare the on-board LED.
44//! - use [`lpspi`] to prepare SPI peripherals.
45//! - use [`lpuart`] to prepare serial peripherals.
46//! - use [`lpi2c`] to prepare I2C peripherals.
47//!
48//! For the complete list of helper functions, study the rest of this API documentation and their
49//! examples. And for the complete driver documentation, see [the `hal` module](crate::hal) and
50//! its submodules.
51//!
52//! These helper functions assume that you're following the `board`'s clock (and power) policy.
53//!
54//! # Clock policy
55//!
56//! Once [`t40`] and [`t41`] return, the clocks of all returned resources are running, and clock gates are
57//! enabled. Essentially, `board` handles CCM configurations so that you can use peripherals with reasonable
58//! settings.
59//!
60//! `board` exposes constants to help you understand those clock frequencies. You should
61//! use these frequencies, along with your own settings, to describe certain types of objects, like
62//! blocking delays.
63//!
64//! The example below shows how a user configures a GPT to meet a given GPT frequency.
65//!
66//! ```no_run
67//! # use teensy4_bsp as bsp;
68//! # use bsp::board;
69//! use bsp::hal::{gpt, timer::Blocking};
70//!
71//! // Given this GPT clock source...
72//! const GPT_CLOCK_SOURCE: gpt::ClockSource = gpt::ClockSource::PeripheralClock;
73//! // ...and this GPT-specific divider...
74//! const GPT_DIVIDER: u32 = 8;
75//! /// ...the GPT frequency is
76//! const GPT_FREQUENCY: u32 = board::PERCLK_FREQUENCY / GPT_DIVIDER;
77//!
78//! let board::Resources{ mut gpt1, .. }  = board::t40(board::instances());
79//!
80//! gpt1.set_clock_source(GPT_CLOCK_SOURCE);
81//! gpt1.set_divider(GPT_DIVIDER);
82//!
83//! let mut delay = Blocking::<_, { GPT_FREQUENCY }>::from_gpt(gpt1);
84//! delay.block_ms(500);
85//! ```
86//!
87//! Clock frequency constants, and all APIs depending on those constants, assume that you do not change the clock policy.
88//! But for those who want extra control, `Resources` exposes the clock management peripherals. If you take this
89//! route, you're responsible for ensuring your peripheral's clock configurations, and you should ignore the constants
90//! exposed by this module.
91//!
92//! ## Clock details
93//!
94//! `board` makes a few guarantees about the clock policy. This section describes those guarantees.
95//!
96//! It's considered an API-breaking change to vary the frequencies and derivations of these clocks:
97//!
98//! - The ARM core frequency is documented in [`ARM_FREQUENCY`].
99//! - PERCLK, the root clock for GPT and PIT timers, is documented in [`PERCLK_FREQUENCY`].
100//! - The crystal oscillator is documented in [`XTAL_OSCILLATOR_FREQUENCY`].
101//!
102//! `board` does not touch the following root clock components. You should configure these components yourself.
103//!
104//! - FlexIO1 and FlexIO2 dividers and multiplexers.
105//!
106//! Other clock frequencies are exempt from this policy; they may change value or derivation without
107//! notice. Nevertheless, if these clock frequencies / derivations change, `board` still guarantees that
108//! the functions to set peripheral baud and clock rates will work as expected.
109//!
110//! By the time your code has access to [`Resources`], the clock gates for _all_ peripherals provided by
111//! `Resources` is set to "on." If you're not using specific resources, you may configure their clock
112//! gates to "off." `board` code that borrows or converts peripherals may assume that clock gates are
113//! set to "on."
114//!
115//! If you're not using the BSP to prepare board `Resources`, consider using [`prepare_clocks_and_power`]
116//! to realize the BSP's clock policy.
117//!
118//! # Naming conventions
119//!
120//! This module identifies peripherals by their hardware names. It does not use identifiers
121//! from the Teensy 4 SDK and documentation. For instance, to name the serial peripheral
122//! that uses pins 14 and 15,
123//!
124//! - this module uses the name "LPUART**2**".
125//! - the Teensy 4 SDK / documentation uses the name "UART**3**".
126//!
127//! There's a few reasons for these differences:
128//!
129//! - It would be unintuitive to register a LPUART**2** *interrupt* for the peripheral named
130//!   UART**3**. Since the BSP typically does not manage interrupt registration, this naming
131//!   decision makes it easier for you to register and implement interrupts.
132//! - It makes clear the peripheral implementation. You know that the serial peripheral
133//!   supports low-power (LP) operation, and that it's not a FlexIO peripheral emulating a UART
134//!   device.
135
136use crate::{hal, pins, ral};
137use core::sync::atomic::{AtomicBool, Ordering};
138pub use hal::lpspi::Pins as LpspiPins;
139
140/// Use [`instances()`] to safely acquire.
141pub use ral::Instances;
142
143/// Acquire peripheral instances.
144///
145/// These are the resources supplied to [a resource constructor](crate::board#getting-started).
146/// They can also be used to initialize your own drivers.
147///
148/// ```
149/// use teensy4_bsp as bsp;
150/// use bsp::board;
151///
152/// let instances = board::instances();
153/// ```
154///
155/// # Panics
156///
157/// Panics if the instances have already been taken from this function.
158/// If you're using RTIC, know that RTIC may take these instances before
159/// calling your `init` function.
160///
161/// ```should_panic
162/// # use teensy4_bsp as bsp;
163/// # use bsp::board;
164/// let instances = board::instances();
165/// // Sometime later...
166/// board::instances(); // Panics! Instances already taken.
167/// ```
168///
169/// # Safety
170///
171/// This function provides a safe, convenient way to acquire one [`Instances`] object.
172/// It's considered safe for the use-cases that `teensy4-bsp` intends to support;
173/// specifically, you're building one binary that represents the entire firmware
174/// image, and that there's no other software which is acquiring these resources.
175pub fn instances() -> Instances {
176    static TAKEN: AtomicBool = AtomicBool::new(false);
177    assert!(!TAKEN.swap(true, Ordering::SeqCst));
178    unsafe { Instances::instances() }
179}
180
181pub use crate::clock_power::*;
182
183/// Resources for a Teensy 4.0.
184///
185/// Use [`t40`] to construct this. The pins are specific to the Teensy 4.0.
186pub type T40Resources = Resources<pins::t40::Pins>;
187/// Resources for a Teensy 4.1.
188///
189/// Use [`t41`] to construct this. The pins are specific to the Teensy 4.1.
190pub type T41Resources = Resources<pins::t41::Pins>;
191/// Resources for a Teensy MicroMod.
192///
193/// Use [`tmm`] to construct this. The pins are specific to the Teensy MicroMod.
194pub type TMMResources = Resources<pins::tmm::Pins>;
195
196/// Resources constructed by the board.
197///
198/// The concrete `Pins` type depends on how this is constructed.
199/// See the various `*Resources` aliases for more information.
200#[non_exhaustive]
201pub struct Resources<Pins> {
202    /// Periodic interrupt timer channels.
203    pub pit: hal::pit::Channels,
204    /// General purpose timer 1.
205    pub gpt1: hal::gpt::Gpt1,
206    /// General purpose timer 2.
207    pub gpt2: hal::gpt::Gpt2,
208    /// GPIO1 port.
209    pub gpio1: hal::gpio::Port<1>,
210    /// GPIO2 port.
211    pub gpio2: hal::gpio::Port<2>,
212    /// GPIO3 port.
213    pub gpio3: hal::gpio::Port<3>,
214    /// GPIO4 port.
215    pub gpio4: hal::gpio::Port<4>,
216    /// USB1 instances.
217    ///
218    /// Use this to construct higher-level USB drivers, or to initialize the USB logger.
219    pub usb: hal::usbd::Instances<1>,
220    /// DMA channels.
221    pub dma: [Option<hal::dma::channel::Channel>; hal::dma::CHANNEL_COUNT],
222    /// The secure real-time counter.
223    ///
224    /// It's initially disabled, and you may enable it in your firmware.
225    pub srtc: hal::snvs::srtc::Disabled,
226    /// Core registers for the SNVS low-power domain.
227    ///
228    /// Use this with the SRTC and other SNVS LP components.
229    pub snvs_lp_core: hal::snvs::LpCore,
230    /// Clock control module.
231    pub ccm: ral::ccm::CCM,
232    /// Analog clock control module.
233    pub ccm_analog: ral::ccm_analog::CCM_ANALOG,
234    /// DCDC converter
235    pub dcdc: ral::dcdc::DCDC,
236    /// All available pins.
237    pub pins: Pins,
238    /// The register block for [`Lpi2c1`].
239    pub lpi2c1: ral::lpi2c::LPI2C1,
240    /// The register block for [`Lpi2c3`].
241    pub lpi2c3: ral::lpi2c::LPI2C3,
242    /// The register blocks for [`Lpspi1`].
243    pub lpspi1: ral::lpspi::LPSPI1,
244    /// The register blocks for [`Lpspi2`].
245    pub lpspi2: ral::lpspi::LPSPI2,
246    /// The register blocks for [`Lpspi3`].
247    pub lpspi3: ral::lpspi::LPSPI3,
248    /// The register block for [`Lpspi4`].
249    pub lpspi4: ral::lpspi::LPSPI4,
250    /// The register block for [`Lpuart6`].
251    pub lpuart6: ral::lpuart::LPUART6,
252    /// The register block for [`Lpuart4`].
253    pub lpuart4: ral::lpuart::LPUART4,
254    /// The register block for [`Lpuart2`].
255    pub lpuart2: ral::lpuart::LPUART2,
256    /// The register block for [`Lpuart3`].
257    pub lpuart3: ral::lpuart::LPUART3,
258    /// The register block for [`Lpuart8`].
259    pub lpuart8: ral::lpuart::LPUART8,
260    /// The register block for [`Lpuart1`].
261    pub lpuart1: ral::lpuart::LPUART1,
262    /// The register block for [`Lpuart5`].
263    pub lpuart5: ral::lpuart::LPUART5,
264    /// The register block for [`Lpuart7`].
265    pub lpuart7: ral::lpuart::LPUART7,
266    /// FlexPWM1 components.
267    pub flexpwm1: (hal::flexpwm::Pwm<1>, hal::flexpwm::Submodules<1>),
268    /// FlexPWM2 components.
269    pub flexpwm2: (hal::flexpwm::Pwm<2>, hal::flexpwm::Submodules<2>),
270    /// FlexPWM3 components.
271    pub flexpwm3: (hal::flexpwm::Pwm<3>, hal::flexpwm::Submodules<3>),
272    /// FlexPWM4 components.
273    pub flexpwm4: (hal::flexpwm::Pwm<4>, hal::flexpwm::Submodules<4>),
274    /// The FlexIO1 register block.
275    pub flexio1: ral::flexio::FLEXIO1,
276    /// The FlexIO2 register block.
277    pub flexio2: ral::flexio::FLEXIO2,
278    /// The FlexIO3 register block.
279    pub flexio3: ral::flexio::FLEXIO3,
280    /// The register block for ADC1.
281    ///
282    /// ADC drivers constructed by `board` use a pre-configured clock and divisor. To change
283    /// this configuration, call `release()` to acquire the register block, then re-construct
284    /// the driver.
285    pub adc1: hal::adc::Adc<1>,
286    /// The register block for ADC2.
287    pub adc2: hal::adc::Adc<2>,
288    /// True random number generator.
289    pub trng: hal::trng::Trng,
290    /// Temperature monitor of the core.
291    pub tempmon: hal::tempmon::TempMon,
292    /// The register block for SAI1 (I2S audio).
293    ///
294    /// SAI1 is the primary audio interface used by the Teensy Audio Shield.
295    pub sai1: ral::sai::SAI1,
296    /// The register block for SAI2.
297    pub sai2: ral::sai::SAI2,
298    /// The register block for SAI3.
299    pub sai3: ral::sai::SAI3,
300    /// The IOMUXC general purpose register block.
301    pub iomuxc_gpr: ral::iomuxc_gpr::IOMUXC_GPR,
302    /// The USDHC1 peripheral instance.
303    pub usdhc1: ral::usdhc::USDHC1,
304    /// The FlexSPI2 peripheral instance.
305    pub flexspi2: ral::flexspi::FLEXSPI2,
306}
307
308/// The board's dedicated LED.
309pub type Led = hal::gpio::Output<pins::common::P13>;
310
311/// Create the board's LED.
312///
313/// ```no_run
314/// use teensy4_bsp as bsp;
315/// use bsp::board;
316///
317/// let board::Resources { mut gpio2, pins, .. }
318///     = board::t40(board::instances());
319///
320/// let led = board::led(&mut gpio2, pins.p13);
321/// ```
322pub fn led(gpio2: &mut hal::gpio::Port<2>, p13: pins::common::P13) -> Led {
323    gpio2.output(p13)
324}
325
326/// Create a LPI2C peripheral.
327///
328/// Consider using explicit type annotations, as demonstrated below,
329/// to simplify any errors from the compiler.
330///
331/// This helper assumes that the actual LPI2C clock frequency equals [`LPI2C_FREQUENCY`].
332///
333/// ```no_run
334/// use teensy4_bsp as bsp;
335/// use bsp::board;
336///
337/// let board::Resources { lpi2c3, pins, ..}
338///     = board::t40(board::instances());
339///
340/// let mut lpi2c: board::Lpi2c3 = board::lpi2c(
341///     lpi2c3,
342///     pins.p16,
343///     pins.p17,
344///     board::Lpi2cClockSpeed::KHz400,
345/// );
346/// ```
347pub fn lpi2c<Scl, Sda, const N: u8>(
348    instance: ral::lpi2c::Instance<N>,
349    scl: Scl,
350    sda: Sda,
351    clock_speed: Lpi2cClockSpeed,
352) -> hal::lpi2c::Lpi2c<hal::lpi2c::Pins<Scl, Sda>, N>
353where
354    Scl: hal::iomuxc::lpi2c::Pin<
355        Signal = hal::iomuxc::lpi2c::Scl,
356        Module = hal::iomuxc::consts::Const<N>,
357    >,
358    Sda: hal::iomuxc::lpi2c::Pin<
359        Signal = hal::iomuxc::lpi2c::Sda,
360        Module = hal::iomuxc::consts::Const<N>,
361    >,
362{
363    hal::lpi2c::Lpi2c::new(
364        instance,
365        hal::lpi2c::Pins { scl, sda },
366        &lpi2c_baud(clock_speed),
367    )
368}
369
370/// LPI2C1 peripheral.
371///
372/// - Pin 19 is the clock line.
373/// - Pin 18 is the data line.
374///
375/// Use [`lpi2c`] to create this driver.
376pub type Lpi2c1 = hal::lpi2c::Lpi2c<hal::lpi2c::Pins<pins::common::P19, pins::common::P18>, 1>;
377
378/// LPI2C3 peripheral.
379///
380/// - Pin 16 is the clock line.
381/// - Pin 17 is the data line.
382///
383/// Use [`lpi2c`] to create this driver.
384pub type Lpi2c3 = hal::lpi2c::Lpi2c<hal::lpi2c::Pins<pins::common::P16, pins::common::P17>, 3>;
385
386/// LPSPI1 peripheral.
387///
388/// - SDO:  GPIO_SD_B0_02 (p43) or GPIO_EMC_28 (p50)
389/// - SDI:  GPIO_SD_B0_03 (p42) or GPIO_EMC_29 (p54)
390/// - SCK:  GPIO_SD_B0_00 (p45) or GPIO_EMC_27 (p49)
391/// - PCS0: GPIO_SD_B0_01 (p44) or GPIO_EMC_30
392///
393/// Use [`lpspi`] to create this driver.
394pub type Lpspi1<SDO, SDI, SCK, PCS0> = hal::lpspi::Lpspi<LpspiPins<SDO, SDI, SCK, PCS0>, 1>;
395
396/// LPSPI2 peripheral.
397///
398/// - SDO:  GPIO_SD_B1_08 or GPIO_EMC_02
399/// - SDI:  GPIO_SD_B1_09 or GPIO_EMC_03
400/// - SCK:  GPIO_SD_B1_07 or GPIO_EMC_00
401/// - PCS0: GPIO_SD_B1_06 or GPIO_EMC_01
402///
403/// Use [`lpspi`] to create this driver.
404pub type Lpspi2<SDO, SDI, SCK, PCS0> = hal::lpspi::Lpspi<LpspiPins<SDO, SDI, SCK, PCS0>, 2>;
405
406/// LPSPI3 peripheral.
407///
408/// CS and SDI have two options each for which pin to use.
409///
410/// - Pin 26 is data out (SDO).
411/// - Pin 39 or 1 is data in (SDI).
412/// - Pin 27 is clock (SCK).
413/// - Pin 0 or 38 is chip select (CS).
414///
415/// Use [`lpspi`] to create this driver.
416pub type Lpspi3<SDI, CS> =
417    hal::lpspi::Lpspi<LpspiPins<pins::common::P26, SDI, pins::common::P27, CS>, 3>;
418
419/// LPSPI4 peripheral.
420///
421/// - Pin 10 is chip select (CS).
422/// - Pin 11 is data out (SDO).
423/// - Pin 12 is data in (SDI).
424/// - Pin 13 is clock (SCK).
425///
426/// Use [`lpspi`] to create this driver.
427pub type Lpspi4 = hal::lpspi::Lpspi<
428    LpspiPins<pins::common::P11, pins::common::P12, pins::common::P13, pins::common::P10>,
429    4,
430>;
431
432/// Create a LPSPI peripheral.
433///
434/// `baud` is the SCK frequency, in Hz. Consider using explicit type annotations, as demonstrated
435/// below, to simplify any errors from the compiler.
436///
437/// This helper assumes that the LPSPI clock frequency equals [`LPSPI_FREQUENCY`].
438///
439/// ```no_run
440/// use teensy4_bsp as bsp;
441/// use bsp::board;
442///
443/// let board::T40Resources { lpspi4, pins, .. }
444///     = board::t40(board::instances());
445///
446/// let mut lpspi4: board::Lpspi4 = board::lpspi(
447///     lpspi4,
448///     board::LpspiPins {
449///         sdo: pins.p11,
450///         sdi: pins.p12,
451///         sck: pins.p13,
452///         pcs0: pins.p10,
453///     },
454///     1_000_000,
455/// );
456/// ```
457pub fn lpspi<Sdo, Sdi, Sck, Pcs0, const N: u8>(
458    instance: ral::lpspi::Instance<N>,
459    pins: LpspiPins<Sdo, Sdi, Sck, Pcs0>,
460    baud: u32,
461) -> hal::lpspi::Lpspi<LpspiPins<Sdo, Sdi, Sck, Pcs0>, N>
462where
463    Sdo: hal::iomuxc::lpspi::Pin<
464        Signal = hal::iomuxc::lpspi::Sdo,
465        Module = hal::iomuxc::consts::Const<N>,
466    >,
467    Sdi: hal::iomuxc::lpspi::Pin<
468        Signal = hal::iomuxc::lpspi::Sdi,
469        Module = hal::iomuxc::consts::Const<N>,
470    >,
471    Sck: hal::iomuxc::lpspi::Pin<
472        Signal = hal::iomuxc::lpspi::Sck,
473        Module = hal::iomuxc::consts::Const<N>,
474    >,
475    Pcs0: hal::iomuxc::lpspi::Pin<
476        Signal = hal::iomuxc::lpspi::Pcs0,
477        Module = hal::iomuxc::consts::Const<N>,
478    >,
479{
480    let mut spi = hal::lpspi::Lpspi::new(instance, pins);
481    spi.disabled(|spi| spi.set_clock_hz(LPSPI_FREQUENCY, baud));
482    spi
483}
484
485/// Create a LPUART peripheral.
486///
487/// The specific peripheral you're creating depends on
488///
489/// - the type of `instance`.
490/// - the TX and RX pins.
491/// - the return type, which can be explicitly annotated.
492///
493/// Consider using an explicit type annotation to help catch any
494/// programming errors.
495///
496/// This helper assumes that the UART clock frequency equals [`UART_FREQUENCY`].
497///
498/// ```no_run
499/// use teensy4_bsp as bsp;
500/// use bsp::board;
501///
502/// let board::T40Resources { lpuart6, lpuart2, pins, .. }
503///     = board::t40(board::instances());
504///
505/// // Explicit type:
506/// let mut lpuart6: board::Lpuart6 = board::lpuart(
507///     lpuart6,
508///     pins.p1,
509///     pins.p0,
510///     115200,
511/// );
512///
513/// // Implicit type:
514/// let mut lpuart2 = board::lpuart(lpuart2, pins.p14, pins.p15, 9600);
515/// ```
516pub fn lpuart<Tx, Rx, const N: u8>(
517    instance: ral::lpuart::Instance<N>,
518    tx: Tx,
519    rx: Rx,
520    baud: u32,
521) -> hal::lpuart::Lpuart<hal::lpuart::Pins<Tx, Rx>, N>
522where
523    Tx: hal::iomuxc::lpuart::Pin<
524        Direction = hal::iomuxc::lpuart::Tx,
525        Module = hal::iomuxc::consts::Const<N>,
526    >,
527    Rx: hal::iomuxc::lpuart::Pin<
528        Direction = hal::iomuxc::lpuart::Rx,
529        Module = hal::iomuxc::consts::Const<N>,
530    >,
531{
532    let mut uart = hal::lpuart::Lpuart::new(instance, hal::lpuart::Pins { tx, rx });
533    uart.disable(|uart| uart.set_baud(&lpuart_baud(baud)));
534    uart
535}
536
537/// LPUART6 peripheral.
538///
539/// - Pin 1 is TX.
540/// - Pin 0 is RX.
541///
542/// Use [`lpuart`] to create this driver.
543pub type Lpuart6 = hal::lpuart::Lpuart<hal::lpuart::Pins<pins::common::P1, pins::common::P0>, 6>;
544
545/// LPUART4 peripheral.
546///
547/// - Pin 8 is TX.
548/// - Pin 7 is RX.
549///
550/// Use [`lpuart`] to create this driver.
551pub type Lpuart4 = hal::lpuart::Lpuart<hal::lpuart::Pins<pins::common::P8, pins::common::P7>, 4>;
552
553/// LPUART2 peripheral.
554///
555/// - Pin 14 is TX.
556/// - Pin 15 is RX.
557///
558/// Use [`lpuart`] to create this driver.
559pub type Lpuart2 = hal::lpuart::Lpuart<hal::lpuart::Pins<pins::common::P14, pins::common::P15>, 2>;
560
561/// LPUART3 peripheral.
562///
563/// - Pin 17 is TX.
564/// - Pin 16 is RX.
565///
566/// Use [`lpuart`] to create this driver.
567pub type Lpuart3 = hal::lpuart::Lpuart<hal::lpuart::Pins<pins::common::P17, pins::common::P16>, 3>;
568
569/// LPUART8 peripheral.
570///
571/// - Pin 20 is TX.
572/// - Pin 21 is RX.
573///
574/// Use [`lpuart`] to create this driver.
575pub type Lpuart8 = hal::lpuart::Lpuart<hal::lpuart::Pins<pins::common::P20, pins::common::P21>, 8>;
576
577/// LPUART1 peripheral.
578///
579/// - Pin 24 is TX.
580/// - Pin 25 is RX.
581///
582/// Use [`lpuart`] to create this driver.
583pub type Lpuart1 = hal::lpuart::Lpuart<hal::lpuart::Pins<pins::common::P24, pins::common::P25>, 1>;
584
585/// LPUART7 peripheral.
586///
587/// - Pin 29 is TX.
588/// - Pin 28 is RX.
589///
590/// Use [`lpuart`] to create this driver.
591pub type Lpuart7 = hal::lpuart::Lpuart<hal::lpuart::Pins<pins::common::P29, pins::common::P28>, 7>;
592
593/// LPUART5 peripheral, available on the Teensy 4.1.
594///
595/// - Pin 35 is TX.
596/// - Pin 34 is RX.
597///
598/// Use [`lpuart`] to create this driver.
599pub type Lpuart5 = hal::lpuart::Lpuart<hal::lpuart::Pins<pins::t41::P35, pins::t41::P34>, 5>;
600
601fn prepare_resources<Pins>(
602    mut instances: Instances,
603    from_pads: impl FnOnce(hal::iomuxc::pads::Pads) -> Pins,
604) -> Resources<Pins> {
605    prepare_clocks_and_power(
606        &mut instances.CCM,
607        &mut instances.CCM_ANALOG,
608        &mut instances.DCDC,
609    );
610    let iomuxc = hal::iomuxc::into_pads(instances.IOMUXC);
611    let pins = from_pads(iomuxc);
612
613    // Stop timers in debug mode.
614    ral::modify_reg!(ral::pit, instances.PIT, MCR, FRZ: FRZ_1);
615    let pit = hal::pit::new(instances.PIT);
616
617    let mut gpt1 = hal::gpt::Gpt::new(instances.GPT1);
618    gpt1.disable();
619
620    let mut gpt2 = hal::gpt::Gpt::new(instances.GPT2);
621    gpt2.disable();
622
623    let hal::snvs::Snvs {
624        low_power:
625            hal::snvs::LowPower {
626                core: snvs_lp_core,
627                srtc,
628                ..
629            },
630        ..
631    } = hal::snvs::new(instances.SNVS);
632
633    let adc1 = hal::adc::Adc::new(
634        instances.ADC1,
635        hal::adc::ClockSelect::ADACK,
636        hal::adc::ClockDivision::Div8,
637    );
638    let adc2 = hal::adc::Adc::new(
639        instances.ADC2,
640        hal::adc::ClockSelect::ADACK,
641        hal::adc::ClockDivision::Div8,
642    );
643
644    let trng = hal::trng::Trng::new(instances.TRNG, Default::default(), Default::default());
645    let tempmon = hal::tempmon::TempMon::with_measure_freq(instances.TEMPMON, 0x1000);
646
647    Resources {
648        pit,
649        gpt1,
650        gpt2,
651        gpio1: hal::gpio::Port::new(instances.GPIO1),
652        gpio2: hal::gpio::Port::new(instances.GPIO2),
653        gpio3: hal::gpio::Port::new(instances.GPIO3),
654        gpio4: hal::gpio::Port::new(instances.GPIO4),
655        usb: hal::usbd::Instances {
656            usb: instances.USB1,
657            usbphy: instances.USBPHY1,
658            usbnc: instances.USBNC1,
659        },
660        dma: hal::dma::channels(instances.DMA, instances.DMAMUX),
661        srtc,
662        snvs_lp_core,
663        ccm: instances.CCM,
664        ccm_analog: instances.CCM_ANALOG,
665        dcdc: instances.DCDC,
666        pins,
667        lpi2c1: instances.LPI2C1,
668        lpi2c3: instances.LPI2C3,
669        lpspi1: instances.LPSPI1,
670        lpspi2: instances.LPSPI2,
671        lpspi3: instances.LPSPI3,
672        lpspi4: instances.LPSPI4,
673        lpuart6: instances.LPUART6,
674        lpuart4: instances.LPUART4,
675        lpuart2: instances.LPUART2,
676        lpuart3: instances.LPUART3,
677        lpuart8: instances.LPUART8,
678        lpuart1: instances.LPUART1,
679        lpuart7: instances.LPUART7,
680        lpuart5: instances.LPUART5,
681        flexio1: instances.FLEXIO1,
682        flexio2: instances.FLEXIO2,
683        flexio3: instances.FLEXIO3,
684        flexpwm1: hal::flexpwm::new(instances.PWM1),
685        flexpwm2: hal::flexpwm::new(instances.PWM2),
686        flexpwm3: hal::flexpwm::new(instances.PWM3),
687        flexpwm4: hal::flexpwm::new(instances.PWM4),
688        adc1,
689        adc2,
690        trng,
691        tempmon,
692        sai1: instances.SAI1,
693        sai2: instances.SAI2,
694        sai3: instances.SAI3,
695        iomuxc_gpr: instances.IOMUXC_GPR,
696        usdhc1: instances.USDHC1,
697        flexspi2: instances.FLEXSPI2,
698    }
699}
700
701/// Create resources for the Teensy 4.0 board.
702///
703/// Note that the peripheral instances acquired by RTIC -- named `device` in the
704/// `init::Context` object -- can be used as the argument to this function.
705pub fn t40(instances: impl Into<Instances>) -> T40Resources {
706    prepare_resources(instances.into(), pins::t40::from_pads)
707}
708
709/// Create resources for the Teensy 4.1 board.
710///
711/// Note that the peripheral instances acquired by RTIC -- named `device` in the
712/// `init::Context` object -- can be used as the argument to this function.
713pub fn t41(instances: impl Into<Instances>) -> T41Resources {
714    prepare_resources(instances.into(), pins::t41::from_pads)
715}
716
717/// Create resources for the Teensy MicroMod board.
718///
719/// Note that the peripheral instances acquired by RTIC -- named `device` in the
720/// `init::Context` object -- can be used as the argument to this function.
721pub fn tmm(instances: impl Into<Instances>) -> TMMResources {
722    prepare_resources(instances.into(), pins::tmm::from_pads)
723}