lpc55_hal/
lib.rs

1#![no_std]
2#![allow(static_mut_refs)]
3
4//! This HAL takes a layered approach.
5//!
6//! 1. raw PAC peripherals
7//! 1. HAL peripheral wrappers (under `peripherals`)
8//! 1. HAL drivers (under `drivers`, typically take ownership of one or more peripherals)
9//!
10//! The middle layer is quite thin, notably we model pins and the clock tree
11//! as drivers.
12//!
13//! In as much as possible, it is a goal for this HAL that drivers implement
14//! general interfaces (under `traits`).
15//!
16//! The main intended use case of this HAL is in the context of RTIC.
17//!
18//! To get started without RTIC, try something like:
19//! ```
20//! let hal = hal::Peripherals::take().unwrap(); // layer 2
21//! let pins = hal::Pins::take().unwrap(); // layer 3
22//!
23//! let mut syscon = hal.syscon;
24//! let mut gpio = hal.gpio.enabled(&mut syscon);
25//! let mut iocon = hal.iocon.enabled(&mut syscon);
26//!
27//! let mut red_led = pins.pio1_6
28//!     .into_gpio_pin(&mut iocon, &mut gpio)
29//!     .into_output(Level::High);
30//!
31//! loop {
32//!     red.set_low().unwrap();
33//!     hal::wait_at_least(300_000);
34//!     red.set_high().unwrap();
35//!     hal::wait_at_least(300_000);
36//! }
37//! ```
38
39pub extern crate lpc55_pac as raw;
40
41pub mod prelude;
42
43// #[macro_use]
44pub mod macros;
45
46pub mod time;
47pub mod traits;
48
49pub mod typestates;
50use core::ptr::copy_nonoverlapping;
51
52pub use typestates::init_state::Enabled;
53
54pub mod peripherals;
55pub use peripherals::{
56    adc::Adc, anactrl::Anactrl, casper::Casper, ctimer::Ctimers, dma::Dma, flash::Flash,
57    flexcomm::Flexcomm, gint::Gint, gpio::Gpio, hashcrypt::Hashcrypt, inputmux::InputMux,
58    iocon::Iocon, pfr::Pfr, pint::Pint, pmc::Pmc, prince::Prince, puf::Puf, rng::Rng, rtc::Rtc,
59    syscon::Syscon, usbfs::Usbfs, usbhs::Usbhs, utick::Utick,
60};
61
62pub mod drivers;
63pub use drivers::{ClockRequirements, FlashGordon, I2cMaster, Pin, Pins, SpiMaster, UsbBus};
64
65pub fn new() -> Peripherals {
66    take().unwrap()
67}
68
69/// This is the main (monolithic) entry point to the HAL for non-RTIC applications.
70/// For RTIC, use `hal::<Peripheral>::from(<raw_peripheral>)` as needed.
71pub fn take() -> Option<Peripherals> {
72    Some(Peripherals::from((
73        raw::Peripherals::take()?, //.expect("raw device peripherals already taken elsewhere"),
74        raw::CorePeripherals::take()?, //.expect("raw core peripherals already taken elsewhere"),
75    )))
76}
77
78#[cfg(not(feature = "rtic-peripherals"))]
79pub fn from(raw: (raw::Peripherals, raw::CorePeripherals)) -> Peripherals {
80    Peripherals::from(raw)
81}
82
83#[cfg(feature = "rtic-peripherals")]
84pub fn from(raw: (raw::Peripherals, rtic::Peripherals)) -> Peripherals {
85    Peripherals::from(raw)
86}
87
88/// This is the entry point to the HAL API.
89///
90/// Before you can do anything else, you need to get an instance of this struct,
91/// via `hal::new` or `hal::steal`.
92#[allow(non_snake_case)]
93pub struct Peripherals {
94    /// Analog-to-Digital Converter (ADC)
95    pub adc: Adc,
96
97    /// Analog control
98    pub anactrl: Anactrl,
99
100    /// Cryptographic Accelerator and Signal Processing Engine with RAM sharing
101    pub casper: Casper,
102
103    /// Standard counter/timer (CTIMER)
104    pub ctimer: Ctimers,
105
106    /// Direct memory access
107    pub dma: Dma,
108
109    /// Flash
110    pub flash: Flash,
111
112    /// Flexcomm Interface Serial Communication
113    pub flexcomm: Flexcomm,
114
115    /// Group GPIO Input Interrupt
116    pub gint: Gint,
117
118    /// General-purpose I/O (GPIO)
119    pub gpio: Gpio,
120
121    /// SHA and AES Engine
122    pub hashcrypt: Hashcrypt,
123
124    /// Input multiplexer
125    pub inputmux: InputMux,
126
127    /// I/O configuration
128    pub iocon: Iocon,
129
130    /// Pin Interrupt and Pattern Match
131    pub pint: Pint,
132
133    /// Protect flash region controller
134    pub pfr: Pfr,
135
136    /// Power configuration
137    pub pmc: Pmc,
138
139    // PRINCE
140    pub prince: Prince,
141
142    // PUF
143    pub puf: Puf,
144
145    /// Random number generator
146    pub rng: Rng,
147
148    /// Real time clock
149    pub rtc: Rtc,
150
151    /// System configuration
152    pub syscon: Syscon,
153
154    /// USB full-speed device or, not implemented, host
155    pub usbfs: Usbfs,
156
157    /// USB high-speed device or, not implemented, host
158    pub usbhs: Usbhs,
159
160    /// Micro-Tick Timer
161    pub utick: Utick,
162
163    /// CRC engine - not HAL-ified.
164    pub CRC_ENGINE: raw::CRC_ENGINE,
165
166    pub FLASH_CMPA: raw::FLASH_CMPA,
167    pub FLASH_CFPA0: raw::FLASH_CFPA0,
168
169    /// Stateful counter/timer (SCTIMER) - not HAL-ified.
170    pub SCT0: raw::SCT0,
171
172    /// SAU - not HAL-ified.
173    pub SAU: raw::SAU,
174
175    /// AHB_SECURE_CTRL - not HAL-ified.
176    pub AHB_SECURE_CTRL: raw::AHB_SECURE_CTRL,
177
178    /// CPUID - core peripheral
179    pub CPUID: raw::CPUID,
180
181    /// Debug Control Block (DCB) - core peripheral
182    pub DCB: raw::DCB,
183
184    /// Data Watchpoint and Trace unit (DWT) - core peripheral
185    pub DWT: raw::DWT,
186
187    /// Memory Protection Unit (MPU) - core peripheral
188    pub MPU: raw::MPU,
189
190    /// Nested Vector Interrupt Controller (NVIC) - core peripheral
191    pub NVIC: raw::NVIC,
192
193    /// System Control Block (SCB) - core peripheral
194    pub SCB: raw::SCB,
195
196    /// Watchdog
197    pub wwdt: raw::WWDT,
198
199    #[cfg(not(feature = "rtic-peripherals"))]
200    /// SysTick: System Timer - core peripheral
201    #[cfg(not(feature = "rtic-peripherals"))]
202    pub SYST: raw::SYST,
203}
204
205#[cfg(feature = "rtic-peripherals")]
206impl From<(raw::Peripherals, rtic::Peripherals)> for Peripherals {
207    fn from(raw: (raw::Peripherals, rtic::Peripherals)) -> Self {
208        let cp = raw.1;
209        let p = raw.0;
210        Peripherals {
211            // HAL peripherals
212            adc: Adc::from(p.ADC0),
213            anactrl: Anactrl::from(p.ANACTRL),
214            casper: Casper::from(p.CASPER),
215            ctimer: (
216                peripherals::ctimer::Ctimer0::from(p.CTIMER0),
217                peripherals::ctimer::Ctimer1::from(p.CTIMER1),
218                peripherals::ctimer::Ctimer2::from(p.CTIMER2),
219                peripherals::ctimer::Ctimer3::from(p.CTIMER3),
220                peripherals::ctimer::Ctimer4::from(p.CTIMER4),
221            ),
222            dma: Dma::from(p.DMA0),
223            flash: Flash::from(p.FLASH),
224            flexcomm: (
225                peripherals::flexcomm::Flexcomm0::from((
226                    p.FLEXCOMM0,
227                    p.I2C0,
228                    p.I2S0,
229                    p.SPI0,
230                    p.USART0,
231                )),
232                peripherals::flexcomm::Flexcomm1::from((
233                    p.FLEXCOMM1,
234                    p.I2C1,
235                    p.I2S1,
236                    p.SPI1,
237                    p.USART1,
238                )),
239                peripherals::flexcomm::Flexcomm2::from((
240                    p.FLEXCOMM2,
241                    p.I2C2,
242                    p.I2S2,
243                    p.SPI2,
244                    p.USART2,
245                )),
246                peripherals::flexcomm::Flexcomm3::from((
247                    p.FLEXCOMM3,
248                    p.I2C3,
249                    p.I2S3,
250                    p.SPI3,
251                    p.USART3,
252                )),
253                peripherals::flexcomm::Flexcomm4::from((
254                    p.FLEXCOMM4,
255                    p.I2C4,
256                    p.I2S4,
257                    p.SPI4,
258                    p.USART4,
259                )),
260                peripherals::flexcomm::Flexcomm5::from((
261                    p.FLEXCOMM5,
262                    p.I2C5,
263                    p.I2S5,
264                    p.SPI5,
265                    p.USART5,
266                )),
267                peripherals::flexcomm::Flexcomm6::from((
268                    p.FLEXCOMM6,
269                    p.I2C6,
270                    p.I2S6,
271                    p.SPI6,
272                    p.USART6,
273                )),
274                peripherals::flexcomm::Flexcomm7::from((
275                    p.FLEXCOMM7,
276                    p.I2C7,
277                    p.I2S7,
278                    p.SPI7,
279                    p.USART7,
280                )),
281                peripherals::flexcomm::Flexcomm8::from((p.FLEXCOMM8, p.SPI8)),
282            ),
283            gint: Gint::from((p.GINT0, p.GINT1)),
284            gpio: Gpio::from(p.GPIO),
285            hashcrypt: Hashcrypt::from(p.HASHCRYPT),
286            inputmux: InputMux::from(p.INPUTMUX),
287            iocon: Iocon::from(p.IOCON),
288            pint: Pint::from(p.PINT),
289            pfr: Pfr::new(),
290            pmc: Pmc::from(p.PMC),
291            prince: Prince::from(p.PRINCE),
292            puf: Puf::from(p.PUF),
293            rng: Rng::from(p.RNG),
294            rtc: Rtc::from(p.RTC),
295            syscon: Syscon::from(p.SYSCON),
296            usbfs: Usbfs::from((p.USB0, p.USBFSH)),
297            usbhs: Usbhs::from((p.USBPHY, p.USB1, p.USBHSH)),
298            utick: Utick::from(p.UTICK0),
299
300            // Raw peripherals
301            AHB_SECURE_CTRL: p.AHB_SECURE_CTRL,
302            CRC_ENGINE: p.CRC_ENGINE,
303            FLASH_CMPA: p.FLASH_CMPA,
304            FLASH_CFPA0: p.FLASH_CFPA0,
305            SAU: p.SAU,
306            SCT0: p.SCT0,
307
308            // Core peripherals
309            CPUID: cp.CPUID,
310            DCB: cp.DCB,
311            DWT: cp.DWT,
312            MPU: cp.MPU,
313            NVIC: cp.NVIC,
314            SCB: cp.SCB,
315        }
316    }
317}
318
319impl From<(raw::Peripherals, raw::CorePeripherals)> for Peripherals {
320    fn from(raw: (raw::Peripherals, raw::CorePeripherals)) -> Self {
321        let cp = raw.1;
322        let p = raw.0;
323        Peripherals {
324            // HAL peripherals
325            adc: Adc::from(p.ADC0),
326            anactrl: Anactrl::from(p.ANACTRL),
327            casper: Casper::from(p.CASPER),
328
329            ctimer: (
330                peripherals::ctimer::Ctimer0::from(p.CTIMER0),
331                peripherals::ctimer::Ctimer1::from(p.CTIMER1),
332                peripherals::ctimer::Ctimer2::from(p.CTIMER2),
333                peripherals::ctimer::Ctimer3::from(p.CTIMER3),
334                peripherals::ctimer::Ctimer4::from(p.CTIMER4),
335            ),
336            dma: Dma::from(p.DMA0),
337            flash: Flash::from(p.FLASH),
338            flexcomm: (
339                peripherals::flexcomm::Flexcomm0::from((
340                    p.FLEXCOMM0,
341                    p.I2C0,
342                    p.I2S0,
343                    p.SPI0,
344                    p.USART0,
345                )),
346                peripherals::flexcomm::Flexcomm1::from((
347                    p.FLEXCOMM1,
348                    p.I2C1,
349                    p.I2S1,
350                    p.SPI1,
351                    p.USART1,
352                )),
353                peripherals::flexcomm::Flexcomm2::from((
354                    p.FLEXCOMM2,
355                    p.I2C2,
356                    p.I2S2,
357                    p.SPI2,
358                    p.USART2,
359                )),
360                peripherals::flexcomm::Flexcomm3::from((
361                    p.FLEXCOMM3,
362                    p.I2C3,
363                    p.I2S3,
364                    p.SPI3,
365                    p.USART3,
366                )),
367                peripherals::flexcomm::Flexcomm4::from((
368                    p.FLEXCOMM4,
369                    p.I2C4,
370                    p.I2S4,
371                    p.SPI4,
372                    p.USART4,
373                )),
374                peripherals::flexcomm::Flexcomm5::from((
375                    p.FLEXCOMM5,
376                    p.I2C5,
377                    p.I2S5,
378                    p.SPI5,
379                    p.USART5,
380                )),
381                peripherals::flexcomm::Flexcomm6::from((
382                    p.FLEXCOMM6,
383                    p.I2C6,
384                    p.I2S6,
385                    p.SPI6,
386                    p.USART6,
387                )),
388                peripherals::flexcomm::Flexcomm7::from((
389                    p.FLEXCOMM7,
390                    p.I2C7,
391                    p.I2S7,
392                    p.SPI7,
393                    p.USART7,
394                )),
395                peripherals::flexcomm::Flexcomm8::from((p.FLEXCOMM8, p.SPI8)),
396            ),
397            gint: Gint::from((p.GINT0, p.GINT1)),
398            gpio: Gpio::from(p.GPIO),
399            hashcrypt: Hashcrypt::from(p.HASHCRYPT),
400            inputmux: InputMux::from(p.INPUTMUX),
401            iocon: Iocon::from(p.IOCON),
402            pint: Pint::from(p.PINT),
403            pfr: Pfr::new(),
404            pmc: Pmc::from(p.PMC),
405            prince: Prince::from(p.PRINCE),
406            puf: Puf::from(p.PUF),
407            rng: Rng::from(p.RNG),
408            rtc: Rtc::from(p.RTC),
409            syscon: Syscon::from(p.SYSCON),
410            usbfs: Usbfs::from((p.USB0, p.USBFSH)),
411            usbhs: Usbhs::from((p.USBPHY, p.USB1, p.USBHSH)),
412            utick: Utick::from(p.UTICK0),
413
414            // Raw peripherals
415            AHB_SECURE_CTRL: p.AHB_SECURE_CTRL,
416            CRC_ENGINE: p.CRC_ENGINE,
417            FLASH_CMPA: p.FLASH_CMPA,
418            FLASH_CFPA0: p.FLASH_CFPA0,
419            SAU: p.SAU,
420            SCT0: p.SCT0,
421            wwdt: p.WWDT,
422
423            // Core peripherals
424            CPUID: cp.CPUID,
425            DCB: cp.DCB,
426            DWT: cp.DWT,
427            MPU: cp.MPU,
428            NVIC: cp.NVIC,
429            SCB: cp.SCB,
430            #[cfg(not(feature = "rtic-peripherals"))]
431            SYST: cp.SYST,
432        }
433    }
434}
435
436impl Peripherals {
437    #[cfg(not(feature = "rtic-peripherals"))]
438    pub fn take() -> Option<Self> {
439        Some(Self::from((
440            raw::Peripherals::take()?,
441            raw::CorePeripherals::take()?,
442        )))
443    }
444
445    // rtic::Peripherals::take does not exist
446    //
447    // #[cfg(feature = "rtic-peripherals")]
448    // pub fn take() -> Option<Self> {
449    //     Some(Self::from((
450    //         raw::Peripherals::take()?,
451    //         rtic::Peripherals::take()?,
452    //     )))
453    // }
454
455    #[cfg(not(feature = "rtic-peripherals"))]
456    /// # Safety
457    ///
458    /// Steals peripherals, must not be used if one of the peripherals
459    /// is already owned
460    pub unsafe fn steal() -> Self {
461        Self::from((raw::Peripherals::steal(), raw::CorePeripherals::steal()))
462    }
463}
464
465pub fn enable_cycle_counter() {
466    unsafe { &mut raw::CorePeripherals::steal().DWT }.enable_cycle_counter();
467}
468
469pub fn get_cycle_count() -> u32 {
470    raw::DWT::cycle_count()
471}
472
473pub fn count_cycles<Output>(f: impl FnOnce() -> Output) -> (u32, Output) {
474    let before = get_cycle_count();
475    let outcome = f();
476    let after = get_cycle_count();
477    (after - before, outcome)
478}
479
480/// Delay of last resort :-))
481pub fn wait_at_least(delay_usecs: u32) {
482    enable_cycle_counter();
483    let max_cpu_speed = 150_000_000; // via PLL
484    let period = max_cpu_speed / 1_000_000;
485
486    let current = get_cycle_count() as u64;
487    let mut target = current + period as u64 * delay_usecs as u64;
488    if target > 0xFFFF_FFFF {
489        // wait for wraparound
490        target -= 0xFFFF_FFFF;
491        while target < get_cycle_count() as u64 {
492            continue;
493        }
494    }
495    while target > get_cycle_count() as u64 {
496        continue;
497    }
498}
499
500/// https://community.nxp.com/t5/LPC-Microcontrollers-Knowledge/Understanding-LPC55S6x-Revisions-and-Tools/ta-p/1117604
501///
502/// Note that: EVK A1 = chip 0A, EVK A2 = chip 1B
503pub fn chip_revision() -> &'static str {
504    const DIEID: *const u8 = 0x5000_0FFC as _;
505    let rev_id: u8 = 0xFu8 & unsafe { core::ptr::read_volatile(DIEID) };
506    match rev_id {
507        0 => "0A",
508        1 => "1B",
509        _ => "unknown",
510    }
511}
512
513pub fn uuid() -> [u8; 16] {
514    const UUID: *const u8 = 0x0009_FC70 as _;
515    let mut uuid: [u8; 16] = [0; 16];
516    unsafe {
517        copy_nonoverlapping(UUID, uuid.as_mut_ptr(), 16);
518    }
519    uuid
520}
521
522/// This is a hack to jump to the bootrom without needing to assert ISP pin
523/// or destroy current firmware.
524///
525/// 1. Resets all peripherals & disconnect all interrupts (like in a soft reset)
526/// 2. Enable Iocon and set the INVERT attribute for Pio0_5 (ISP pin).
527/// 3. Jump to bootrom, which will think ISP pin is asserted.
528///
529/// Other prerequisites for this to work:
530/// - Must not be called from an interrupt handler.
531/// - TrustZone must not be disabled (unless you can find a way to re-enable it here).
532pub fn boot_to_bootrom() -> ! {
533    // Disconnect all interrupts
534    cortex_m::interrupt::disable();
535    let core_peripherals = unsafe { cortex_m::peripheral::Peripherals::steal() };
536    unsafe {
537        core_peripherals.NVIC.icer[0].write(0xFFFF_FFFFu32);
538        core_peripherals.NVIC.icer[1].write(0xFFFF_FFFFu32);
539        cortex_m::interrupt::enable();
540    }
541
542    // Release everything from reset
543    let mut syscon = unsafe { Syscon::reset_all_noncritical_peripherals() };
544
545    // Now we just INVERT pio0_5 before jumping
546    let iocon = unsafe { Iocon::steal() }.enabled(&mut syscon).release();
547    iocon
548        .pio0_5
549        .modify(|_, w| w.invert().set_bit().digimode().digital());
550
551    // Jump to bootrom
552    unsafe { cortex_m::asm::bootload(0x03000000 as *const u32) }
553}