esp32_c3_board/
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//! Board file for ESP32-C3 RISC-V development platform.
6//!
7
8#![no_std]
9#![no_main]
10#![feature(custom_test_frameworks)]
11#![test_runner(test_runner)]
12#![reexport_test_harness_main = "test_main"]
13
14use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
15use esp32_c3::chip::Esp32C3DefaultPeripherals;
16use kernel::capabilities;
17use kernel::component::Component;
18use kernel::platform::{KernelResources, SyscallDriverLookup};
19use kernel::process::ProcessArray;
20use kernel::scheduler::priority::PrioritySched;
21use kernel::utilities::registers::interfaces::ReadWriteable;
22use kernel::{create_capability, debug, hil, static_init};
23use rv32i::csr;
24
25pub mod io;
26
27#[cfg(test)]
28mod tests;
29
30const NUM_PROCS: usize = 4;
31
32type ChipHw = esp32_c3::chip::Esp32C3<'static, Esp32C3DefaultPeripherals<'static>>;
33type AlarmHw = esp32_c3::timg::TimG<'static>;
34type SchedulerTimerHw =
35    components::virtual_scheduler_timer::VirtualSchedulerTimerNoMuxComponentType<AlarmHw>;
36
37/// Static variables used by io.rs.
38static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
39// Reference to the chip for panic dumps.
40static mut CHIP: Option<&'static esp32_c3::chip::Esp32C3<Esp32C3DefaultPeripherals>> = None;
41// Static reference to process printer for panic dumps.
42static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
43    None;
44
45// How should the kernel respond when a process faults.
46const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
47    capsules_system::process_policies::PanicFaultPolicy {};
48
49// Test access to the peripherals
50#[cfg(test)]
51static mut PERIPHERALS: Option<&'static Esp32C3DefaultPeripherals> = None;
52// Test access to scheduler
53#[cfg(test)]
54static mut SCHEDULER: Option<&PrioritySched> = None;
55// Test access to board
56#[cfg(test)]
57static mut BOARD: Option<&'static kernel::Kernel> = None;
58// Test access to platform
59#[cfg(test)]
60static mut PLATFORM: Option<&'static Esp32C3Board> = None;
61// Test access to main loop capability
62#[cfg(test)]
63static mut MAIN_CAP: Option<&dyn kernel::capabilities::MainLoopCapability> = None;
64// Test access to alarm
65static mut ALARM: Option<&'static MuxAlarm<'static, esp32_c3::timg::TimG<'static>>> = None;
66
67kernel::stack_size! {0x900}
68
69type RngDriver = components::rng::RngComponentType<esp32_c3::rng::Rng<'static>>;
70type GpioHw = esp32::gpio::GpioPin<'static>;
71type LedHw = components::sk68xx::Sk68xxLedComponentType<GpioHw, 3>;
72type LedDriver = components::led::LedsComponentType<LedHw, 3>;
73type ButtonDriver = components::button::ButtonComponentType<GpioHw>;
74
75/// A structure representing this platform that holds references to all
76/// capsules for this platform. We've included an alarm and console.
77struct Esp32C3Board {
78    gpio: &'static capsules_core::gpio::GPIO<'static, esp32::gpio::GpioPin<'static>>,
79    console: &'static capsules_core::console::Console<'static>,
80    alarm: &'static capsules_core::alarm::AlarmDriver<
81        'static,
82        VirtualMuxAlarm<'static, esp32_c3::timg::TimG<'static>>,
83    >,
84    scheduler: &'static PrioritySched,
85    scheduler_timer: &'static SchedulerTimerHw,
86    rng: &'static RngDriver,
87    led: &'static LedDriver,
88    button: &'static ButtonDriver,
89}
90
91/// Mapping of integer syscalls to objects that implement syscalls.
92impl SyscallDriverLookup for Esp32C3Board {
93    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
94    where
95        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
96    {
97        match driver_num {
98            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
99            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
100            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
101            capsules_core::rng::DRIVER_NUM => f(Some(self.rng)),
102            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
103            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
104            _ => f(None),
105        }
106    }
107}
108
109impl KernelResources<esp32_c3::chip::Esp32C3<'static, Esp32C3DefaultPeripherals<'static>>>
110    for Esp32C3Board
111{
112    type SyscallDriverLookup = Self;
113    type SyscallFilter = ();
114    type ProcessFault = ();
115    type ContextSwitchCallback = ();
116    type Scheduler = PrioritySched;
117    type SchedulerTimer = SchedulerTimerHw;
118    type WatchDog = ();
119
120    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
121        self
122    }
123    fn syscall_filter(&self) -> &Self::SyscallFilter {
124        &()
125    }
126    fn process_fault(&self) -> &Self::ProcessFault {
127        &()
128    }
129    fn scheduler(&self) -> &Self::Scheduler {
130        self.scheduler
131    }
132    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
133        self.scheduler_timer
134    }
135    fn watchdog(&self) -> &Self::WatchDog {
136        &()
137    }
138    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
139        &()
140    }
141}
142
143unsafe fn setup() -> (
144    &'static kernel::Kernel,
145    &'static Esp32C3Board,
146    &'static esp32_c3::chip::Esp32C3<'static, Esp32C3DefaultPeripherals<'static>>,
147    &'static Esp32C3DefaultPeripherals<'static>,
148) {
149    use esp32_c3::sysreg::{CpuFrequency, PllFrequency};
150
151    // only machine mode
152    esp32_c3::chip::configure_trap_handler();
153
154    // Initialize deferred calls very early.
155    kernel::deferred_call::initialize_deferred_call_state_unsafe::<
156        <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
157    >();
158
159    //
160    // PERIPHERALS
161    //
162
163    let peripherals = static_init!(Esp32C3DefaultPeripherals, Esp32C3DefaultPeripherals::new());
164
165    peripherals.timg0.disable_wdt();
166    peripherals.rtc_cntl.disable_wdt();
167    peripherals.rtc_cntl.disable_super_wdt();
168    peripherals.rtc_cntl.enable_fosc();
169    peripherals.sysreg.disable_timg0();
170    peripherals.sysreg.enable_timg0();
171
172    peripherals
173        .sysreg
174        .use_pll_clock_source(PllFrequency::MHz320, CpuFrequency::MHz160);
175
176    // initialise capabilities
177    let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
178    let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
179
180    //
181    // BOARD SETUP AND PROCESSES
182    //
183
184    // Create an array to hold process references.
185    let processes = components::process_array::ProcessArrayComponent::new()
186        .finalize(components::process_array_component_static!(NUM_PROCS));
187    PROCESSES = Some(processes);
188
189    // Setup space to store the core kernel data structure.
190    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
191
192    //
193    // UART
194    //
195
196    // Create a shared UART channel for the console and for kernel debug.
197    let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
198        .finalize(components::uart_mux_component_static!());
199
200    // Setup the console.
201    let console = components::console::ConsoleComponent::new(
202        board_kernel,
203        capsules_core::console::DRIVER_NUM,
204        uart_mux,
205    )
206    .finalize(components::console_component_static!());
207    // Create the debugger object that handles calls to `debug!()`.
208    components::debug_writer::DebugWriterComponent::new_unsafe(
209        uart_mux,
210        create_capability!(capabilities::SetDebugWriterCapability),
211        || unsafe {
212            kernel::debug::initialize_debug_writer_wrapper_unsafe::<
213                <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
214            >();
215        },
216    )
217    .finalize(components::debug_writer_component_static!());
218
219    // Create process printer for panic.
220    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
221        .finalize(components::process_printer_text_component_static!());
222    PROCESS_PRINTER = Some(process_printer);
223
224    //
225    // GPIO
226    //
227
228    let gpio = components::gpio::GpioComponent::new(
229        board_kernel,
230        capsules_core::gpio::DRIVER_NUM,
231        components::gpio_component_helper!(
232            esp32::gpio::GpioPin,
233            0 => &peripherals.gpio[0],
234            1 => &peripherals.gpio[1],
235            2 => &peripherals.gpio[2],
236            3 => &peripherals.gpio[3],
237            4 => &peripherals.gpio[4],
238            5 => &peripherals.gpio[5],
239            6 => &peripherals.gpio[6],
240            7 => &peripherals.gpio[7],
241            8 => &peripherals.gpio[15]
242        ),
243    )
244    .finalize(components::gpio_component_static!(esp32::gpio::GpioPin));
245
246    //
247    // ALARM
248    //
249
250    // Create a shared virtualization mux layer on top of a single hardware
251    // alarm.
252    let mux_alarm = static_init!(
253        MuxAlarm<'static, esp32_c3::timg::TimG>,
254        MuxAlarm::new(&peripherals.timg0)
255    );
256    hil::time::Alarm::set_alarm_client(&peripherals.timg0, mux_alarm);
257
258    ALARM = Some(mux_alarm);
259
260    // Alarm
261    let virtual_alarm_user = static_init!(
262        VirtualMuxAlarm<'static, esp32_c3::timg::TimG>,
263        VirtualMuxAlarm::new(mux_alarm)
264    );
265    virtual_alarm_user.setup();
266
267    let alarm = static_init!(
268        capsules_core::alarm::AlarmDriver<'static, VirtualMuxAlarm<'static, esp32_c3::timg::TimG>>,
269        capsules_core::alarm::AlarmDriver::new(
270            virtual_alarm_user,
271            board_kernel.create_grant(capsules_core::alarm::DRIVER_NUM, &memory_allocation_cap)
272        )
273    );
274    hil::time::Alarm::set_alarm_client(virtual_alarm_user, alarm);
275
276    //
277    // LED
278    //
279
280    let led_gpio = &peripherals.gpio[8];
281    let sk68xx = components::sk68xx::Sk68xxComponent::new(led_gpio, rv32i::support::nop)
282        .finalize(components::sk68xx_component_static_esp32c3_160mhz!(GpioHw,));
283
284    let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
285        LedHw,
286        capsules_extra::sk68xx::Sk68xxLed::new(sk68xx, 0), // red
287        capsules_extra::sk68xx::Sk68xxLed::new(sk68xx, 1), // green
288        capsules_extra::sk68xx::Sk68xxLed::new(sk68xx, 2), // blue
289    ));
290
291    //
292    // BUTTONS
293    //
294
295    let button_boot_gpio = &peripherals.gpio[9];
296    let button = components::button::ButtonComponent::new(
297        board_kernel,
298        capsules_core::button::DRIVER_NUM,
299        components::button_component_helper!(
300            GpioHw,
301            (
302                button_boot_gpio,
303                kernel::hil::gpio::ActivationMode::ActiveLow,
304                kernel::hil::gpio::FloatingState::PullUp
305            )
306        ),
307    )
308    .finalize(components::button_component_static!(GpioHw));
309
310    //
311    // SCHEDULER
312    //
313
314    let scheduler_timer_alarm = &peripherals.timg1;
315    let scheduler_timer =
316        components::virtual_scheduler_timer::VirtualSchedulerTimerNoMuxComponent::new(
317            scheduler_timer_alarm,
318        )
319        .finalize(components::virtual_scheduler_timer_no_mux_component_static!(AlarmHw));
320
321    let scheduler = components::sched::priority::PriorityComponent::new(board_kernel)
322        .finalize(components::priority_component_static!());
323
324    //
325    // PROCESS CONSOLE
326    //
327
328    let process_console = components::process_console::ProcessConsoleComponent::new(
329        board_kernel,
330        uart_mux,
331        mux_alarm,
332        process_printer,
333        None,
334    )
335    .finalize(components::process_console_component_static!(
336        esp32_c3::timg::TimG
337    ));
338    let _ = process_console.start();
339
340    //
341    // RNG
342    //
343
344    let rng = components::rng::RngComponent::new(
345        board_kernel,
346        capsules_core::rng::DRIVER_NUM,
347        &peripherals.rng,
348    )
349    .finalize(components::rng_component_static!(esp32_c3::rng::Rng));
350
351    //
352    // CHIP AND INTERRUPTS
353    //
354
355    let chip = static_init!(
356        esp32_c3::chip::Esp32C3<
357            Esp32C3DefaultPeripherals,
358        >,
359        esp32_c3::chip::Esp32C3::new(peripherals)
360    );
361    CHIP = Some(chip);
362
363    // Need to enable all interrupts for Tock Kernel
364    chip.map_pic_interrupts();
365    chip.enable_pic_interrupts();
366
367    // enable interrupts globally
368    csr::CSR.mstatus.modify(csr::mstatus::mstatus::mie::SET);
369
370    debug!("ESP32-C3 initialisation complete.");
371    debug!("Entering main loop.");
372
373    //
374    // LOAD PROCESSES
375    //
376
377    // These symbols are defined in the linker script.
378    extern "C" {
379        /// Beginning of the ROM region containing app images.
380        static _sapps: u8;
381        /// End of the ROM region containing app images.
382        static _eapps: u8;
383        /// Beginning of the RAM region for app memory.
384        static mut _sappmem: u8;
385        /// End of the RAM region for app memory.
386        static _eappmem: u8;
387    }
388
389    let esp32_c3_board = static_init!(
390        Esp32C3Board,
391        Esp32C3Board {
392            gpio,
393            console,
394            alarm,
395            scheduler,
396            scheduler_timer,
397            rng,
398            led,
399            button
400        }
401    );
402
403    kernel::process::load_processes(
404        board_kernel,
405        chip,
406        core::slice::from_raw_parts(
407            core::ptr::addr_of!(_sapps),
408            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
409        ),
410        core::slice::from_raw_parts_mut(
411            core::ptr::addr_of_mut!(_sappmem),
412            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
413        ),
414        &FAULT_RESPONSE,
415        &process_mgmt_cap,
416    )
417    .unwrap_or_else(|err| {
418        debug!("Error loading processes!");
419        debug!("{:?}", err);
420    });
421
422    peripherals.init();
423
424    (board_kernel, esp32_c3_board, chip, peripherals)
425}
426
427/// Main function.
428///
429/// This function is called from the arch crate after some very basic RISC-V
430/// setup and RAM initialization.
431#[no_mangle]
432pub unsafe fn main() {
433    #[cfg(test)]
434    test_main();
435
436    #[cfg(not(test))]
437    {
438        let (board_kernel, esp32_c3_board, chip, _peripherals) = setup();
439
440        let main_loop_cap = create_capability!(capabilities::MainLoopCapability);
441
442        board_kernel.kernel_loop(
443            esp32_c3_board,
444            chip,
445            None::<&kernel::ipc::IPC<0>>,
446            &main_loop_cap,
447        );
448    }
449}
450
451#[cfg(test)]
452use kernel::platform::watchdog::WatchDog;
453
454#[cfg(test)]
455fn test_runner(tests: &[&dyn Fn()]) {
456    unsafe {
457        let (board_kernel, esp32_c3_board, _chip, peripherals) = setup();
458
459        BOARD = Some(board_kernel);
460        PLATFORM = Some(&esp32_c3_board);
461        PERIPHERALS = Some(peripherals);
462        SCHEDULER = Some(
463            components::sched::priority::PriorityComponent::new(board_kernel)
464                .finalize(components::priority_component_static!()),
465        );
466        MAIN_CAP = Some(&create_capability!(capabilities::MainLoopCapability));
467
468        PLATFORM.map(|p| {
469            p.watchdog().setup();
470        });
471
472        for test in tests {
473            test();
474        }
475    }
476
477    loop {}
478}