Skip to main content

embassy_neorv32/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3pub mod dma;
4#[cfg(feature = "dual-hart")]
5pub mod dual_hart;
6pub mod gpio;
7pub mod interrupts;
8pub mod pwm;
9pub mod spi;
10pub mod sysinfo;
11#[cfg(feature = "time-driver")]
12mod time_driver;
13pub mod trng;
14pub mod twi;
15pub mod uart;
16pub mod wdt;
17
18// Peripherals and interrupts supported by the NEORV32 chip
19mod chip {
20    #[rustfmt::skip]
21    embassy_hal_internal::peripherals!(
22        HART1,
23        WDT,
24        UART0, UART1,
25        TRNG,
26        DMA,
27        SPI,
28        TWI,
29        GPIO,
30        PORT0, PORT1, PORT2, PORT3, PORT4, PORT5, PORT6, PORT7,
31        PORT8, PORT9, PORT10, PORT11, PORT12, PORT13, PORT14, PORT15,
32        PORT16, PORT17, PORT18, PORT19, PORT20, PORT21, PORT22, PORT23,
33        PORT24, PORT25, PORT26, PORT27, PORT28, PORT29, PORT30, PORT31,
34        PWM,
35        PWMCHAN0, PWMCHAN1, PWMCHAN2, PWMCHAN3, PWMCHAN4, PWMCHAN5, PWMCHAN6, PWMCHAN7,
36        PWMCHAN8, PWMCHAN9, PWMCHAN10, PWMCHAN11, PWMCHAN12, PWMCHAN13, PWMCHAN14, PWMCHAN15,
37        PWMCHAN16, PWMCHAN17, PWMCHAN18, PWMCHAN19, PWMCHAN20, PWMCHAN21, PWMCHAN22, PWMCHAN23,
38        PWMCHAN24, PWMCHAN25, PWMCHAN26, PWMCHAN27, PWMCHAN28, PWMCHAN29, PWMCHAN30, PWMCHAN31,
39    );
40    pub mod interrupts {
41        crate::interrupt_mod!(UART0, UART1, TRNG, DMA, GPIO, SPI);
42    }
43}
44
45pub use chip::{Peripherals, interrupts::*, peripherals};
46pub use neorv32_pac as pac;
47
48/// Initialize the HAL. This must only be called from hart 0.
49///
50/// # Panics
51///
52/// Panics if this has already been called once before or not called from hart 0.
53///
54/// Panics if `time-driver` feature is enabled but `CLINT` is not supported.
55pub fn init() -> Peripherals {
56    // Attempt to take first so we panic before doing anything else
57    let p = Peripherals::take();
58
59    // In dual-hart, global interrupts are enabled in hart_main()
60    // So for single-hart just enable them now
61    // SAFETY: We're not worried about breaking any critical sections here
62    #[cfg(feature = "single-hart")]
63    unsafe {
64        riscv::interrupt::enable()
65    }
66
67    #[cfg(feature = "time-driver")]
68    time_driver::init();
69
70    p
71}
72
73/// The motivation for this macro is that due to neorv32 constraints, several peripherals need
74/// to disable the peripheral interrupt in their IRQ handler for proper async behavior.
75///
76/// The driver then needs to re-enable the interrupt on wake. The HALs are designed to not require
77/// an Instance generic as part of the struct for ergonomic purposes, so we need to explicitly list
78/// the peripheral name.
79///
80/// Currently this is fine since the neorv32 only supports single instances of
81/// the peripherals where this is used, but may need revisiting if that ever changes in the future.
82macro_rules! enable_periph_irq {
83    ($periph:ident) => {{ <$crate::peripherals::$periph as Instance>::Interrupt::enable() }};
84}
85pub(crate) use enable_periph_irq;