raspberry_pi_pico/
main.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Tock kernel for the Raspberry Pi Pico.
6//!
7//! It is based on RP2040SoC SoC (Cortex M0+).
8
9#![no_std]
10#![no_main]
11#![deny(missing_docs)]
12
13use core::ptr::addr_of_mut;
14
15use capsules_core::i2c_master::I2CMasterDriver;
16use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm;
17use components::date_time_component_static;
18use components::gpio::GpioComponent;
19use components::led::LedsComponent;
20use enum_primitive::cast::FromPrimitive;
21use kernel::component::Component;
22use kernel::debug;
23use kernel::hil::gpio::{Configure, FloatingState};
24use kernel::hil::i2c::I2CMaster;
25use kernel::hil::led::LedHigh;
26use kernel::hil::usb::Client;
27use kernel::platform::{KernelResources, SyscallDriverLookup};
28use kernel::process::ProcessArray;
29use kernel::scheduler::round_robin::RoundRobinSched;
30use kernel::syscall::SyscallDriver;
31use kernel::{capabilities, create_capability, static_init};
32
33use rp2040::adc::{Adc, Channel};
34use rp2040::chip::{Rp2040, Rp2040DefaultPeripherals};
35use rp2040::clocks::{
36    AdcAuxiliaryClockSource, PeripheralAuxiliaryClockSource, PllClock,
37    ReferenceAuxiliaryClockSource, ReferenceClockSource, RtcAuxiliaryClockSource,
38    SystemAuxiliaryClockSource, SystemClockSource, UsbAuxiliaryClockSource,
39};
40use rp2040::gpio::{GpioFunction, RPGpio, RPGpioPin};
41use rp2040::i2c::I2c;
42use rp2040::resets::Peripheral;
43use rp2040::sysinfo;
44use rp2040::timer::RPTimer;
45
46mod io;
47
48mod flash_bootloader;
49
50kernel::stack_size! {0x1500}
51
52// Manually setting the boot header section that contains the FCB header
53//
54// When compiling for a macOS host, the `link_section` attribute is elided as
55// it yields the following error: `mach-o section specifier requires a segment
56// and section separated by a comma`.
57#[cfg_attr(not(target_os = "macos"), link_section = ".flash_bootloader")]
58#[used]
59static FLASH_BOOTLOADER: [u8; 256] = flash_bootloader::FLASH_BOOTLOADER;
60
61// State for loading and holding applications.
62// How should the kernel respond when a process faults.
63const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
64    capsules_system::process_policies::PanicFaultPolicy {};
65
66// Number of concurrent processes this platform supports.
67const NUM_PROCS: usize = 4;
68
69type ChipHw = Rp2040<'static, Rp2040DefaultPeripherals<'static>>;
70
71/// Static variables used by io.rs.
72static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
73
74static mut CHIP: Option<&'static Rp2040<Rp2040DefaultPeripherals>> = None;
75static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
76    None;
77
78type TemperatureRp2040Sensor = components::temperature_rp2040::TemperatureRp2040ComponentType<
79    capsules_core::virtualizers::virtual_adc::AdcDevice<'static, rp2040::adc::Adc<'static>>,
80>;
81type TemperatureDriver = components::temperature::TemperatureComponentType<TemperatureRp2040Sensor>;
82
83/// Supported drivers by the platform
84pub struct RaspberryPiPico {
85    ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
86    console: &'static capsules_core::console::Console<'static>,
87    alarm: &'static capsules_core::alarm::AlarmDriver<
88        'static,
89        VirtualMuxAlarm<'static, rp2040::timer::RPTimer<'static>>,
90    >,
91    gpio: &'static capsules_core::gpio::GPIO<'static, RPGpioPin<'static>>,
92    led: &'static capsules_core::led::LedDriver<'static, LedHigh<'static, RPGpioPin<'static>>, 1>,
93    adc: &'static capsules_core::adc::AdcVirtualized<'static>,
94    temperature: &'static TemperatureDriver,
95    i2c: &'static capsules_core::i2c_master::I2CMasterDriver<'static, I2c<'static, 'static>>,
96
97    date_time:
98        &'static capsules_extra::date_time::DateTimeCapsule<'static, rp2040::rtc::Rtc<'static>>,
99    scheduler: &'static RoundRobinSched<'static>,
100    systick: cortexm0p::systick::SysTick,
101}
102
103impl SyscallDriverLookup for RaspberryPiPico {
104    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
105    where
106        F: FnOnce(Option<&dyn SyscallDriver>) -> R,
107    {
108        match driver_num {
109            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
110            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
111            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
112            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
113            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
114            capsules_core::adc::DRIVER_NUM => f(Some(self.adc)),
115            capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)),
116            capsules_core::i2c_master::DRIVER_NUM => f(Some(self.i2c)),
117            capsules_extra::date_time::DRIVER_NUM => f(Some(self.date_time)),
118            _ => f(None),
119        }
120    }
121}
122
123impl KernelResources<Rp2040<'static, Rp2040DefaultPeripherals<'static>>> for RaspberryPiPico {
124    type SyscallDriverLookup = Self;
125    type SyscallFilter = ();
126    type ProcessFault = ();
127    type Scheduler = RoundRobinSched<'static>;
128    type SchedulerTimer = cortexm0p::systick::SysTick;
129    type WatchDog = ();
130    type ContextSwitchCallback = ();
131
132    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
133        self
134    }
135    fn syscall_filter(&self) -> &Self::SyscallFilter {
136        &()
137    }
138    fn process_fault(&self) -> &Self::ProcessFault {
139        &()
140    }
141    fn scheduler(&self) -> &Self::Scheduler {
142        self.scheduler
143    }
144    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
145        &self.systick
146    }
147    fn watchdog(&self) -> &Self::WatchDog {
148        &()
149    }
150    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
151        &()
152    }
153}
154
155/// Entry point used for debugger
156///
157/// When loaded using gdb, the Raspberry Pi Pico is not reset
158/// by default. Without this function, gdb sets the PC to the
159/// beginning of the flash. This is not correct, as the RP2040
160/// has a more complex boot process.
161///
162/// This function is set to be the entry point for gdb and is used
163/// to send the RP2040 back in the bootloader so that all the boot
164/// sequence is performed.
165#[no_mangle]
166#[unsafe(naked)]
167pub unsafe extern "C" fn jump_to_bootloader() {
168    use core::arch::naked_asm;
169    naked_asm!(
170        "
171    movs r0, #0
172    ldr r1, =(0xe0000000 + 0x0000ed08)
173    str r0, [r1]
174    ldmia r0!, {{r1, r2}}
175    msr msp, r1
176    bx r2
177        "
178    );
179}
180
181fn init_clocks(peripherals: &Rp2040DefaultPeripherals) {
182    // Start tick in watchdog
183    peripherals.watchdog.start_tick(12);
184
185    // Disable the Resus clock
186    peripherals.clocks.disable_resus();
187
188    // Setup the external Oscillator
189    peripherals.xosc.init();
190
191    // disable ref and sys clock aux sources
192    peripherals.clocks.disable_sys_aux();
193    peripherals.clocks.disable_ref_aux();
194
195    peripherals
196        .resets
197        .reset(&[Peripheral::PllSys, Peripheral::PllUsb]);
198    peripherals
199        .resets
200        .unreset(&[Peripheral::PllSys, Peripheral::PllUsb], true);
201
202    // Configure PLLs (from Pico SDK)
203    //                   REF     FBDIV VCO            POSTDIV
204    // PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHZ / 6 / 2 = 125MHz
205    // PLL USB: 12 / 1 = 12MHz * 40  = 480 MHz / 5 / 2 =  48MHz
206
207    // It seems that the external oscillator is clocked at 12 MHz
208
209    peripherals
210        .clocks
211        .pll_init(PllClock::Sys, 12, 1, 1500 * 1000000, 6, 2);
212    peripherals
213        .clocks
214        .pll_init(PllClock::Usb, 12, 1, 480 * 1000000, 5, 2);
215
216    // pico-sdk: // CLK_REF = XOSC (12MHz) / 1 = 12MHz
217    peripherals.clocks.configure_reference(
218        ReferenceClockSource::Xosc,
219        ReferenceAuxiliaryClockSource::PllUsb,
220        12000000,
221        12000000,
222    );
223    // pico-sdk: CLK SYS = PLL SYS (125MHz) / 1 = 125MHz
224    peripherals.clocks.configure_system(
225        SystemClockSource::Auxiliary,
226        SystemAuxiliaryClockSource::PllSys,
227        125000000,
228        125000000,
229    );
230    // pico-sdk: CLK USB = PLL USB (48MHz) / 1 = 48MHz
231    peripherals
232        .clocks
233        .configure_usb(UsbAuxiliaryClockSource::PllSys, 48000000, 48000000);
234    // pico-sdk: CLK ADC = PLL USB (48MHZ) / 1 = 48MHz
235    peripherals
236        .clocks
237        .configure_adc(AdcAuxiliaryClockSource::PllUsb, 48000000, 48000000);
238    // pico-sdk: CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz
239    peripherals
240        .clocks
241        .configure_rtc(RtcAuxiliaryClockSource::PllSys, 48000000, 46875);
242    // pico-sdk:
243    // CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable
244    // Normally choose clk_sys or clk_usb
245    peripherals
246        .clocks
247        .configure_peripheral(PeripheralAuxiliaryClockSource::System, 125000000);
248}
249
250/// This is in a separate, inline(never) function so that its stack frame is
251/// removed when this function returns. Otherwise, the stack space used for
252/// these static_inits is wasted.
253#[inline(never)]
254pub unsafe fn start() -> (
255    &'static kernel::Kernel,
256    RaspberryPiPico,
257    &'static rp2040::chip::Rp2040<'static, Rp2040DefaultPeripherals<'static>>,
258) {
259    // Loads relocations and clears BSS
260    rp2040::init();
261
262    // Initialize deferred calls very early.
263    kernel::deferred_call::initialize_deferred_call_state_unsafe::<
264        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
265    >();
266
267    let peripherals = static_init!(Rp2040DefaultPeripherals, Rp2040DefaultPeripherals::new());
268    peripherals.resolve_dependencies();
269
270    // Reset all peripherals except QSPI (we might be booting from Flash), PLL USB and PLL SYS
271    peripherals.resets.reset_all_except(&[
272        Peripheral::IOQSpi,
273        Peripheral::PadsQSpi,
274        Peripheral::PllUsb,
275        Peripheral::PllSys,
276    ]);
277
278    // Unreset all the peripherals that do not require clock setup as they run using the sys_clk or ref_clk
279    // Wait for the peripherals to reset
280    peripherals.resets.unreset_all_except(
281        &[
282            Peripheral::Adc,
283            Peripheral::Rtc,
284            Peripheral::Spi0,
285            Peripheral::Spi1,
286            Peripheral::Uart0,
287            Peripheral::Uart1,
288            Peripheral::UsbCtrl,
289        ],
290        true,
291    );
292
293    init_clocks(peripherals);
294
295    // Unreset all peripherals
296    peripherals.resets.unreset_all_except(&[], true);
297
298    // Set the UART used for panic
299    (*addr_of_mut!(io::WRITER)).set_uart(&peripherals.uart0);
300
301    //set RX and TX pins in UART mode
302    let gpio_tx = peripherals.pins.get_pin(RPGpio::GPIO0);
303    let gpio_rx = peripherals.pins.get_pin(RPGpio::GPIO1);
304    gpio_rx.set_function(GpioFunction::UART);
305    gpio_tx.set_function(GpioFunction::UART);
306
307    // Disable IE for pads 26-29 (the Pico SDK runtime does this, not sure why)
308    for pin in 26..30 {
309        peripherals
310            .pins
311            .get_pin(RPGpio::from_usize(pin).unwrap())
312            .deactivate_pads();
313    }
314
315    let chip = static_init!(
316        Rp2040<Rp2040DefaultPeripherals>,
317        Rp2040::new(peripherals, &peripherals.sio)
318    );
319
320    CHIP = Some(chip);
321
322    // Create an array to hold process references.
323    let processes = components::process_array::ProcessArrayComponent::new()
324        .finalize(components::process_array_component_static!(NUM_PROCS));
325    PROCESSES = Some(processes);
326
327    // Setup space to store the core kernel data structure.
328    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
329
330    let process_management_capability =
331        create_capability!(capabilities::ProcessManagementCapability);
332    let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
333
334    let mux_alarm = components::alarm::AlarmMuxComponent::new(&peripherals.timer)
335        .finalize(components::alarm_mux_component_static!(RPTimer));
336
337    let alarm = components::alarm::AlarmDriverComponent::new(
338        board_kernel,
339        capsules_core::alarm::DRIVER_NUM,
340        mux_alarm,
341    )
342    .finalize(components::alarm_component_static!(RPTimer));
343
344    // CDC
345    let strings = static_init!(
346        [&str; 3],
347        [
348            "Raspberry Pi",      // Manufacturer
349            "Pico - TockOS",     // Product
350            "00000000000000000", // Serial number
351        ]
352    );
353
354    let cdc = components::cdc::CdcAcmComponent::new(
355        &peripherals.usb,
356        //capsules_extra::usb::cdc::MAX_CTRL_PACKET_SIZE_RP2040,
357        64,
358        peripherals.sysinfo.get_manufacturer_rp2040() as u16,
359        peripherals.sysinfo.get_part() as u16,
360        strings,
361        mux_alarm,
362        None,
363    )
364    .finalize(components::cdc_acm_component_static!(
365        rp2040::usb::UsbCtrl,
366        rp2040::timer::RPTimer
367    ));
368
369    // UART
370    // Create a shared UART channel for kernel debug.
371    let uart_mux = components::console::UartMuxComponent::new(cdc, 115200)
372        .finalize(components::uart_mux_component_static!());
373
374    // Uncomment this to use UART as an output
375    // let uart_mux2 = components::console::UartMuxComponent::new(
376    //     &peripherals.uart0,
377    //     115200,
378    // )
379    // .finalize(components::uart_mux_component_static!());
380
381    // Setup the console.
382    let console = components::console::ConsoleComponent::new(
383        board_kernel,
384        capsules_core::console::DRIVER_NUM,
385        uart_mux,
386    )
387    .finalize(components::console_component_static!());
388    // Create the debugger object that handles calls to `debug!()`.
389    components::debug_writer::DebugWriterComponent::new_unsafe(
390        uart_mux,
391        create_capability!(capabilities::SetDebugWriterCapability),
392        || unsafe {
393            kernel::debug::initialize_debug_writer_wrapper_unsafe::<
394                <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
395            >();
396        },
397    )
398    .finalize(components::debug_writer_component_static!());
399
400    cdc.enable();
401    cdc.attach();
402
403    let gpio = GpioComponent::new(
404        board_kernel,
405        capsules_core::gpio::DRIVER_NUM,
406        components::gpio_component_helper!(
407            RPGpioPin,
408            // Used for serial communication. Comment them in if you don't use serial.
409            // 0 => peripherals.pins.get_pin(RPGpio::GPIO0),
410            // 1 => peripherals.pins.get_pin(RPGpio::GPIO1),
411            2 => peripherals.pins.get_pin(RPGpio::GPIO2),
412            3 => peripherals.pins.get_pin(RPGpio::GPIO3),
413            // Used for i2c. Comment them in if you don't use i2c.
414            // 4 => peripherals.pins.get_pin(RPGpio::GPIO4),
415            // 5 => peripherals.pins.get_pin(RPGpio::GPIO5),
416            6 => peripherals.pins.get_pin(RPGpio::GPIO6),
417            7 => peripherals.pins.get_pin(RPGpio::GPIO7),
418            8 => peripherals.pins.get_pin(RPGpio::GPIO8),
419            9 => peripherals.pins.get_pin(RPGpio::GPIO9),
420            10 => peripherals.pins.get_pin(RPGpio::GPIO10),
421            11 => peripherals.pins.get_pin(RPGpio::GPIO11),
422            12 => peripherals.pins.get_pin(RPGpio::GPIO12),
423            13 => peripherals.pins.get_pin(RPGpio::GPIO13),
424            14 => peripherals.pins.get_pin(RPGpio::GPIO14),
425            15 => peripherals.pins.get_pin(RPGpio::GPIO15),
426            16 => peripherals.pins.get_pin(RPGpio::GPIO16),
427            17 => peripherals.pins.get_pin(RPGpio::GPIO17),
428            18 => peripherals.pins.get_pin(RPGpio::GPIO18),
429            19 => peripherals.pins.get_pin(RPGpio::GPIO19),
430            20 => peripherals.pins.get_pin(RPGpio::GPIO20),
431            21 => peripherals.pins.get_pin(RPGpio::GPIO21),
432            22 => peripherals.pins.get_pin(RPGpio::GPIO22),
433            23 => peripherals.pins.get_pin(RPGpio::GPIO23),
434            24 => peripherals.pins.get_pin(RPGpio::GPIO24),
435            // LED pin
436            // 25 => peripherals.pins.get_pin(RPGpio::GPIO25),
437
438            // Uncomment to use these as GPIO pins instead of ADC pins
439            // 26 => peripherals.pins.get_pin(RPGpio::GPIO26),
440            // 27 => peripherals.pins.get_pin(RPGpio::GPIO27),
441            // 28 => peripherals.pins.get_pin(RPGpio::GPIO28),
442            // 29 => peripherals.pins.get_pin(RPGpio::GPIO29)
443        ),
444    )
445    .finalize(components::gpio_component_static!(RPGpioPin<'static>));
446
447    let led = LedsComponent::new().finalize(components::led_component_static!(
448        LedHigh<'static, RPGpioPin<'static>>,
449        LedHigh::new(peripherals.pins.get_pin(RPGpio::GPIO25))
450    ));
451
452    peripherals.adc.init();
453
454    let adc_mux = components::adc::AdcMuxComponent::new(&peripherals.adc)
455        .finalize(components::adc_mux_component_static!(Adc));
456
457    let temp_sensor = components::temperature_rp2040::TemperatureRp2040Component::new(
458        adc_mux,
459        Channel::Channel4,
460        1.721,
461        0.706,
462    )
463    .finalize(components::temperature_rp2040_adc_component_static!(
464        rp2040::adc::Adc
465    ));
466
467    // RTC DATE TIME
468
469    match peripherals.rtc.rtc_init() {
470        Ok(()) => {}
471        Err(e) => {
472            debug!("error starting rtc {:?}", e)
473        }
474    }
475
476    let date_time = components::date_time::DateTimeComponent::new(
477        board_kernel,
478        capsules_extra::date_time::DRIVER_NUM,
479        &peripherals.rtc,
480    )
481    .finalize(date_time_component_static!(rp2040::rtc::Rtc<'static>));
482
483    let temp = components::temperature::TemperatureComponent::new(
484        board_kernel,
485        capsules_extra::temperature::DRIVER_NUM,
486        temp_sensor,
487    )
488    .finalize(components::temperature_component_static!(
489        TemperatureRp2040Sensor
490    ));
491
492    let adc_channel_0 = components::adc::AdcComponent::new(adc_mux, Channel::Channel0)
493        .finalize(components::adc_component_static!(Adc));
494
495    let adc_channel_1 = components::adc::AdcComponent::new(adc_mux, Channel::Channel1)
496        .finalize(components::adc_component_static!(Adc));
497
498    let adc_channel_2 = components::adc::AdcComponent::new(adc_mux, Channel::Channel2)
499        .finalize(components::adc_component_static!(Adc));
500
501    let adc_channel_3 = components::adc::AdcComponent::new(adc_mux, Channel::Channel3)
502        .finalize(components::adc_component_static!(Adc));
503
504    let adc_syscall =
505        components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM)
506            .finalize(components::adc_syscall_component_helper!(
507                adc_channel_0,
508                adc_channel_1,
509                adc_channel_2,
510                adc_channel_3,
511            ));
512    // PROCESS CONSOLE
513    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
514        .finalize(components::process_printer_text_component_static!());
515    PROCESS_PRINTER = Some(process_printer);
516
517    let process_console = components::process_console::ProcessConsoleComponent::new(
518        board_kernel,
519        uart_mux,
520        mux_alarm,
521        process_printer,
522        Some(cortexm0p::support::reset),
523    )
524    .finalize(components::process_console_component_static!(RPTimer));
525    let _ = process_console.start();
526
527    let sda_pin = peripherals.pins.get_pin(RPGpio::GPIO4);
528    let scl_pin = peripherals.pins.get_pin(RPGpio::GPIO5);
529
530    sda_pin.set_function(GpioFunction::I2C);
531    scl_pin.set_function(GpioFunction::I2C);
532
533    sda_pin.set_floating_state(FloatingState::PullUp);
534    scl_pin.set_floating_state(FloatingState::PullUp);
535
536    let i2c_master_buffer = static_init!(
537        [u8; capsules_core::i2c_master::BUFFER_LENGTH],
538        [0; capsules_core::i2c_master::BUFFER_LENGTH]
539    );
540    let i2c0 = &peripherals.i2c0;
541    let i2c = static_init!(
542        I2CMasterDriver<I2c<'static, 'static>>,
543        I2CMasterDriver::new(
544            i2c0,
545            i2c_master_buffer,
546            board_kernel.create_grant(
547                capsules_core::i2c_master::DRIVER_NUM,
548                &memory_allocation_capability
549            ),
550        )
551    );
552    i2c0.init(10 * 1000);
553    i2c0.set_master_client(i2c);
554
555    let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
556        .finalize(components::round_robin_component_static!(NUM_PROCS));
557
558    let raspberry_pi_pico = RaspberryPiPico {
559        ipc: kernel::ipc::IPC::new(
560            board_kernel,
561            kernel::ipc::DRIVER_NUM,
562            &memory_allocation_capability,
563        ),
564        alarm,
565        gpio,
566        led,
567        console,
568        adc: adc_syscall,
569        temperature: temp,
570        i2c,
571        date_time,
572
573        scheduler,
574        systick: cortexm0p::systick::SysTick::new_with_calibration(125_000_000),
575    };
576
577    let platform_type = match peripherals.sysinfo.get_platform() {
578        sysinfo::Platform::Asic => "ASIC",
579        sysinfo::Platform::Fpga => "FPGA",
580    };
581
582    debug!(
583        "RP2040 Revision {} {}",
584        peripherals.sysinfo.get_revision(),
585        platform_type
586    );
587
588    debug!("Initialization complete. Enter main loop");
589
590    // These symbols are defined in the linker script.
591    extern "C" {
592        /// Beginning of the ROM region containing app images.
593        static _sapps: u8;
594        /// End of the ROM region containing app images.
595        static _eapps: u8;
596        /// Beginning of the RAM region for app memory.
597        static mut _sappmem: u8;
598        /// End of the RAM region for app memory.
599        static _eappmem: u8;
600    }
601
602    kernel::process::load_processes(
603        board_kernel,
604        chip,
605        core::slice::from_raw_parts(
606            core::ptr::addr_of!(_sapps),
607            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
608        ),
609        core::slice::from_raw_parts_mut(
610            core::ptr::addr_of_mut!(_sappmem),
611            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
612        ),
613        &FAULT_RESPONSE,
614        &process_management_capability,
615    )
616    .unwrap_or_else(|err| {
617        debug!("Error loading processes!");
618        debug!("{:?}", err);
619    });
620
621    (board_kernel, raspberry_pi_pico, chip)
622}
623
624/// Main function called after RAM initialized.
625#[no_mangle]
626pub unsafe fn main() {
627    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
628
629    let (board_kernel, platform, chip) = start();
630    board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
631}