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}