lpc8xx_hal/
lib.rs

1//! # LPC8xx HAL
2//!
3//! Hardware Abstraction Layer (HAL) for the NXP LPC800 series of ARM Cortex-M0+
4//! microcontrollers.
5//!
6//!
7//! ## Adding LPC8xx HAL as a dependency
8//!
9//! To use LPC8xx HAL in your project, you need to include it via Cargo, by
10//! adding a dependency to you `Cargo.toml`:
11//!
12//! ``` toml
13//! [dependencies.lpc8xx-hal]
14//! version  = "0.9"
15//! features = ["824m201jhi33"]
16//! ```
17//!
18//! The above adds a dependency on the `lpc8xx-hal` crate and selects your
19//! target hardware. To find out which targets are supported, please check out
20//! the list of targets in our [`Cargo.toml`].
21//!
22//! In principle, there are two things you might want to do differently in your
23//! project (besides selecting another target):
24//!
25//! 1. Select a less specific target.
26//! 2. Enable runtime support.
27//!
28//! If you're writing an application or library that can work with (part of) a
29//! family you can select that instead:
30//!
31//! ``` toml
32//! [dependencies.lpc8xx-hal]
33//! version  = "0.9"
34//! features = ["82x"]
35//! ```
36//!
37//! This selects the LPC82x family. Only the hardware resources available on all
38//! targets within that family will be provided, while the actual target
39//! hardware you're running on might have more peripherals or more memory.
40//!
41//! Again, check out [`Cargo.toml`] for a list of options.
42//!
43//! If you want to use LPC8xx HAL in an application (as opposed to a library),
44//! you probably need to enable runtime support. You can do this by passing
45//! the runtime feature for your selected family:
46//!
47//! ``` toml
48//! [dependencies.lpc8xx-hal]
49//! version  = "0.9"
50//! features = ["824m201jhi33", "82x-rt"]
51//! ```
52//!
53//! Again, the available options are listed in [`Cargo.toml`].
54//!
55//! Please note that LPC8xx HAL is an implementation of [embedded-hal]. If you
56//! are writing code that is not specific to LPC800, please consider depending
57//! on embedded-hal instead.
58//!
59//! That's it! Now you can start using the LPC8xx HAL APIs. Take a look at
60//! [`Peripherals`], which is the entry point to the whole API.
61//!
62//! [`Cargo.toml`]: https://github.com/lpc-rs/lpc8xx-hal/blob/master/Cargo.toml
63//! [`Peripherals`]: struct.Peripherals.html
64//!
65//!
66//! ## Examples
67//!
68//! There are a number of [examples in the repository]. A good place to start is
69//! the [GPIO example].
70//!
71//! If you have an LPCXpresso824-MAX development board connected via USB, you
72//! should be able to run any example like this:
73//!
74//! ``` ignore
75//! cargo run --release --features=82x-rt --example gpio_simple
76//! ```
77//!
78//!
79//! ## Other documentation
80//!
81//! Please refer to the [Embedded Rust Book] for further documentation on how to
82//! use embedded Rust. The book does not use LPC8xx HAL as an example, but most
83//! of what you learn their will transfer over to this crate.
84//!
85//! [Embedded Rust Book]: https://rust-embedded.github.io/book/
86//!
87//!
88//! # References
89//!
90//! Various places in this crate's documentation reference the LPC82x User
91//! manual, which is [available from NXP].
92//!
93//! [embedded-hal]: https://crates.io/crates/embedded-hal
94//! [examples in the repository]: https://github.com/lpc-rs/lpc8xx-hal/tree/master/examples
95//! [GPIO example]: https://github.com/lpc-rs/lpc8xx-hal/blob/master/examples/gpio_delay.rs
96//! [available from NXP]: https://www.nxp.com/docs/en/user-guide/UM10800.pdf
97
98#![cfg_attr(not(test), no_std)]
99#![deny(missing_docs)]
100
101pub extern crate cortex_m;
102#[cfg(feature = "rt-selected")]
103pub extern crate cortex_m_rt;
104pub extern crate embedded_hal;
105pub extern crate embedded_hal_alpha;
106pub extern crate embedded_time;
107pub extern crate nb;
108pub extern crate void;
109
110#[macro_use]
111pub(crate) mod reg_proxy;
112
113pub mod adc;
114pub mod clock;
115#[cfg(feature = "845")]
116pub mod ctimer;
117pub mod delay;
118pub mod dma;
119pub mod gpio;
120pub mod i2c;
121pub mod mrt;
122#[cfg(feature = "845")]
123pub mod pinint;
124pub mod pins;
125pub mod pmu;
126pub mod sleep;
127pub mod spi;
128pub mod swm;
129pub mod syscon;
130pub mod usart;
131pub mod wkt;
132
133/// Re-exports various traits that are required to use lpc8xx-hal
134///
135/// The purpose of this module is to improve convenience, by not requiring the
136/// user to import traits separately. Just add the following to your code, and
137/// you should be good to go:
138///
139/// ``` rust
140/// use lpc8xx_hal::prelude::*;
141/// ```
142///
143/// The traits in this module have been renamed, to avoid collisions with other
144/// imports.
145pub mod prelude {
146    pub use core::fmt::Write as _;
147
148    pub use crate::clock::{Enabled as _, Frequency as _};
149    pub use crate::embedded_hal::{digital::v2::*, prelude::*};
150    pub use crate::sleep::Sleep as _;
151}
152
153#[cfg(feature = "82x")]
154pub use lpc82x_pac as pac;
155#[cfg(feature = "845")]
156pub use lpc845_pac as pac;
157
158pub use self::adc::ADC;
159#[cfg(feature = "845")]
160pub use self::ctimer::CTIMER;
161pub use self::dma::DMA;
162pub use self::gpio::GPIO;
163pub use self::i2c::I2C;
164pub use self::mrt::MRT;
165#[cfg(feature = "845")]
166pub use self::pinint::PININT;
167pub use self::pmu::PMU;
168pub use self::spi::SPI;
169pub use self::swm::SWM;
170pub use self::syscon::SYSCON;
171pub use self::usart::USART;
172pub use self::wkt::WKT;
173
174pub use pac::CorePeripherals;
175
176#[cfg(feature = "845")]
177use ctimer::channel::state::Detached;
178
179/// Provides access to all peripherals
180///
181/// This is the entry point to the HAL API. Before you can do anything else, you
182/// need to get an instance of this struct via [`Peripherals::take`] or
183/// [`Peripherals::steal`].
184///
185/// The HAL API tracks the state of peripherals at compile-time, to prevent
186/// potential bugs before the program can even run. Many parts of this
187/// documentation call this "type state". The peripherals available in this
188/// struct are set to their initial state (i.e. their state after a system
189/// reset). See user manual, section 5.6.14.
190///
191/// # Safe Use of the API
192///
193/// Since it should be impossible (outside of unsafe code) to access the
194/// peripherals before this struct is initialized, you can rely on the
195/// peripheral states being correct, as long as there's no bug in the API, and
196/// you're not using unsafe code to do anything that the HAL API can't account
197/// for.
198///
199/// If you directly use unsafe code to access peripherals or manipulate this
200/// API, this will be really obvious from the code. But please note that if
201/// you're using other APIs to access the hardware, such conflicting hardware
202/// access might not be obvious, as the other API might use unsafe code under
203/// the hood to access the hardware (just like this API does).
204///
205/// If you do access the peripherals in any way not intended by this API, please
206/// make sure you know what you're doing. In specific terms, this means you
207/// should be fully aware of what your code does, and whether that is a valid
208/// use of the hardware.
209///
210/// [`Peripherals::take`]: #method.take
211/// [`Peripherals::steal`]: #method.steal
212#[allow(non_snake_case)]
213pub struct Peripherals {
214    /// Pins that can be used for GPIO or other functions
215    pub pins: pins::Pins,
216
217    /// Analog-to-Digital Converter (ADC)
218    pub ADC: ADC<init_state::Disabled>,
219
220    /// Standard counter/timer (CTIMER)
221    #[cfg(feature = "845")]
222    pub CTIMER0: CTIMER<init_state::Disabled, Detached, Detached, Detached>,
223
224    /// DMA controller
225    pub DMA: DMA<init_state::Disabled>,
226
227    /// General-purpose I/O (GPIO)
228    ///
229    /// By default, the GPIO peripheral is enabled on the LPC82x and disabled on
230    /// the LPC845.
231    #[cfg(feature = "82x")]
232    pub GPIO: GPIO<init_state::Enabled>,
233
234    /// General-purpose I/O (GPIO)
235    ///
236    /// By default, the GPIO peripheral is enabled on the LPC82x and disabled on
237    /// the LPC845.
238    #[cfg(feature = "845")]
239    pub GPIO: GPIO<init_state::Disabled>,
240
241    /// I2C0
242    pub I2C0: I2C<
243        pac::I2C0,
244        init_state::Disabled,
245        init_state::Disabled,
246        init_state::Disabled,
247    >,
248
249    /// I2C1
250    pub I2C1: I2C<
251        pac::I2C1,
252        init_state::Disabled,
253        init_state::Disabled,
254        init_state::Disabled,
255    >,
256
257    /// I2C2
258    pub I2C2: I2C<
259        pac::I2C2,
260        init_state::Disabled,
261        init_state::Disabled,
262        init_state::Disabled,
263    >,
264
265    /// I2C3
266    pub I2C3: I2C<
267        pac::I2C3,
268        init_state::Disabled,
269        init_state::Disabled,
270        init_state::Disabled,
271    >,
272
273    /// Multi-Rate Timer (MRT)
274    pub MRT0: MRT,
275
276    /// Pin interrupt and pattern match engine
277    #[cfg(feature = "845")]
278    pub PININT: PININT<init_state::Disabled>,
279
280    /// Power Management Unit
281    pub PMU: PMU,
282
283    /// SPI0
284    pub SPI0: SPI<pac::SPI0, init_state::Disabled>,
285
286    /// SPI1
287    pub SPI1: SPI<pac::SPI1, init_state::Disabled>,
288
289    /// Switch matrix
290    ///
291    /// By default, the switch matrix is enabled on the LPC82x and disabled on
292    /// the LPC845.
293    ///
294    /// The reference manual for the LPC845 suggests otherwise, but it seems to
295    /// be wrong.
296    #[cfg(feature = "82x")]
297    pub SWM: SWM<init_state::Enabled>,
298
299    /// Switch matrix
300    ///
301    /// By default, the switch matrix is enabled on the LPC82x and disabled on
302    /// the LPC845.
303    ///
304    /// The reference manual for the LPC845 suggests otherwise, but it seems to
305    /// be wrong.
306    #[cfg(feature = "845")]
307    pub SWM: SWM<init_state::Disabled>,
308
309    /// System configuration
310    pub SYSCON: SYSCON,
311
312    /// USART0
313    pub USART0: USART<pac::USART0, init_state::Disabled>,
314
315    /// USART1
316    pub USART1: USART<pac::USART1, init_state::Disabled>,
317
318    /// USART2
319    pub USART2: USART<pac::USART2, init_state::Disabled>,
320
321    #[cfg(feature = "845")]
322    /// USART3
323    ///
324    /// USART3 and PIN_INT6 share an interrupt, this may cause difficulties
325    /// when trying to use both at the same time
326    pub USART3: USART<pac::USART3, init_state::Disabled>,
327
328    #[cfg(feature = "845")]
329    /// USART4
330    ///
331    /// USART4 and PIN_INT7 share an interrupt, this may cause difficulties
332    /// when trying to use both at the same time
333    pub USART4: USART<pac::USART4, init_state::Disabled>,
334
335    /// Self-wake-up timer (WKT)
336    pub WKT: WKT<init_state::Disabled>,
337
338    /// Analog comparator
339    ///
340    /// A HAL API for this peripheral has not been implemented yet. In the
341    /// meantime, this field provides you with the raw register mappings, which
342    /// allow you full, unprotected access to the peripheral.
343    pub ACOMP: pac::ACOMP,
344
345    /// Capacitive Touch (CAPT)
346    ///
347    /// A HAL API for this peripheral has not been implemented yet. In the
348    /// meantime, this field provides you with the raw register mappings, which
349    /// allow you full, unprotected access to the peripheral.
350    #[cfg(feature = "845")]
351    pub CAPT: pac::CAPT,
352
353    /// CRC engine
354    ///
355    /// A HAL API for this peripheral has not been implemented yet. In the
356    /// meantime, this field provides you with the raw register mappings, which
357    /// allow you full, unprotected access to the peripheral.
358    pub CRC: pac::CRC,
359
360    /// Digital-to-Analog Converter 0 (DAC0)
361    ///
362    /// A HAL API for this peripheral has not been implemented yet. In the
363    /// meantime, this field provides you with the raw register mappings, which
364    /// allow you full, unprotected access to the peripheral.
365    #[cfg(feature = "845")]
366    pub DAC0: pac::DAC0,
367
368    /// Digital-to-Analog Converter 1 (DAC1)
369    ///
370    /// A HAL API for this peripheral has not been implemented yet. In the
371    /// meantime, this field provides you with the raw register mappings, which
372    /// allow you full, unprotected access to the peripheral.
373    #[cfg(feature = "845")]
374    pub DAC1: pac::DAC1,
375
376    /// Flash controller
377    ///
378    /// A HAL API for this peripheral has not been implemented yet. In the
379    /// meantime, this field provides you with the raw register mappings, which
380    /// allow you full, unprotected access to the peripheral.
381    pub FLASH_CTRL: pac::FLASH_CTRL,
382
383    /// Input multiplexing
384    ///
385    /// A HAL API for this peripheral has not been implemented yet. In the
386    /// meantime, this field provides you with the raw register mappings, which
387    /// allow you full, unprotected access to the peripheral.
388    pub INPUTMUX: pac::INPUTMUX,
389
390    /// I/O configuration
391    ///
392    /// A HAL API for this peripheral has not been implemented yet. In the
393    /// meantime, this field provides you with the raw register mappings, which
394    /// allow you full, unprotected access to the peripheral.
395    pub IOCON: pac::IOCON,
396
397    /// Pin interrupt and pattern match engine
398    ///
399    /// A HAL API for this peripheral has not been implemented yet for LPC82x. In
400    /// the meantime, this field provides you with the raw register mappings,
401    /// which allow you full, unprotected access to the peripheral.
402    ///
403    /// A HAL API for this peripheral is available for LPC845. Even though the
404    /// peripherals are largely identical on both targets, on LPC82x PININT
405    /// shares a peripheral clock with GPIO, which is not the case on LPC845.
406    /// Porting the API to LPC82x would require additional effort for that
407    /// reason.
408    #[cfg(feature = "82x")]
409    pub PININT: pac::PINT,
410
411    /// State Configurable Timer (SCT)
412    ///
413    /// A HAL API for this peripheral has not been implemented yet. In the
414    /// meantime, this field provides you with the raw register mappings, which
415    /// allow you full, unprotected access to the peripheral.
416    pub SCT0: pac::SCT0,
417
418    /// Windowed Watchdog Timer (WWDT)
419    ///
420    /// A HAL API for this peripheral has not been implemented yet. In the
421    /// meantime, this field provides you with the raw register mappings, which
422    /// allow you full, unprotected access to the peripheral.
423    pub WWDT: pac::WWDT,
424}
425
426impl Peripherals {
427    /// Take the peripherals safely
428    ///
429    /// This method can only be called one time to access the peripherals. It
430    /// will return `Some(Peripherals)` when called for the first time, then
431    /// `None` on any subsequent calls.
432    ///
433    /// Applications should call this method once, at the beginning of their
434    /// main method, to get access to the full API. Any other parts of the
435    /// program should just expect to be passed whatever parts of the HAL API
436    /// they need.
437    ///
438    /// Calling this method from a library is considered an anti-pattern.
439    /// Libraries should just require whatever they need to be passed as
440    /// arguments and leave the initialization to the application that calls
441    /// them.
442    ///
443    /// For an alternative way to gain access to the hardware, please take a
444    /// look at [`Peripherals::steal`].
445    ///
446    /// # Example
447    ///
448    /// ``` no_run
449    /// use lpc8xx_hal::Peripherals;
450    ///
451    /// // This code should be at the beginning of your program. As long as this
452    /// // is the only place that calls `take`, the following should never
453    /// // panic.
454    /// let p = Peripherals::take().unwrap();
455    /// ```
456    pub fn take() -> Option<Self> {
457        Some(Self::new(pac::Peripherals::take()?))
458    }
459
460    /// Steal the peripherals
461    ///
462    /// This function returns an instance of `Peripherals`, whether or not such
463    /// an instance exists somewhere else. This is highly unsafe, as it can lead
464    /// to conflicting access of the hardware, mismatch between actual hardware
465    /// state and peripheral state as tracked by this API at compile-time, and
466    /// in general a full nullification of all safety guarantees that this API
467    /// would normally make.
468    ///
469    /// If at all possible, you should always prefer `Peripherals::take` to this
470    /// method. The only legitimate use of this API is code that can't access
471    /// `Peripherals` the usual way, like a panic handler, or maybe temporary
472    /// debug code in an interrupt handler.
473    ///
474    /// # Safety
475    ///
476    /// This method returns an instance of `Peripherals` that might conflict
477    /// with either other instances of `Peripherals` that exist in the program,
478    /// or other means of accessing the hardware. This is only sure, if you make
479    /// sure of the following:
480    /// 1. No other code can access the hardware at the same time.
481    /// 2. You don't change the hardware state in any way that could invalidate
482    ///    the type state of other `Peripherals` instances.
483    /// 3. The type state in your `Peripherals` instance matches the actual
484    ///    state of the hardware.
485    ///
486    /// Items 1. and 2. are really tricky, so it is recommended to avoid any
487    /// situations where they apply, and restrict the use of this method to
488    /// situations where the program has effectively ended and the hardware will
489    /// be reset right after (like a panic handler).
490    ///
491    /// Item 3. applies to all uses of this method, and is generally very tricky
492    /// to get right. The best way to achieve that is probably to force the API
493    /// into a type state that allows you to execute operations that are known
494    /// to put the hardware in a safe state. Like forcing the type state for a
495    /// peripheral API to the "disabled" state, then enabling it, to make sure
496    /// it is enabled, regardless of whether it was enabled before.
497    ///
498    /// Since there are no means within this API to forcibly change type state,
499    /// you will need to resort to something like [`core::mem::transmute`].
500    pub unsafe fn steal() -> Self {
501        Self::new(pac::Peripherals::steal())
502    }
503
504    fn new(p: pac::Peripherals) -> Self {
505        Peripherals {
506            pins: pins::Pins::new(),
507
508            // HAL peripherals
509            ADC: ADC::new(p.ADC0),
510            #[cfg(feature = "845")]
511            CTIMER0: CTIMER::new(p.CTIMER0),
512            DMA: DMA::new(p.DMA0),
513            GPIO: GPIO::new(p.GPIO),
514            I2C0: I2C::new(p.I2C0),
515            I2C1: I2C::new(p.I2C1),
516            I2C2: I2C::new(p.I2C2),
517            I2C3: I2C::new(p.I2C3),
518            MRT0: MRT::new(p.MRT0),
519            #[cfg(feature = "845")]
520            PININT: PININT::new(p.PINT),
521            PMU: PMU::new(p.PMU),
522            SPI0: SPI::new(p.SPI0),
523            SPI1: SPI::new(p.SPI1),
524            SWM: SWM::new(p.SWM0),
525            SYSCON: SYSCON::new(p.SYSCON),
526            USART0: USART::new(p.USART0),
527            USART1: USART::new(p.USART1),
528            USART2: USART::new(p.USART2),
529            #[cfg(feature = "845")]
530            USART3: USART::new(p.USART3),
531            #[cfg(feature = "845")]
532            USART4: USART::new(p.USART4),
533            WKT: WKT::new(p.WKT),
534
535            // Raw peripherals
536            ACOMP: p.ACOMP,
537            #[cfg(feature = "845")]
538            CAPT: p.CAPT,
539            CRC: p.CRC,
540            #[cfg(feature = "845")]
541            DAC0: p.DAC0,
542            #[cfg(feature = "845")]
543            DAC1: p.DAC1,
544            FLASH_CTRL: p.FLASH_CTRL,
545            INPUTMUX: p.INPUTMUX,
546            IOCON: p.IOCON,
547            #[cfg(feature = "82x")]
548            PININT: p.PINT,
549            SCT0: p.SCT0,
550            WWDT: p.WWDT,
551        }
552    }
553}
554
555/// Contains types that encode the state of hardware initialization
556///
557/// The types in this module are used by structs representing peripherals or
558/// other hardware components, to encode the initialization state of the
559/// underlying hardware as part of the type.
560pub mod init_state {
561    /// Indicates that the hardware component is enabled
562    ///
563    /// This usually indicates that the hardware has been initialized and can be
564    /// used for its intended purpose. Contains an optional payload that APIs
565    /// can use to keep data that is only available while enabled.
566    pub struct Enabled<T = ()>(pub T);
567
568    /// Indicates that the hardware component is disabled
569    pub struct Disabled;
570}
571
572mod private {
573    pub trait Sealed {}
574}