RKTK API Docs RKTK Home Repo

rktk_drivers_nrf/
sdc.rs

1use embassy_nrf::interrupt::typelevel::{Binding, Interrupt};
2use embassy_nrf::peripherals::RNG;
3use embassy_nrf::rng::{InterruptHandler, Rng};
4use embassy_nrf::{interrupt, rng};
5use nrf_sdc::mpsl::{
6    ClockInterruptHandler, HighPrioInterruptHandler, LowPrioInterruptHandler,
7    MultiprotocolServiceLayer,
8};
9use nrf_sdc::{self as sdc, mpsl};
10use rktk::singleton;
11use static_cell::StaticCell;
12
13pub use mpsl::Peripherals as MpslPeripherals;
14pub use sdc::Peripherals as SdcPeripherals;
15
16#[derive(Debug)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum SdcInitError {
19    Mpsl(mpsl::Error),
20    Sdc(sdc::Error),
21}
22
23#[macro_export]
24macro_rules! init_sdc {
25    (
26        $sdc_name:ident,
27        $irqs:expr,
28        $rng:expr,
29        mpsl: ($rtc0:expr, $timer0:expr, $temp:expr, $ppi1:expr, $ppi2:expr, $ppi3:expr),
30        sdc: ($ppis1:expr,$ppis2:expr,$ppis3:expr,$ppis4:expr,$ppis5:expr,$ppis6:expr,$ppis7:expr,$ppis8:expr,$ppis9:expr,$ppis10:expr,$ppis11:expr,$ppis12:expr),
31        mtu: $l2cap_mtu:expr,
32        txq: $l2cap_txq:expr,
33        rxq: $l2cap_rxq:expr
34    ) => {
35        let __mpsl_p =
36            $crate::sdc::MpslPeripherals::new($rtc0, $timer0, $temp, $ppi1, $ppi2, $ppi3);
37        let __sdc_p = $crate::sdc::SdcPeripherals::new(
38            $ppis1, $ppis2, $ppis3, $ppis4, $ppis5, $ppis6, $ppis7, $ppis8, $ppis9, $ppis10,
39            $ppis11, $ppis12,
40        );
41        let $sdc_name = $crate::sdc::init_sdc(
42            __mpsl_p, __sdc_p, $rng, $l2cap_mtu, $l2cap_txq, $l2cap_rxq, $irqs,
43        )
44        .await;
45    };
46}
47
48#[embassy_executor::task]
49async fn mpsl_task(mpsl: &'static MultiprotocolServiceLayer<'static>) -> ! {
50    mpsl.run().await
51}
52
53/// Initialize softdevice controller(sdc) and starts mpsl task.
54///
55/// This function must be called only once.
56pub async fn init_sdc<
57    T: Interrupt,
58    I: Binding<T, LowPrioInterruptHandler>
59        + Binding<interrupt::typelevel::RADIO, HighPrioInterruptHandler>
60        + Binding<interrupt::typelevel::TIMER0, HighPrioInterruptHandler>
61        + Binding<interrupt::typelevel::RTC0, HighPrioInterruptHandler>
62        + Binding<interrupt::typelevel::CLOCK_POWER, ClockInterruptHandler>
63        + Binding<interrupt::typelevel::RNG, InterruptHandler<RNG>>
64        + 'static
65        + Clone,
66    PR: rng::Instance,
67>(
68    mpsl_peripherals: mpsl::Peripherals<'static>,
69    sdc_peripherals: sdc::Peripherals<'static>,
70    rng: &'static mut Rng<'static, PR>,
71    l2cap_mtu: u8,
72    l2cap_txq: u8,
73    l2cap_rxq: u8,
74    irqs: I,
75) -> Result<nrf_sdc::SoftdeviceController<'static>, mpsl::Error> {
76    let lfclk_cfg = mpsl::raw::mpsl_clock_lfclk_cfg_t {
77        source: mpsl::raw::MPSL_CLOCK_LF_SRC_RC as u8,
78        rc_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_CTIV as u8,
79        rc_temp_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_TEMP_CTIV as u8,
80        accuracy_ppm: mpsl::raw::MPSL_DEFAULT_CLOCK_ACCURACY_PPM as u16,
81        skip_wait_lfclk_started: mpsl::raw::MPSL_DEFAULT_SKIP_WAIT_LFCLK_STARTED != 0,
82    };
83    static MPSL: StaticCell<MultiprotocolServiceLayer> = StaticCell::new();
84    let mpsl = MPSL.init(mpsl::MultiprotocolServiceLayer::new(
85        mpsl_peripherals,
86        irqs.clone(),
87        lfclk_cfg,
88    )?);
89
90    embassy_executor::Spawner::for_current_executor()
91        .await
92        .must_spawn(mpsl_task(&*mpsl));
93
94    let sdc_mem = singleton!(sdc::Mem::<3312>::new(), sdc::Mem::<3312>);
95
96    let sdc = sdc::Builder::new()?
97        .support_adv()?
98        .support_peripheral()?
99        .peripheral_count(1)?
100        .buffer_cfg(l2cap_mtu, l2cap_mtu, l2cap_txq, l2cap_rxq)?
101        .build(sdc_peripherals, rng, mpsl, sdc_mem)?;
102
103    Ok(sdc)
104}