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