Skip to main content

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/// This is the entry point to the HAL API.
79///
80/// Before you can do anything else, you need to get an instance of this struct,
81/// via `hal::new` or `hal::steal`.
82#[allow(non_snake_case)]
83pub struct Peripherals {
84    /// Analog-to-Digital Converter (ADC)
85    pub adc: Adc,
86
87    /// Analog control
88    pub anactrl: Anactrl,
89
90    /// Cryptographic Accelerator and Signal Processing Engine with RAM sharing
91    pub casper: Casper,
92
93    /// Standard counter/timer (CTIMER)
94    pub ctimer: Ctimers,
95
96    /// Direct memory access
97    pub dma: Dma,
98
99    /// Flash
100    pub flash: Flash,
101
102    /// Flexcomm Interface Serial Communication
103    pub flexcomm: Flexcomm,
104
105    /// Group GPIO Input Interrupt
106    pub gint: Gint,
107
108    /// General-purpose I/O (GPIO)
109    pub gpio: Gpio,
110
111    /// SHA and AES Engine
112    pub hashcrypt: Hashcrypt,
113
114    /// Input multiplexer
115    pub inputmux: InputMux,
116
117    /// I/O configuration
118    pub iocon: Iocon,
119
120    /// Pin Interrupt and Pattern Match
121    pub pint: Pint,
122
123    /// Protect flash region controller
124    pub pfr: Pfr,
125
126    /// Power configuration
127    pub pmc: Pmc,
128
129    // PRINCE
130    pub prince: Prince,
131
132    // PUF
133    pub puf: Puf,
134
135    /// Random number generator
136    pub rng: Rng,
137
138    /// Real time clock
139    pub rtc: Rtc,
140
141    /// System configuration
142    pub syscon: Syscon,
143
144    /// USB full-speed device or, not implemented, host
145    pub usbfs: Usbfs,
146
147    /// USB high-speed device or, not implemented, host
148    pub usbhs: Usbhs,
149
150    /// Micro-Tick Timer
151    pub utick: Utick,
152
153    /// CRC engine - not HAL-ified.
154    pub CRC_ENGINE: raw::CRC_ENGINE,
155
156    pub FLASH_CMPA: raw::FLASH_CMPA,
157    pub FLASH_CFPA0: raw::FLASH_CFPA0,
158
159    /// Stateful counter/timer (SCTIMER) - not HAL-ified.
160    pub SCT0: raw::SCT0,
161
162    /// SAU - not HAL-ified.
163    pub SAU: raw::SAU,
164
165    /// AHB_SECURE_CTRL - not HAL-ified.
166    pub AHB_SECURE_CTRL: raw::AHB_SECURE_CTRL,
167
168    /// CPUID - core peripheral
169    pub CPUID: raw::CPUID,
170
171    /// Debug Control Block (DCB) - core peripheral
172    pub DCB: raw::DCB,
173
174    /// Data Watchpoint and Trace unit (DWT) - core peripheral
175    pub DWT: raw::DWT,
176
177    /// Memory Protection Unit (MPU) - core peripheral
178    pub MPU: raw::MPU,
179
180    /// Nested Vector Interrupt Controller (NVIC) - core peripheral
181    pub NVIC: raw::NVIC,
182
183    /// System Control Block (SCB) - core peripheral
184    pub SCB: raw::SCB,
185
186    /// Watchdog
187    pub wwdt: raw::WWDT,
188
189    /// SysTick: System Timer - core peripheral
190    pub SYST: raw::SYST,
191}
192
193impl From<(raw::Peripherals, raw::CorePeripherals)> for Peripherals {
194    fn from(raw: (raw::Peripherals, raw::CorePeripherals)) -> Self {
195        let cp = raw.1;
196        let p = raw.0;
197        Peripherals {
198            // HAL peripherals
199            adc: Adc::from(p.ADC0),
200            anactrl: Anactrl::from(p.ANACTRL),
201            casper: Casper::from(p.CASPER),
202
203            ctimer: (
204                peripherals::ctimer::Ctimer0::from(p.CTIMER0),
205                peripherals::ctimer::Ctimer1::from(p.CTIMER1),
206                peripherals::ctimer::Ctimer2::from(p.CTIMER2),
207                peripherals::ctimer::Ctimer3::from(p.CTIMER3),
208                peripherals::ctimer::Ctimer4::from(p.CTIMER4),
209            ),
210            dma: Dma::from(p.DMA0),
211            flash: Flash::from(p.FLASH),
212            flexcomm: (
213                peripherals::flexcomm::Flexcomm0::from((
214                    p.FLEXCOMM0,
215                    p.I2C0,
216                    p.I2S0,
217                    p.SPI0,
218                    p.USART0,
219                )),
220                peripherals::flexcomm::Flexcomm1::from((
221                    p.FLEXCOMM1,
222                    p.I2C1,
223                    p.I2S1,
224                    p.SPI1,
225                    p.USART1,
226                )),
227                peripherals::flexcomm::Flexcomm2::from((
228                    p.FLEXCOMM2,
229                    p.I2C2,
230                    p.I2S2,
231                    p.SPI2,
232                    p.USART2,
233                )),
234                peripherals::flexcomm::Flexcomm3::from((
235                    p.FLEXCOMM3,
236                    p.I2C3,
237                    p.I2S3,
238                    p.SPI3,
239                    p.USART3,
240                )),
241                peripherals::flexcomm::Flexcomm4::from((
242                    p.FLEXCOMM4,
243                    p.I2C4,
244                    p.I2S4,
245                    p.SPI4,
246                    p.USART4,
247                )),
248                peripherals::flexcomm::Flexcomm5::from((
249                    p.FLEXCOMM5,
250                    p.I2C5,
251                    p.I2S5,
252                    p.SPI5,
253                    p.USART5,
254                )),
255                peripherals::flexcomm::Flexcomm6::from((
256                    p.FLEXCOMM6,
257                    p.I2C6,
258                    p.I2S6,
259                    p.SPI6,
260                    p.USART6,
261                )),
262                peripherals::flexcomm::Flexcomm7::from((
263                    p.FLEXCOMM7,
264                    p.I2C7,
265                    p.I2S7,
266                    p.SPI7,
267                    p.USART7,
268                )),
269                peripherals::flexcomm::Flexcomm8::from((p.FLEXCOMM8, p.SPI8)),
270            ),
271            gint: Gint::from((p.GINT0, p.GINT1)),
272            gpio: Gpio::from(p.GPIO),
273            hashcrypt: Hashcrypt::from(p.HASHCRYPT),
274            inputmux: InputMux::from(p.INPUTMUX),
275            iocon: Iocon::from(p.IOCON),
276            pint: Pint::from(p.PINT),
277            pfr: Pfr::new(),
278            pmc: Pmc::from(p.PMC),
279            prince: Prince::from(p.PRINCE),
280            puf: Puf::from(p.PUF),
281            rng: Rng::from(p.RNG),
282            rtc: Rtc::from(p.RTC),
283            syscon: Syscon::from(p.SYSCON),
284            usbfs: Usbfs::from((p.USB0, p.USBFSH)),
285            usbhs: Usbhs::from((p.USBPHY, p.USB1, p.USBHSH)),
286            utick: Utick::from(p.UTICK0),
287
288            // Raw peripherals
289            AHB_SECURE_CTRL: p.AHB_SECURE_CTRL,
290            CRC_ENGINE: p.CRC_ENGINE,
291            FLASH_CMPA: p.FLASH_CMPA,
292            FLASH_CFPA0: p.FLASH_CFPA0,
293            SAU: p.SAU,
294            SCT0: p.SCT0,
295            wwdt: p.WWDT,
296
297            // Core peripherals
298            CPUID: cp.CPUID,
299            DCB: cp.DCB,
300            DWT: cp.DWT,
301            MPU: cp.MPU,
302            NVIC: cp.NVIC,
303            SCB: cp.SCB,
304            SYST: cp.SYST,
305        }
306    }
307}
308
309impl Peripherals {
310    pub fn take() -> Option<Self> {
311        Some(Self::from((
312            raw::Peripherals::take()?,
313            raw::CorePeripherals::take()?,
314        )))
315    }
316
317    /// # Safety
318    ///
319    /// Steals peripherals, must not be used if one of the peripherals
320    /// is already owned
321    pub unsafe fn steal() -> Self {
322        Self::from((raw::Peripherals::steal(), raw::CorePeripherals::steal()))
323    }
324}
325
326pub fn enable_cycle_counter() {
327    unsafe { &mut raw::CorePeripherals::steal().DWT }.enable_cycle_counter();
328}
329
330pub fn get_cycle_count() -> u32 {
331    raw::DWT::cycle_count()
332}
333
334pub fn count_cycles<Output>(f: impl FnOnce() -> Output) -> (u32, Output) {
335    let before = get_cycle_count();
336    let outcome = f();
337    let after = get_cycle_count();
338    (after - before, outcome)
339}
340
341/// Delay of last resort :-))
342pub fn wait_at_least(delay_usecs: u32) {
343    enable_cycle_counter();
344    let max_cpu_speed = 150_000_000; // via PLL
345    let period = max_cpu_speed / 1_000_000;
346
347    let current = get_cycle_count() as u64;
348    let mut target = current + period as u64 * delay_usecs as u64;
349    if target > 0xFFFF_FFFF {
350        // wait for wraparound
351        target -= 0xFFFF_FFFF;
352        while target < get_cycle_count() as u64 {
353            continue;
354        }
355    }
356    while target > get_cycle_count() as u64 {
357        continue;
358    }
359}
360
361/// https://community.nxp.com/t5/LPC-Microcontrollers-Knowledge/Understanding-LPC55S6x-Revisions-and-Tools/ta-p/1117604
362///
363/// Note that: EVK A1 = chip 0A, EVK A2 = chip 1B
364pub fn chip_revision() -> &'static str {
365    const DIEID: *const u8 = 0x5000_0FFC as _;
366    let rev_id: u8 = 0xFu8 & unsafe { core::ptr::read_volatile(DIEID) };
367    match rev_id {
368        0 => "0A",
369        1 => "1B",
370        _ => "unknown",
371    }
372}
373
374pub fn uuid() -> [u8; 16] {
375    const UUID: *const u8 = 0x0009_FC70 as _;
376    let mut uuid: [u8; 16] = [0; 16];
377    unsafe {
378        copy_nonoverlapping(UUID, uuid.as_mut_ptr(), 16);
379    }
380    uuid
381}
382
383/// This is a hack to jump to the bootrom without needing to assert ISP pin
384/// or destroy current firmware.
385///
386/// 1. Resets all peripherals & disconnect all interrupts (like in a soft reset)
387/// 2. Enable Iocon and set the INVERT attribute for Pio0_5 (ISP pin).
388/// 3. Jump to bootrom, which will think ISP pin is asserted.
389///
390/// Other prerequisites for this to work:
391/// - Must not be called from an interrupt handler.
392/// - TrustZone must not be disabled (unless you can find a way to re-enable it here).
393pub fn boot_to_bootrom() -> ! {
394    // Disconnect all interrupts
395    cortex_m::interrupt::disable();
396    let core_peripherals = unsafe { cortex_m::peripheral::Peripherals::steal() };
397    unsafe {
398        core_peripherals.NVIC.icer[0].write(0xFFFF_FFFFu32);
399        core_peripherals.NVIC.icer[1].write(0xFFFF_FFFFu32);
400        cortex_m::interrupt::enable();
401    }
402
403    // Release everything from reset
404    let mut syscon = unsafe { Syscon::reset_all_noncritical_peripherals() };
405
406    // Now we just INVERT pio0_5 before jumping
407    let iocon = unsafe { Iocon::steal() }.enabled(&mut syscon).release();
408    iocon
409        .pio0_5
410        .modify(|_, w| w.invert().set_bit().digimode().digital());
411
412    // Jump to bootrom
413    unsafe { cortex_m::asm::bootload(0x03000000 as *const u32) }
414}