1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! HAL for the RP2040 microcontroller
//!
//! This is an implementation of the [`embedded-hal`](https://crates.io/crates/embedded-hal)
//! traits for the RP2040 microcontroller
//!
//! NOTE This HAL is still under active development. This API will remain volatile until 1.0.0
//!
//! # Crate features
//!
//! * **chrono** -
//!   Add conversion functions between chrono types and the rp2040-hal specific DateTime type
//! * **critical-section-impl** -
//!   critical section that is safe for multicore use
//! * **defmt** -
//!   Implement `defmt::Format` for several types.
//! * **disable-intrinsics** -
//!   Disable automatic mapping of language features (like floating point math) to ROM functions
//! * **embedded_hal_1** -
//!   Support alpha release of embedded-hal
//! * **rom-func-cache** -
//!   Memoize(cache) ROM function pointers on first use to improve performance
//! * **rt** -
//!   Minimal startup / runtime for Cortex-M microcontrollers
//! * **rom-v2-intrinsics** -
//!   This enables ROM functions for f64 math that were not present in the earliest RP2040s
//! * **rp2040-e5** -
//!   This enables a fix for USB errata 5: USB device fails to exit RESET state on busy USB bus.
//!   Only required for RP2040 B0 and RP2040 B1, but it also works for RP2040 B2 and above.
//!   **Note that the workaround takes control of pin 15 (bank0) during usb reset so the bank needs
//!   to be taken out of reset before calling `UsbBus::new`**.
//!   Using `let pins = Pins::new(peripherals.IO_BANK0, peripherals.PADS_BANK0, sio.gpio_bank0, &mut peripherals.RESETS);`
//!   is enough to take the Bank 0 out of reset.
//! * **rtic-monotonic** -
//!   Implement
//!   `rtic_monotonic::Monotonic` based on the RP2040 timer peripheral
//! * **i2c-write-iter** -
//!   Implement `i2c_write_iter` traits for `I2C<_, _, Controller>`.

#![warn(missing_docs)]
#![no_std]

#[doc(hidden)]
pub use paste;

/// Re-export of the PAC
pub use rp2040_pac as pac;

#[macro_use]
mod intrinsics;

pub mod adc;
#[macro_use]
pub mod async_utils;
pub(crate) mod atomic_register_access;
pub mod clocks;
#[cfg(feature = "critical-section-impl")]
mod critical_section_impl;
pub mod dma;
mod float;
pub mod gpio;
pub mod i2c;
pub mod multicore;
pub mod pio;
pub mod pll;
pub mod prelude;
pub mod pwm;
pub mod resets;
pub mod rom_data;
pub mod rosc;
pub mod rtc;
pub mod sio;
pub mod spi;
pub mod ssi;
pub mod timer;
pub mod typelevel;
pub mod uart;
pub mod usb;
pub mod vector_table;
pub mod vreg;
pub mod watchdog;
pub mod xosc;

// Provide access to common datastructures to avoid repeating ourselves
pub use adc::Adc;
pub use clocks::Clock;
pub use i2c::I2C;
/// Attribute to declare the entry point of the program
///
/// This is based on and can be used like the [entry attribute from
/// cortex-m-rt](https://docs.rs/cortex-m-rt/latest/cortex_m_rt/attr.entry.html).
///
/// It extends that macro with code to unlock all spinlocks at the beginning
/// of `main`. As spinlocks are not automatically unlocked on software resets,
/// this can prevent unexpected deadlocks when running from a debugger.
pub use rp2040_hal_macros::entry;
use sio::CoreId;
pub use sio::Sio;
pub use spi::Spi;
pub use timer::Timer;
pub use watchdog::Watchdog;
// Re-export crates used in rp2040-hal's public API
pub extern crate fugit;

/// Trigger full reset of the RP2040.
///
/// Uses the watchdog and the power-on state machine (PSM) to reset all on-chip components.
pub fn reset() -> ! {
    unsafe {
        cortex_m::interrupt::disable();
        (*pac::PSM::PTR).wdsel().write(|w| w.bits(0x0001ffff));
        (*pac::WATCHDOG::PTR)
            .ctrl()
            .write(|w| w.trigger().set_bit());
        #[allow(clippy::empty_loop)]
        loop {}
    }
}

/// Halt the RP2040.
///
/// Disables the other core, and parks the current core in an
/// infinite loop with interrupts disabled.
///
/// Doesn't stop other subsystems, like the DMA controller.
///
/// When called from core1, core0 will be kept forced off, which
/// likely breaks debug connections. You may need to reboot with
/// BOOTSEL pressed to reboot into a debuggable state.
pub fn halt() -> ! {
    unsafe {
        cortex_m::interrupt::disable();
        // Stop other core
        match crate::Sio::core() {
            CoreId::Core0 => {
                // Stop core 1.
                (*pac::PSM::PTR)
                    .frce_off()
                    .modify(|_, w| w.proc1().set_bit());
                while !(*pac::PSM::PTR).frce_off().read().proc1().bit_is_set() {
                    cortex_m::asm::nop();
                }
                // Restart core 1. Without this, most debuggers will fail connecting.
                // It will loop indefinitely in BOOTROM, as nothing
                // will trigger the wakeup sequence.
                (*pac::PSM::PTR)
                    .frce_off()
                    .modify(|_, w| w.proc1().clear_bit());
            }
            CoreId::Core1 => {
                // Stop core 0.
                (*pac::PSM::PTR)
                    .frce_off()
                    .modify(|_, w| w.proc0().set_bit());
                // We cannot restart core 0 here, as it would just boot into main.
                // So the best we can do is to keep core 0 disabled, which may break
                // further debug connections.
            }
        };

        // Keep current core running, so debugging stays possible
        loop {
            cortex_m::asm::wfe()
        }
    }
}