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