cy8cproto_62_4243_w/
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 OxidOS Automotive 2025 SRL.
4
5#![no_std]
6#![no_main]
7#![deny(missing_docs)]
8
9//! Tock kernel for the CY8CPROTO-062-4343W.
10
11mod io;
12
13/// Kernel stack memory
14#[no_mangle]
15#[link_section = ".stack_buffer"]
16static mut STACK_MEMORY: [u8; 0x2000] = [0; 0x2000];
17
18use core::ptr::addr_of_mut;
19
20use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm;
21use components::led::LedsComponent;
22use kernel::component::Component;
23use kernel::hil::led::LedHigh;
24use kernel::platform::{KernelResources, SyscallDriverLookup};
25use kernel::process::ProcessArray;
26use kernel::scheduler::round_robin::RoundRobinSched;
27use kernel::{capabilities, create_capability, static_init};
28
29#[allow(unused)]
30use psoc62xa::{
31    chip::{PsoC62xaDefaultPeripherals, Psoc62xa},
32    gpio::GpioPin,
33    tcpwm::Tcpwm0,
34    BASE_VECTORS,
35};
36
37// State for loading and holding applications.
38// How should the kernel respond when a process faults.
39const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
40    capsules_system::process_policies::PanicFaultPolicy {};
41
42// Number of concurrent processes this platform supports.
43const NUM_PROCS: usize = 4;
44
45/// Static variables used by io.rs.
46static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
47static mut CHIP: Option<&'static Psoc62xa<PsoC62xaDefaultPeripherals>> = None;
48static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
49    None;
50
51/// Supported drivers by the platform
52pub struct Cy8cproto0624343w {
53    console: &'static capsules_core::console::Console<'static>,
54    alarm: &'static capsules_core::alarm::AlarmDriver<
55        'static,
56        VirtualMuxAlarm<'static, psoc62xa::tcpwm::Tcpwm0<'static>>,
57    >,
58    led: &'static capsules_core::led::LedDriver<'static, LedHigh<'static, GpioPin<'static>>, 1>,
59    button: &'static capsules_core::button::Button<'static, GpioPin<'static>>,
60    gpio: &'static capsules_core::gpio::GPIO<'static, psoc62xa::gpio::GpioPin<'static>>,
61    scheduler: &'static RoundRobinSched<'static>,
62    systick: cortexm0p::systick::SysTick,
63}
64
65impl SyscallDriverLookup for Cy8cproto0624343w {
66    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
67    where
68        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
69    {
70        match driver_num {
71            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
72            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
73            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
74            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
75            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
76            _ => f(None),
77        }
78    }
79}
80
81impl KernelResources<Psoc62xa<'static, PsoC62xaDefaultPeripherals<'static>>> for Cy8cproto0624343w {
82    type SyscallDriverLookup = Self;
83    type SyscallFilter = ();
84    type ProcessFault = ();
85    type Scheduler = RoundRobinSched<'static>;
86    type SchedulerTimer = cortexm0p::systick::SysTick;
87    type WatchDog = ();
88    type ContextSwitchCallback = ();
89
90    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
91        self
92    }
93    fn syscall_filter(&self) -> &Self::SyscallFilter {
94        &()
95    }
96    fn process_fault(&self) -> &Self::ProcessFault {
97        &()
98    }
99    fn scheduler(&self) -> &Self::Scheduler {
100        self.scheduler
101    }
102    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
103        &self.systick
104    }
105    fn watchdog(&self) -> &Self::WatchDog {
106        &()
107    }
108    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
109        &()
110    }
111}
112
113fn init_clocks(peripherals: &PsoC62xaDefaultPeripherals) {
114    peripherals.srss.init_clock();
115    peripherals.cpuss.init_clock();
116    peripherals.peri.init_uart_clock();
117    peripherals.peri.init_alarm_clock();
118}
119
120/// Main function called after RAM initialized.
121#[no_mangle]
122pub unsafe fn main() {
123    // Set the offset of the vector table
124    cortexm0p::scb::set_vector_table_offset(0x10000000 as *const ());
125
126    let peripherals = static_init!(
127        PsoC62xaDefaultPeripherals,
128        PsoC62xaDefaultPeripherals::new()
129    );
130
131    // Initialize clocks
132    init_clocks(peripherals);
133
134    // Enable interrupts
135    peripherals.cpuss.enable_int_for_scb5();
136    peripherals.cpuss.enable_int_for_tcpwm00();
137    peripherals.cpuss.enable_int_for_gpio0();
138    cortexm0p::nvic::enable_all();
139
140    //--------------------------------------------------------------------------
141    // UART & CONSOLE & DEBUG
142    //--------------------------------------------------------------------------
143
144    peripherals.scb.set_standard_uart_mode();
145    peripherals.scb.enable_scb();
146    peripherals.hsiom.enable_uart();
147    let uart_tx_pin = peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P5_1);
148    uart_tx_pin.configure_drive_mode(psoc62xa::gpio::DriveMode::Strong);
149    uart_tx_pin.configure_input(false);
150    let uart_rx_pin = peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P5_0);
151    uart_rx_pin.configure_drive_mode(psoc62xa::gpio::DriveMode::HighZ);
152    uart_rx_pin.configure_input(true);
153    let chip = static_init!(
154        Psoc62xa<PsoC62xaDefaultPeripherals>,
155        Psoc62xa::new(peripherals)
156    );
157
158    // Create an array to hold process references.
159    let processes = components::process_array::ProcessArrayComponent::new()
160        .finalize(components::process_array_component_static!(NUM_PROCS));
161    PROCESSES = Some(processes);
162
163    // Setup space to store the core kernel data structure.
164    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
165
166    // Create a shared UART channel for kernel debug.
167    let uart_mux = components::console::UartMuxComponent::new(&peripherals.scb, 115200)
168        .finalize(components::uart_mux_component_static!());
169
170    let console = components::console::ConsoleComponent::new(
171        board_kernel,
172        capsules_core::console::DRIVER_NUM,
173        uart_mux,
174    )
175    .finalize(components::console_component_static!());
176    components::debug_writer::DebugWriterComponent::new(
177        uart_mux,
178        create_capability!(capabilities::SetDebugWriterCapability),
179    )
180    .finalize(components::debug_writer_component_static!());
181
182    //--------------------------------------------------------------------------
183    // ALARM & TIMER
184    //--------------------------------------------------------------------------
185    peripherals.tcpwm.init_timer();
186
187    let mux_alarm = components::alarm::AlarmMuxComponent::new(&peripherals.tcpwm)
188        .finalize(components::alarm_mux_component_static!(Tcpwm0));
189
190    let alarm = components::alarm::AlarmDriverComponent::new(
191        board_kernel,
192        capsules_core::alarm::DRIVER_NUM,
193        mux_alarm,
194    )
195    .finalize(components::alarm_component_static!(Tcpwm0));
196
197    //--------------------------------------------------------------------------
198    // PROCESS CONSOLE
199    //--------------------------------------------------------------------------
200    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
201        .finalize(components::process_printer_text_component_static!());
202    PROCESS_PRINTER = Some(process_printer);
203
204    let process_console = components::process_console::ProcessConsoleComponent::new(
205        board_kernel,
206        uart_mux,
207        mux_alarm,
208        process_printer,
209        Some(cortexm0p::support::reset),
210    )
211    .finalize(components::process_console_component_static!(Tcpwm0));
212    let _ = process_console.start();
213
214    let led_pin = peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P13_7);
215
216    let led = LedsComponent::new().finalize(components::led_component_static!(
217        LedHigh<'static, GpioPin>,
218        LedHigh::new(led_pin)
219    ));
220
221    //--------------------------------------------------------------------------
222    // GPIO
223    //--------------------------------------------------------------------------
224
225    let gpio = components::gpio::GpioComponent::new(
226        board_kernel,
227        capsules_core::gpio::DRIVER_NUM,
228        components::gpio_component_helper!(
229            psoc62xa::gpio::GpioPin,
230            5 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P0_5),
231            44 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P5_4),
232            45 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P5_5),
233            46 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P5_6),
234            47 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P5_7),
235            50 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P6_2),
236            51 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P6_3),
237            52 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P6_4),
238            53 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P6_5),
239            64 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P8_0),
240            72 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P9_0),
241            73 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P9_1),
242            74 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P9_2),
243            76 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P9_4),
244            77 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P9_5),
245            78 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P9_6),
246            79 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P9_7),
247            96 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P12_0),
248            97 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P12_1),
249            99 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P12_3),
250            108 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P13_4),
251            110 => peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P13_6),
252        ),
253    )
254    .finalize(components::gpio_component_static!(psoc62xa::gpio::GpioPin));
255
256    //--------------------------------------------------------------------------
257    // BUTTON
258    //--------------------------------------------------------------------------
259
260    let button_pin = peripherals.gpio.get_pin(psoc62xa::gpio::PsocPin::P0_4);
261
262    let button = components::button::ButtonComponent::new(
263        board_kernel,
264        capsules_core::button::DRIVER_NUM,
265        components::button_component_helper!(
266            GpioPin,
267            (
268                button_pin,
269                kernel::hil::gpio::ActivationMode::ActiveLow,
270                kernel::hil::gpio::FloatingState::PullNone
271            ),
272        ),
273    )
274    .finalize(components::button_component_static!(GpioPin));
275
276    //--------------------------------------------------------------------------
277    // FINAL SETUP AND BOARD BOOT
278    //--------------------------------------------------------------------------
279
280    let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
281        .finalize(components::round_robin_component_static!(NUM_PROCS));
282
283    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
284
285    let cy8cproto0624343w = Cy8cproto0624343w {
286        console,
287        alarm,
288        scheduler,
289        led,
290        button,
291        gpio,
292        // Currently, the CPU runs at 8MHz, that being the frequency of the IMO.
293        systick: cortexm0p::systick::SysTick::new_with_calibration(8_000_000),
294    };
295
296    CHIP = Some(chip);
297    (*addr_of_mut!(io::WRITER)).set_scb(&peripherals.scb);
298
299    kernel::debug!("Initialization complete. Entering main loop.");
300
301    //--------------------------------------------------------------------------
302    // PROCESSES AND MAIN LOOP
303    //--------------------------------------------------------------------------
304
305    // These symbols are defined in the linker script.
306    extern "C" {
307        /// Beginning of the ROM region containing app images.
308        static _sapps: u8;
309        /// End of the ROM region containing app images.
310        static _eapps: u8;
311        /// Beginning of the RAM region for app memory.
312        static mut _sappmem: u8;
313        /// End of the RAM region for app memory.
314        static _eappmem: u8;
315    }
316
317    let process_management_capability =
318        create_capability!(capabilities::ProcessManagementCapability);
319
320    kernel::process::load_processes(
321        board_kernel,
322        chip,
323        core::slice::from_raw_parts(
324            core::ptr::addr_of!(_sapps),
325            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
326        ),
327        core::slice::from_raw_parts_mut(
328            core::ptr::addr_of_mut!(_sappmem),
329            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
330        ),
331        &FAULT_RESPONSE,
332        &process_management_capability,
333    )
334    .unwrap_or_else(|err| {
335        kernel::debug!("Error loading processes!");
336        kernel::debug!("{:?}", err);
337    });
338
339    board_kernel.kernel_loop(
340        &cy8cproto0624343w,
341        chip,
342        None::<kernel::ipc::IPC<{ NUM_PROCS as u8 }>>.as_ref(),
343        &main_loop_capability,
344    );
345}