From ea64dbee2ce27230fa25700143d164bb116e8c4d Mon Sep 17 00:00:00 2001 From: Cristian-Stefan Lazar Date: Sun, 7 Jan 2024 21:14:31 +0200 Subject: [PATCH 1/9] Added the new Nucleo-F429ZI graphics display capsule (and all associated files) and modified most of them to fit into the tock hierarchy. Signed-off-by: Lazar Cristian-Stefan --- boards/clue_nrf52840/src/main.rs | 6 +- boards/components/src/graphic_display.rs | 97 +++ boards/components/src/lib.rs | 2 + boards/components/src/ssd1306.rs | 105 +++ boards/pico_explorer_base/src/main.rs | 6 +- boards/stm32f412gdiscovery/src/main.rs | 6 +- capsules/extra/src/bus.rs | 18 +- capsules/extra/src/graphics_display.rs | 577 +++++++++++++++ capsules/extra/src/lib.rs | 2 + capsules/extra/src/ssd1306.rs | 863 +++++++++++++++++++++++ kernel/src/hil/display.rs | 414 +++++++++++ kernel/src/hil/mod.rs | 1 + 12 files changed, 2087 insertions(+), 10 deletions(-) create mode 100644 boards/components/src/graphic_display.rs create mode 100644 boards/components/src/ssd1306.rs create mode 100644 capsules/extra/src/graphics_display.rs create mode 100644 capsules/extra/src/ssd1306.rs create mode 100644 kernel/src/hil/display.rs diff --git a/boards/clue_nrf52840/src/main.rs b/boards/clue_nrf52840/src/main.rs index 1badea6195..f0736413e9 100644 --- a/boards/clue_nrf52840/src/main.rs +++ b/boards/clue_nrf52840/src/main.rs @@ -158,7 +158,7 @@ pub struct Platform { 2, >, button: &'static capsules_core::button::Button<'static, nrf52::gpio::GPIOPin<'static>>, - screen: &'static capsules_extra::screen::Screen<'static>, + screen: &'static capsules_extra::graphics_display::Screen<'static>, rng: &'static capsules_core::rng::RngDriver<'static>, ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>, alarm: &'static capsules_core::alarm::AlarmDriver< @@ -199,7 +199,7 @@ impl SyscallDriverLookup for Platform { capsules_core::led::DRIVER_NUM => f(Some(self.led)), capsules_core::button::DRIVER_NUM => f(Some(self.button)), capsules_core::adc::DRIVER_NUM => f(Some(self.adc)), - capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)), + capsules_extra::graphics_display::DRIVER_NUM => f(Some(self.screen)), capsules_core::rng::DRIVER_NUM => f(Some(self.rng)), capsules_extra::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)), capsules_extra::ieee802154::DRIVER_NUM => f(Some(self.ieee802154_radio)), @@ -678,7 +678,7 @@ pub unsafe fn main() { let screen = components::screen::ScreenComponent::new( board_kernel, - capsules_extra::screen::DRIVER_NUM, + capsules_extra::graphics_display::DRIVER_NUM, tft, Some(tft), ) diff --git a/boards/components/src/graphic_display.rs b/boards/components/src/graphic_display.rs new file mode 100644 index 0000000000..3fd6346cd0 --- /dev/null +++ b/boards/components/src/graphic_display.rs @@ -0,0 +1,97 @@ +//! Components for the Screen. +//! +//! Buffer Size +//! ----------- +//! +//! Displays can receive a large amount of data and having larger transfer buffers +//! optimizes the number of bus writes. +//! +//! As memory is limited on some MCUs, the `components::screen_buffer_size`` +//! macro allows users to define the size of the screen buffer. +//! +//! Usage +//! ----- +//! +//! // Screen +//! ```rust +//! let screen = +//! components::screen::GraphicDisplayComponent::new(board_kernel, tft, None) +//! .finalize(components::graphic_display_component_static!(40960)); +//! ``` +//! +//! // Screen with Setup +//! ```rust +//! let screen = +//! components::screen::GraphicDisplayComponent::new(board_kernel, tft, Some(tft)) +//! .finalize(components::graphic_display_component_static!(40960)); +//! ``` + +use core::mem::MaybeUninit; +use capsules_extra::graphics_display::graphics_display::GraphicDisplay; +use kernel::hil::display; +use kernel::capabilities; +use kernel::component::Component; +use kernel::create_capability; + +#[macro_export] +macro_rules! graphic_display_component_static { + ($s:literal $(,)?) => {{ + let buffer = kernel::static_buf!([u8; $s]); + let screen = kernel::static_buf!(drivers::graphic_display::GraphicDisplay); + + (buffer, screen) + };}; +} + +pub struct GraphicDisplayComponent { + board_kernel: &'static kernel::Kernel, + driver_num: usize, + display: &'static dyn display::GraphicDisplay<'static>, + display_setup: Option<&'static dyn display::FrameBufferSetup<'static>>, +} + +impl GraphicDisplayComponent { + pub fn new( + board_kernel: &'static kernel::Kernel, + driver_num: usize, + display: &'static dyn display::GraphicDisplay<'static>, + display_setup: Option<&'static dyn display::FrameBufferSetup<'static>>, + ) -> GraphicDisplayComponent { + GraphicDisplayComponent { + board_kernel, + driver_num, + display, + display_setup, + } + } +} + +impl Component for GraphicDisplayComponent { + type StaticInput = ( + &'static mut MaybeUninit<[u8; SCREEN_BUF_LEN]>, + &'static mut MaybeUninit>, + ); + type Output = &'static GraphicDisplay<'static>; + + fn finalize(self, static_input: Self::StaticInput) -> Self::Output { + let grant_cap = create_capability!(capabilities::MemoryAllocationCapability); + let grant_screen = self.board_kernel.create_grant(self.driver_num, &grant_cap); + + let buffer = static_input.0.write([0; SCREEN_BUF_LEN]); + + let display = static_input.1.write(GraphicDisplay::new( + self.display, + self.display_setup, + buffer, + grant_screen, + )); + + display::Screen::set_client(self.display, Some(display)); + display::FrameBuffer::set_client(self.display, Some(display)); + if let Some(display_setup) = self.display_setup { + display::FrameBuffer::set_client(display_setup, Some(display)); + } + + display + } +} diff --git a/boards/components/src/lib.rs b/boards/components/src/lib.rs index fd9703ae6d..a19154537f 100644 --- a/boards/components/src/lib.rs +++ b/boards/components/src/lib.rs @@ -33,6 +33,7 @@ pub mod fm25cl; pub mod ft6x06; pub mod fxos8700; pub mod gpio; +pub mod graphic_display; pub mod hd44780; pub mod hmac; pub mod hs3003; @@ -77,6 +78,7 @@ pub mod siphash; pub mod sound_pressure; pub mod spi; pub mod st77xx; +pub mod ssd1306; pub mod temperature; pub mod temperature_rp2040; pub mod temperature_stm; diff --git a/boards/components/src/ssd1306.rs b/boards/components/src/ssd1306.rs new file mode 100644 index 0000000000..c21a11dd45 --- /dev/null +++ b/boards/components/src/ssd1306.rs @@ -0,0 +1,105 @@ +use core::mem::MaybeUninit; +use capsules_extra::bus; +use capsules_extra::ssd1306; +use kernel::component::Component; +use kernel::dynamic_deferred_call::DynamicDeferredCall; + +#[macro_export] +macro_rules! ssd1306_component_static { + ($B: ty, $(,)?) => {{ + let buffer = kernel::static_buf!([u8; drivers::ssd1306::BUFFER_SIZE]); + let app_write_buffer = kernel::static_buf!( + [u8; drivers::ssd1306::WIDTH * drivers::ssd1306::HEIGHT / 8 + + drivers::ssd1306::BUFFER_PADDING] + ); + let bus_write_buffer = kernel::static_buf!( + [u8; drivers::ssd1306::WIDTH * drivers::ssd1306::HEIGHT / 8 + + drivers::ssd1306::BUFFER_PADDING] + ); + let aux_write_buffer = kernel::static_buf!( + [u8; drivers::ssd1306::WIDTH * drivers::ssd1306::HEIGHT / 8 + + drivers::ssd1306::BUFFER_PADDING] + ); + let command_sequence = kernel::static_buf!( + [drivers::ssd1306::ScreenCommand; drivers::ssd1306::SEQUENCE_BUFFER_SIZE] + ); + let ssd1306 = kernel::static_buf!(drivers::ssd1306::SSD1306<'static, $B>); + ( + ssd1306, + command_sequence, + buffer, + app_write_buffer, + bus_write_buffer, + aux_write_buffer, + ) + };}; +} + +pub struct SSD1306Component> { + bus: &'static B, + deferred_caller: &'static DynamicDeferredCall, +} + +impl> SSD1306Component { + pub fn new( + bus: &'static B, + deferred_caller: &'static DynamicDeferredCall, + ) -> SSD1306Component { + SSD1306Component { + bus, + deferred_caller, + } + } +} + +impl> Component for SSD1306Component { + type StaticInput = ( + &'static mut MaybeUninit>, + &'static mut MaybeUninit<[ssd1306::ScreenCommand; ssd1306::SEQUENCE_BUFFER_SIZE]>, + &'static mut MaybeUninit<[u8; ssd1306::BUFFER_SIZE]>, + &'static mut MaybeUninit< + [u8; ssd1306::HEIGHT * ssd1306::WIDTH / 8 + ssd1306::BUFFER_PADDING], + >, + &'static mut MaybeUninit< + [u8; ssd1306::HEIGHT * ssd1306::WIDTH / 8 + ssd1306::BUFFER_PADDING], + >, + &'static mut MaybeUninit< + [u8; ssd1306::HEIGHT * ssd1306::WIDTH / 8 + ssd1306::BUFFER_PADDING], + >, + ); + + type Output = &'static ssd1306::SSD1306<'static, B>; + + fn finalize(self, static_memory: Self::StaticInput) -> Self::Output { + let command_sequence = static_memory.1.write( + [ssd1306::ScreenCommand { + id: ssd1306::CommandId::Nop, + parameters: None, + }; ssd1306::SEQUENCE_BUFFER_SIZE], + ); + let command_arguments = static_memory.2.write([0; ssd1306::BUFFER_SIZE]); + let app_write_buffer = static_memory + .3 + .write([0; ssd1306::HEIGHT * ssd1306::WIDTH / 8 + ssd1306::BUFFER_PADDING]); + let bus_write_buffer = static_memory + .4 + .write([0; ssd1306::HEIGHT * ssd1306::WIDTH / 8 + ssd1306::BUFFER_PADDING]); + let aux_write_buffer = static_memory + .5 + .write([0; ssd1306::HEIGHT * ssd1306::WIDTH / 8 + ssd1306::BUFFER_PADDING]); + + let ssd1306 = static_memory.0.write(ssd1306::SSD1306::new( + self.bus, + command_sequence, + command_arguments, + app_write_buffer, + bus_write_buffer, + aux_write_buffer, + self.deferred_caller, + )); + self.bus.set_client(ssd1306); + + ssd1306.initialize_callback_handle(self.deferred_caller.register(ssd1306).unwrap()); + ssd1306 + } +} diff --git a/boards/pico_explorer_base/src/main.rs b/boards/pico_explorer_base/src/main.rs index 44ae6c0af7..04feff525a 100644 --- a/boards/pico_explorer_base/src/main.rs +++ b/boards/pico_explorer_base/src/main.rs @@ -94,7 +94,7 @@ pub struct PicoExplorerBase { >, >, button: &'static capsules_core::button::Button<'static, RPGpioPin<'static>>, - screen: &'static capsules_extra::screen::Screen<'static>, + screen: &'static capsules_extra::graphics_display::Screen<'static>, scheduler: &'static RoundRobinSched<'static>, systick: cortexm0p::systick::SysTick, @@ -115,7 +115,7 @@ impl SyscallDriverLookup for PicoExplorerBase { capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)), capsules_extra::buzzer_driver::DRIVER_NUM => f(Some(self.buzzer_driver)), capsules_core::button::DRIVER_NUM => f(Some(self.button)), - capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)), + capsules_extra::graphics_display::DRIVER_NUM => f(Some(self.screen)), _ => f(None), } } @@ -523,7 +523,7 @@ pub unsafe fn main() { let screen = components::screen::ScreenComponent::new( board_kernel, - capsules_extra::screen::DRIVER_NUM, + capsules_extra::graphics_display::DRIVER_NUM, tft, Some(tft), ) diff --git a/boards/stm32f412gdiscovery/src/main.rs b/boards/stm32f412gdiscovery/src/main.rs index b2fe43ea96..8dfa026a8f 100644 --- a/boards/stm32f412gdiscovery/src/main.rs +++ b/boards/stm32f412gdiscovery/src/main.rs @@ -63,7 +63,7 @@ struct STM32F412GDiscovery { gpio: &'static capsules_core::gpio::GPIO<'static, stm32f412g::gpio::Pin<'static>>, adc: &'static capsules_core::adc::AdcVirtualized<'static>, touch: &'static capsules_extra::touch::Touch<'static>, - screen: &'static capsules_extra::screen::Screen<'static>, + screen: &'static capsules_extra::graphics_display::Screen<'static>, temperature: &'static capsules_extra::temperature::TemperatureSensor<'static>, rng: &'static capsules_core::rng::RngDriver<'static>, @@ -86,7 +86,7 @@ impl SyscallDriverLookup for STM32F412GDiscovery { capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)), capsules_core::adc::DRIVER_NUM => f(Some(self.adc)), capsules_extra::touch::DRIVER_NUM => f(Some(self.touch)), - capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)), + capsules_extra::graphics_display::DRIVER_NUM => f(Some(self.screen)), capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)), capsules_core::rng::DRIVER_NUM => f(Some(self.rng)), _ => f(None), @@ -645,7 +645,7 @@ pub unsafe fn main() { let screen = components::screen::ScreenComponent::new( board_kernel, - capsules_extra::screen::DRIVER_NUM, + capsules_extra::graphics_display::DRIVER_NUM, tft, Some(tft), ) diff --git a/capsules/extra/src/bus.rs b/capsules/extra/src/bus.rs index 77326f83d2..126cc3b942 100644 --- a/capsules/extra/src/bus.rs +++ b/capsules/extra/src/bus.rs @@ -301,7 +301,21 @@ impl<'a, I: I2CDevice> Bus<'a> for I2CMasterBus<'a, I> { } } }), - + BusWidth::Bits16LE => self + .addr_buffer + .take() + .map_or(Err(ErrorCode::NOMEM), |buffer| { + buffer[0] = 0x00; + buffer[1] = addr as u8; + self.status.set(BusStatus::SetAddress); + match self.i2c.write(buffer, 2) { + Ok(()) => Ok(()), + Err((error, buffer)) => { + self.addr_buffer.replace(buffer); + Err(error.into()) + } + } + }), _ => Err(ErrorCode::NOSUPPORT), } } @@ -315,6 +329,8 @@ impl<'a, I: I2CDevice> Bus<'a> for I2CMasterBus<'a, I> { // endianess does not matter as the buffer is sent as is let bytes = data_width.width_in_bytes(); self.len.set(len * bytes); + + //TODO: might crash if len * bytes < 255 && buffer.len() >= len * bytes { debug!("write len {}", len); self.len.set(len); diff --git a/capsules/extra/src/graphics_display.rs b/capsules/extra/src/graphics_display.rs new file mode 100644 index 0000000000..10518af034 --- /dev/null +++ b/capsules/extra/src/graphics_display.rs @@ -0,0 +1,577 @@ +//! Provides userspace with access to the screen. +//! +//! Usage +//! ----- +//! +//! You need a screen that provides the `hil::screen::Screen` trait. +//! +//! ```rust +//! let screen = +//! components::screen::ScreenComponent::new(board_kernel, tft).finalize(); +//! ``` + +use core::cell::Cell; +use core::convert::From; + +use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount}; +use kernel::processbuffer::ReadableProcessBuffer; +use kernel::syscall::{CommandReturn, SyscallDriver}; +use kernel::utilities::cells::{OptionalCell, TakeCell}; +use kernel::{ErrorCode, ProcessId}; + +use kernel::hil::display::{GraphicsFrame, GraphicsMode, PixelFormat, Point, Rotation}; + +/// Syscall driver number. +use capsules_core::driver; +pub const DRIVER_NUM: usize = driver::NUM::Screen as usize; + +/// Ids for read-only allow buffers +mod ro_allow { + pub const SHARED: usize = 0; + /// The number of allow buffers the kernel stores for this grant + pub const COUNT: u8 = 1; +} + +fn screen_rotation_from(screen_rotation: usize) -> Option { + match screen_rotation { + 0 => Some(Rotation::Normal), + 1 => Some(Rotation::Rotated90), + 2 => Some(Rotation::Rotated180), + 3 => Some(Rotation::Rotated270), + _ => None, + } +} + +fn screen_pixel_format_from(screen_pixel_format: usize) -> Option { + match screen_pixel_format { + 0 => Some(PixelFormat::Mono), + 1 => Some(PixelFormat::RGB_233), + 2 => Some(PixelFormat::RGB_565), + 3 => Some(PixelFormat::RGB_888), + 4 => Some(PixelFormat::ARGB_8888), + _ => None, + } +} + +#[derive(Clone, Copy, PartialEq)] +enum ScreenCommand { + Nop, + SetBrightness(u16), + SetPower(bool), + SetInvert(bool), + SetRotation(Rotation), + SetMode(GraphicsMode), + // SetPixelFormat(PixelFormat), + SetWriteFrame { origin: Point, size: GraphicsFrame }, + Write(usize), + Fill, +} + +fn pixels_in_bytes(pixels: usize, bits_per_pixel: usize) -> usize { + let bytes = pixels * bits_per_pixel / 8; + if pixels * bits_per_pixel % 8 != 0 { + bytes + 1 + } else { + bytes + } +} + +pub struct App { + pending_command: bool, + write_position: usize, + write_len: usize, + command: ScreenCommand, + width: u16, + height: u16, +} + +impl Default for App { + fn default() -> App { + App { + pending_command: false, + command: ScreenCommand::Nop, + width: 0, + height: 0, + write_len: 0, + write_position: 0, + } + } +} + +pub struct GraphicDisplay<'a> { + display: &'a dyn kernel::hil::display::GraphicDisplay<'a>, + display_setup: Option<&'a dyn kernel::hil::display::FrameBufferSetup<'a>>, + apps: Grant, AllowRoCount<{ ro_allow::COUNT }>, AllowRwCount<0>>, + current_process: OptionalCell, + display_format: Cell, + buffer: TakeCell<'static, [u8]>, +} + +impl<'a> GraphicDisplay<'a> { + pub fn new( + display: &'a dyn kernel::hil::display::GraphicDisplay<'a>, + display_setup: Option<&'a dyn kernel::hil::display::FrameBufferSetup<'a>>, + buffer: &'static mut [u8], + grant: Grant, AllowRoCount<{ ro_allow::COUNT }>, AllowRwCount<0>>, + ) -> GraphicDisplay<'a> { + GraphicDisplay { + display, + display_setup, + apps: grant, + current_process: OptionalCell::empty(), + display_format: Cell::new(display.get_mode()), + buffer: TakeCell::new(buffer), + } + } + + // Check to see if we are doing something. If not, + // go ahead and do this command. If so, this is queued + // and will be run when the pending command completes. + fn enqueue_command(&self, command: ScreenCommand, process_id: ProcessId) -> CommandReturn { + match self + .apps + .enter(process_id, |app, _| { + if app.pending_command { + CommandReturn::failure(ErrorCode::BUSY) + } else { + app.pending_command = true; + app.command = command; + app.write_position = 0; + CommandReturn::success() + } + }) + .map_err(ErrorCode::from) + { + Err(e) => CommandReturn::failure(e), + Ok(r) => { + if self.current_process.is_none() { + self.current_process.set(process_id); + let r = self.call_screen(command, process_id); + if r != Ok(()) { + self.current_process.clear(); + } + CommandReturn::from(r) + } else { + r + } + } + } + } + + fn is_len_multiple_color_depth(&self, len: usize) -> bool { + let depth = pixels_in_bytes(1, self.display.get_mode().pixel_format.get_bits_per_pixel()); + (len % depth) == 0 + } + + fn call_screen(&self, command: ScreenCommand, process_id: ProcessId) -> Result<(), ErrorCode> { + match command { + ScreenCommand::SetBrightness(brighness) => self.display.set_brightness(brighness), + ScreenCommand::SetPower(enabled) => self.display.set_power(enabled), + ScreenCommand::SetInvert(enabled) => self.display.set_invert(enabled), + ScreenCommand::SetRotation(rotation) => self.display.set_rotation(rotation), + ScreenCommand::SetMode(graphics_mode) => { + if let Some(display) = self.display_setup { + display.set_mode(graphics_mode) + } else { + Err(ErrorCode::NOSUPPORT) + } + } + ScreenCommand::Fill => match self + .apps + .enter(process_id, |app, kernel_data| { + let len = kernel_data + .get_readonly_processbuffer(ro_allow::SHARED) + .map_or(0, |shared| shared.len()); + // Ensure we have a buffer that is the correct size + if len == 0 { + Err(ErrorCode::NOMEM) + } else if !self.is_len_multiple_color_depth(len) { + Err(ErrorCode::INVAL) + } else { + app.write_position = 0; + app.write_len = pixels_in_bytes( + app.width as usize * app.height as usize, + self.display_format.get().pixel_format.get_bits_per_pixel(), + ); + Ok(()) + } + }) + .unwrap_or_else(|err| err.into()) + { + Err(e) => Err(e), + Ok(()) => self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| { + let len = self.fill_next_buffer_for_write(buffer); + if len > 0 { + self.display.write(buffer, len, false) + } else { + self.buffer.replace(buffer); + self.run_next_command(kernel::errorcode::into_statuscode(Ok(())), 0, 0); + Ok(()) + } + }), + }, + + ScreenCommand::Write(data_len) => match self + .apps + .enter(process_id, |app, kernel_data| { + let len = kernel_data + .get_readonly_processbuffer(ro_allow::SHARED) + .map_or(0, |shared| shared.len()) + .min(data_len); + // Ensure we have a buffer that is the correct size + if len == 0 { + Err(ErrorCode::NOMEM) + } else if !self.is_len_multiple_color_depth(len) { + Err(ErrorCode::INVAL) + } else { + app.write_position = 0; + app.write_len = len; + Ok(()) + } + }) + .unwrap_or_else(|err| err.into()) + { + Ok(()) => self.buffer.take().map_or(Err(ErrorCode::FAIL), |buffer| { + let len = self.fill_next_buffer_for_write(buffer); + if len > 0 { + self.display.write(buffer, len, false) + } else { + self.buffer.replace(buffer); + self.display.flush() + } + }), + Err(e) => Err(e), + }, + + ScreenCommand::SetWriteFrame { + origin: Point { x, y }, + size: GraphicsFrame { width, height }, + } => self + .apps + .enter(process_id, |app, _| { + app.write_position = 0; + app.width = width; + app.height = height; + + self.display + .set_write_frame(Point { x, y }, GraphicsFrame { width, height }) + }) + .unwrap_or_else(|err| err.into()), + _ => Err(ErrorCode::NOSUPPORT), + } + } + + fn schedule_callback(&self, data1: usize, data2: usize, data3: usize) { + if let Some(process_id) = self.current_process.take() { + let _ = self.apps.enter(process_id, |app, upcalls| { + app.pending_command = false; + upcalls.schedule_upcall(0, (data1, data2, data3)).ok(); + }); + } + } + + fn run_next_command(&self, data1: usize, data2: usize, data3: usize) { + self.schedule_callback(data1, data2, data3); + + let mut command = ScreenCommand::Nop; + + // Check if there are any pending events. + for app in self.apps.iter() { + let process_id = app.processid(); + let start_command = app.enter(|app, _| { + if app.pending_command { + app.pending_command = false; + command = app.command; + self.current_process.set(process_id); + true + } else { + false + } + }); + if start_command { + match self.call_screen(command, process_id) { + Err(err) => { + self.current_process.clear(); + self.schedule_callback(kernel::errorcode::into_statuscode(Err(err)), 0, 0); + } + Ok(()) => { + break; + } + } + } + } + } + + fn fill_next_buffer_for_write(&self, buffer: &mut [u8]) -> usize { + let (before, after) = self.display.get_buffer_padding(); + self.current_process.map_or_else( + || 0, + |process_id| { + self.apps + .enter(*process_id, |app, kernel_data| { + let position = app.write_position; + let mut len = app.write_len; + // debug!("position is {} and len is {}, (before, after) - ({}, {})", position, len, before, after); + if position < len { + let buffer_size = buffer.len(); + let chunk_number = position / buffer_size; + let initial_pos = chunk_number * buffer_size; + let mut pos = initial_pos; + match app.command { + ScreenCommand::Write(_) => { + let res = kernel_data + .get_readonly_processbuffer(ro_allow::SHARED) + .and_then(|shared| { + shared.enter(|s| { + let mut chunks = + s.chunks(buffer_size - before - after); + if let Some(chunk) = chunks.nth(chunk_number) { + for item in buffer.iter_mut().take(before) { + *item = 0x00; + } + for (i, byte) in chunk.iter().enumerate() { + if pos + after < len { + buffer[i + before] = byte.get(); + pos += 1 + } else { + break; + } + } + for item in buffer + .iter_mut() + .take(buffer_size) + .skip(before + chunk.len()) + { + *item = 0x00; + } + app.write_len - initial_pos + } else { + // stop writing + 0 + } + }) + }) + .unwrap_or(0); + // debug!("in fill buffer {}", res); + if res > 0 { + app.write_position = pos; + } + res + } + ScreenCommand::Fill => { + // TODO bytes per pixel + len -= position; + let bytes_per_pixel = pixels_in_bytes( + 1, + self.display_format.get().pixel_format.get_bits_per_pixel(), + ); + let mut write_len = + (buffer_size - before - after) / bytes_per_pixel; + if write_len > len { + write_len = len + }; + app.write_position += write_len * bytes_per_pixel; + kernel_data + .get_readonly_processbuffer(ro_allow::SHARED) + .and_then(|shared| { + shared.enter(|data| { + let mut bytes = data.iter(); + // bytes per pixel + + for item in buffer.iter_mut().take(bytes_per_pixel) + { + if let Some(byte) = bytes.next() { + *item = byte.get(); + } + } + for i in 1..write_len { + // bytes per pixel + for j in 0..bytes_per_pixel { + buffer[bytes_per_pixel * i + j] = buffer[j] + } + } + write_len * bytes_per_pixel + }) + }) + .unwrap_or(0) + } + _ => 0, + } + } else { + 0 + } + }) + .unwrap_or(0) + }, + ) + } +} + +impl<'a> kernel::hil::display::ScreenClient for GraphicDisplay<'a> { + fn command_complete(&self, r: Result<(), ErrorCode>) { + // debug!("[display capsule] command complete received from screen client cu {:?}", r); + self.run_next_command(kernel::errorcode::into_statuscode(r), 0, 0); + } +} + +impl<'a> kernel::hil::display::FrameBufferClient for GraphicDisplay<'a> { + fn write_complete(&self, buffer: &'static mut [u8], r: Result<(), ErrorCode>) { + // debug!("[display capsule] write complete received from client"); + let len = self.fill_next_buffer_for_write(buffer); + + if r == Ok(()) && len > 0 { + let _ = self.display.write(buffer, len, false); + } else { + self.buffer.replace(buffer); + let _ = self.display.flush(); + // self.run_next_command(kernel::errorcode::into_statuscode(r), 0, 0); + } + } + + fn command_complete(&self, r: Result<(), ErrorCode>) { + // debug!("[display capsule] command complete received from frame buffer client"); + self.run_next_command(kernel::errorcode::into_statuscode(r), 0, 0); + } +} + +impl<'a> SyscallDriver for GraphicDisplay<'a> { + fn command( + &self, + command_num: usize, + data1: usize, + data2: usize, + process_id: ProcessId, + ) -> CommandReturn { + match command_num { + 0 => + // This driver exists. + { + CommandReturn::success() + } + // Does it have the screen setup + 1 => CommandReturn::success_u32(self.display_setup.is_some() as u32), + // Set power + 2 => self.enqueue_command(ScreenCommand::SetPower(data1 != 0), process_id), + // Set Brightness + 3 => self.enqueue_command(ScreenCommand::SetBrightness(data1 as u16), process_id), + // Invert on (deprecated) + 4 => self.enqueue_command(ScreenCommand::SetInvert(true), process_id), + // Invert off (deprecated) + 5 => self.enqueue_command(ScreenCommand::SetInvert(false), process_id), + // Set Invert + 6 => self.enqueue_command(ScreenCommand::SetInvert(data1 != 0), process_id), + + // Get Graphics Modes count + 11 => { + if let Some(display) = self.display_setup { + CommandReturn::success_u32(display.get_num_supported_modes() as u32) + } else { + CommandReturn::failure(ErrorCode::NOSUPPORT) + } + } + // Get Graphics Mode + 12 => { + if let Some(display) = self.display_setup { + match display.get_supported_mode(data1) { + Some(GraphicsMode { + frame: GraphicsFrame { width, height }, + pixel_format, + }) if width > 0 && height > 0 => CommandReturn::success_u32_u32( + (width as u32) << 16 | (height as u32), + pixel_format as u32, + ), + _ => CommandReturn::failure(ErrorCode::INVAL), + } + } else { + CommandReturn::failure(ErrorCode::NOSUPPORT) + } + } + + // Get Rotation + 21 => CommandReturn::success_u32(self.display.get_rotation() as u32), + // Set Rotation + 22 => self.enqueue_command( + ScreenCommand::SetRotation(screen_rotation_from(data1).unwrap_or(Rotation::Normal)), + process_id, + ), + + // Get Resolution + 23 => { + let GraphicsMode { + frame: GraphicsFrame { width, height }, + pixel_format: _, + } = self.display.get_mode(); + CommandReturn::success_u32_u32(width as u32, height as u32) + } + // Set Resolution + 24 => { + let GraphicsMode { + frame: _, + pixel_format, + } = self.display.get_mode(); + self.enqueue_command( + ScreenCommand::SetMode(GraphicsMode { + frame: GraphicsFrame { + width: data1 as u16, + height: data2 as u16, + }, + pixel_format, + }), + process_id, + ) + } + + // Get pixel format + 25 => { + let GraphicsMode { + frame: _, + pixel_format, + } = self.display.get_mode(); + CommandReturn::success_u32(pixel_format as u32) + } + // Set pixel format + 26 => { + if let Some(new_pixel_format) = screen_pixel_format_from(data1) { + let GraphicsMode { + frame, + pixel_format: _, + } = self.display.get_mode(); + self.enqueue_command( + ScreenCommand::SetMode(GraphicsMode { + frame, + pixel_format: new_pixel_format, + }), + process_id, + ) + } else { + CommandReturn::failure(ErrorCode::INVAL) + } + } + + // Set Write Frame + 100 => self.enqueue_command( + ScreenCommand::SetWriteFrame { + origin: Point { + x: ((data1 >> 16) & 0xFFFF) as u16, + y: (data1 & 0xFFFF) as u16, + }, + size: GraphicsFrame { + width: ((data2 >> 16) & 0xFFFF) as u16, + height: (data2 & 0xFFFF) as u16, + }, + }, + process_id, + ), + // Write + 200 => self.enqueue_command(ScreenCommand::Write(data1), process_id), + // Fill + 300 => self.enqueue_command(ScreenCommand::Fill, process_id), + + _ => CommandReturn::failure(ErrorCode::NOSUPPORT), + } + } + + fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> { + self.apps.enter(processid, |_, _| {}) + } +} diff --git a/capsules/extra/src/lib.rs b/capsules/extra/src/lib.rs index d667586acd..455795fb74 100644 --- a/capsules/extra/src/lib.rs +++ b/capsules/extra/src/lib.rs @@ -36,6 +36,7 @@ pub mod fm25cl; pub mod ft6x06; pub mod fxos8700cq; pub mod gpio_async; +pub mod graphics_display; pub mod hd44780; pub mod hmac; pub mod hmac_sha256; @@ -85,6 +86,7 @@ pub mod si7021; pub mod sip_hash; pub mod sound_pressure; pub mod st77xx; +pub mod ssd1306; pub mod symmetric_encryption; pub mod temperature; pub mod temperature_rp2040; diff --git a/capsules/extra/src/ssd1306.rs b/capsules/extra/src/ssd1306.rs new file mode 100644 index 0000000000..ba470918c1 --- /dev/null +++ b/capsules/extra/src/ssd1306.rs @@ -0,0 +1,863 @@ +use kernel::{ + utilities::cells::{OptionalCell, TakeCell}, + ErrorCode, +}; + +//TODO; wtf is this? +use kernel::deferred_call::{ + DeferredCallHandle, DynamicDeferredCall, DynamicDeferredCallClient, +}; + +use crate::bus::{self, Bus, BusWidth}; +use kernel::hil::display::{ + Align, FrameBuffer, FrameBufferClient, FrameBufferSetup, GraphicsFrame, GraphicsMode, + PixelFormat, Point, Rotation, Screen, ScreenClient, Tile, +}; +use core::cell::Cell; + +pub const SLAVE_ADDRESS_WRITE: u8 = 0b0111100; +pub const SLAVE_ADDRESS_READ: u8 = 0b0111101; +pub const WIDTH: usize = 128; +pub const HEIGHT: usize = 64; +pub const BUFFER_PADDING: usize = 1; +pub const TILE_SIZE: u16 = 8; +pub const I2C_ADDR: usize = 0x3D; +pub const WRITE_COMMAND: u8 = 0x40; +pub const CONTROL_COMMAND: u8 = 0x00; + +pub const BUFFER_SIZE: usize = 64; +pub const SEQUENCE_BUFFER_SIZE: usize = 32; +#[derive(PartialEq, Copy, Clone)] +pub struct ScreenCommand { + pub id: CommandId, + pub parameters: Option<&'static [u8]>, +} + +#[repr(u8)] +pub enum MemoryAddressing { + Page = 0x10, + Horizontal = 0x00, + Vertical = 0x01, +} + +#[derive(Copy, Clone, PartialEq, Debug)] +enum ScreenStatus { + Idle, + Init, + Error(ErrorCode), + SendCommand, + SendCommandId(bool, usize), + SendCommandArguments(usize), + SendCommandArgumentsDone, + WriteData, +} + +#[derive(Copy, Clone, PartialEq, Debug)] +enum ScreenAsyncCommand { + Idle, + AsyncFrameBufferCommand(Result<(), kernel::ErrorCode>), + AsyncScreenCommand(Result<(), kernel::ErrorCode>), + Write(Result<(), kernel::ErrorCode>), +} + +#[derive(PartialEq, Copy, Clone)] +#[repr(u8)] +pub enum CommandId { + /* Fundamental Commands */ + // Contrast Control - 2 bytes command + // 2nd byte: contrast step - 0 <-> 255 + SetContrastControl = 0x81, + + // Entire Display ON + // 0xA4 - output follows RAM content + // 0xA5 - output ignores RAM content + EntireDisplay = 0xA4, + + // Set Normal Display - 0xA6 + // 0/1 in RAM - OFF/ON in display panel + // Set Inverse Display - 0xA7 + // 0/1 in RAM - ON?OFF in display panel + SetNormalDisplayOn = 0xA6, + SetNormalDisplayOff = 0xA7, + + // Set Display Off - 0xAE + // Set Display On - 0xAF + SetDisplayOff = 0xAE, + SetDisplayOn = 0xAF, + + /* Addressing Settings */ + // Set Lower Column - 0x00 <-> 0x0F + SetLowerColumn = 0x00, + + // Set Higher Column - 0x10 <-> 0x1F + SetHigherColumn = 0x10, + + // Set Memory Addressing Mode - 2 bytes command + // 2nd byte: MemoryAddressing enum + SetMemoryMode = 0x20, + + // Set Column Address - 3 bytes command + // 2nd byte: column start address (0-127) + // 3rd byte: column end address (0-127) + SetColumnAddr = 0x21, + + // Set Page Address - 3 bytes command + // 2nd byte: page start address (0-7) + // 3rd byte: page end address (0-7) + SetPageAddr = 0x22, + + // Set Page Start Address for MemoryAddressing::Page - 0xB0 <-> 0xB7 + SetPageStart = 0xB0, + + /* Hardware Configuration */ + // Set Display Start Line - 0x40 <-> 0x7F + SetDisplayStart = 0x40, + + // Set Segment Re-map + // column address 0 -> SEG0 - 0xA0 + // column address 127 -> SEG0 - 0xA1 + SetSegmentRemap0 = 0xA0, + SetSegmentRemap127 = 0xA1, + + // Set Multiplex Radio - 2 bytes command + // 2nd byte: mux - 16 <-> 64 + SetMultiplexRadio = 0xA8, + + // Set COM Output Scan Direction + // from COM0 -> COM[multiplex radio - 1] - 0xC0 + // from COM[multiplex radio - 1] -> COM0 - 0xC8 + SetCOMOutputScanAsc = 0xC0, + SetCOMOutputScanDes = 0xC8, + + // Set Display Offset - 2 bytes command + // 2nd byte: the vertical shift - 0 <->63 + SetDisplayOffset = 0xD3, + + // Set COM Pins - 2 bytes command + // 2nd byte: - bit 4: 0 -> seq COM pin configuration + // 1 -> reset + alternative pin configuration + // - bit 5: 0 -> reset + disable COM left/right remap + // 1 -> enable COM left/right remap + SetCOMPins = 0xDA, + + /* Timing & Driving Scheme Setting */ + // Set Display Clock Divide Ratio + Oscillator Freq - 2 bytes command + // 2nd byte: - bits 3:0 -> divide ratio (D) of the display clocks (DCLK) + // D = bits 3:0 + 1 + // - bits 7:4 -> adds to the oscillator frequency + SetDisplayClockDivideRatio = 0xD5, + + // Set Pre-charge period - 2 bytes command + // 2nd byte: - bits 3:0 -> phase 1 period: 1 <-> 15 + // - bits 7:4 -> phase 2 period: 1 <-> 15 + SetPreChargePeriod = 0xD9, + + // Set Vcomh Deselect Level - 2 bytes command + // 2nd byte: bits 6:4 - 000b (0,65), 010b (0,77), 020b (0,83) + SetVcomhDeselect = 0xDB, + + // Nop + Nop = 0xE3, + Write = 0xE4, + + /* Scrolling Commands */ + // Continous Horizontal Scroll Setup - 7 bytes commands + // 2nd, 6th and 7th bytes: dummy bytes + // 3rd byte: start page address - 0 <-> 7 + // 4th byte: set time interval between each scroll step in frame freq + // 000b -> 5 | 001b -> 64 | 010b -> 128 | 011b -> 256 + // 100b -> 3 | 101b -> 4 | 110b -> 25 | 111b -> 2 + // 5th byte: end page address - 0 <-> 7 (>= 3rd byte) + ContHorizontalScrollRight = 0x26, + ContHorizontalScrollLeft = 0x27, + + // Continous Horizontal & Vertical Scroll Setup - 6 bytes commands + // 2nd byte: dummy byte + // 3rd byte: start page address - 0 <-> 7 + // 4th byte: set time interval between each scroll step in frame freq + // 000b -> 5 | 001b -> 64 | 010b -> 128 | 011b -> 256 + // 100b -> 3 | 101b -> 4 | 110b -> 25 | 111b -> 2 + // 5th byte: end page address - 0 <-> 7 (>= 3rd byte) + // 6th byte: vertical scroll offset - 0 <-> 63 + ContVertHorizontalScrollRight = 0x29, + ContVertHorizontalScrollLeft = 0x2A, + + // Deactivate Scrolling that is configured by one of the last 4 commands + DeactivateScrolling = 0x2E, + + // Activate Scrolling that is configured by one of the last 4 commands + // Overwrites the previously configured setup + ActivateScrolling = 0x2F, + + // Set Vertical Scroll Area - 3 bytes command + // 2nd byte: number of rows in top fixed area + // 3rd byte: number of rows in scroll area + SetVerticalScroll = 0xA3, + + /* Charge Pump Settings */ + // Charge Pump Command - 2 bytes command + // 2nd byte: - 0x14 - enable (followed by 0xAF - display on) + // - 0x10 - disable + ChargePump = 0x8D, +} + +const SSD1306_INIT_SEQ: [ScreenCommand; 20] = [ + ScreenCommand { + id: CommandId::SetDisplayOff, + parameters: None, + }, + ScreenCommand { + id: CommandId::SetDisplayClockDivideRatio, + parameters: Some(&[CONTROL_COMMAND, 0x80]), + }, + ScreenCommand { + id: CommandId::SetMultiplexRadio, + parameters: Some(&[CONTROL_COMMAND, HEIGHT as u8 - 1]), + }, + ScreenCommand { + id: CommandId::SetDisplayOffset, + parameters: Some(&[CONTROL_COMMAND, 0x00]), + }, + ScreenCommand { + id: CommandId::SetDisplayStart, + parameters: None, + }, + ScreenCommand { + id: CommandId::ChargePump, + parameters: Some(&[CONTROL_COMMAND, 0x14]), + }, + ScreenCommand { + id: CommandId::SetMemoryMode, + parameters: Some(&[CONTROL_COMMAND, MemoryAddressing::Horizontal as u8]), + }, + ScreenCommand { + id: CommandId::SetSegmentRemap127, + parameters: None, + }, + ScreenCommand { + id: CommandId::SetCOMOutputScanDes, + parameters: None, + }, + ScreenCommand { + id: CommandId::SetCOMPins, + parameters: Some(&[CONTROL_COMMAND, 0x12]), + }, + ScreenCommand { + id: CommandId::SetContrastControl, + parameters: Some(&[CONTROL_COMMAND, 0xCF]), + }, + ScreenCommand { + id: CommandId::SetPreChargePeriod, + parameters: Some(&[CONTROL_COMMAND, 0xF1]), + }, + ScreenCommand { + id: CommandId::SetVcomhDeselect, + parameters: Some(&[CONTROL_COMMAND, 0x40]), + }, + ScreenCommand { + id: CommandId::EntireDisplay, + parameters: None, + }, + ScreenCommand { + id: CommandId::SetNormalDisplayOn, + parameters: None, + }, + ScreenCommand { + id: CommandId::DeactivateScrolling, + parameters: None, + }, + ScreenCommand { + id: CommandId::SetDisplayOn, + parameters: None, + }, + ScreenCommand { + id: CommandId::SetPageAddr, + parameters: Some(&[CONTROL_COMMAND, 0x00, 0xFF]), + }, + ScreenCommand { + id: CommandId::SetColumnAddr, + parameters: Some(&[CONTROL_COMMAND, 0x00, WIDTH as u8 - 1]), + }, + ScreenCommand { + id: CommandId::Write, + parameters: None, + }, + // ScreenCommand { + // id: CommandId::SetPageAddr, + // parameters: Some(&[CONTROL_COMMAND, 0x02, 0x5]), + // }, + // ScreenCommand { + // id: CommandId::SetColumnAddr, + // parameters: Some(&[CONTROL_COMMAND, 0xA, WIDTH as u8 - 0x10]), + // }, + // ScreenCommand { + // id: CommandId::Write, + // parameters: None, + // }, + // ScreenCommand { + // id: CommandId::Write, + // parameters: None, + // } +]; + +pub struct SSD1306<'a, B: Bus<'a>> { + bus: &'a B, + status: Cell, + async_status: Cell, + + rotation: Cell, + graphics_mode: Cell, + origin: Cell, + tile: Cell, + + app_write_buffer: TakeCell<'static, [u8]>, + bus_write_buffer: TakeCell<'static, [u8]>, + aux_write_buffer: TakeCell<'static, [u8]>, + write_buffer_len: Cell, + write_buffer_position: Cell, + + command_sequence: TakeCell<'static, [ScreenCommand]>, + command_sequence_length: Cell, + command_sequence_position: Cell, + command_arguments: TakeCell<'static, [u8]>, + + initialization_complete: Cell, + screen_client: OptionalCell<&'static dyn ScreenClient>, + frame_buffer_client: OptionalCell<&'static dyn FrameBufferClient>, + + deferred_caller: &'a DynamicDeferredCall, + handle: OptionalCell, + + initial_write: Cell, + invert: Cell, +} + +impl<'a, B: Bus<'a>> SSD1306<'a, B> { + pub fn new( + bus: &'a B, + command_sequence: &'static mut [ScreenCommand], + command_arguments: &'static mut [u8], + app_write_buffer: &'static mut [u8], + bus_write_buffer: &'static mut [u8], + aux_write_buffer: &'static mut [u8], + deferred_caller: &'a DynamicDeferredCall, + ) -> SSD1306<'a, B> { + SSD1306 { + bus, + status: Cell::new(ScreenStatus::Idle), + async_status: Cell::new(ScreenAsyncCommand::Idle), + rotation: Cell::new(Rotation::Normal), + origin: Cell::new(Point { x: 0, y: 0 }), + tile: Cell::new(Tile { + align: Align { + horizontal: 0, + vertical: 0, + }, + size: GraphicsFrame { + width: TILE_SIZE, + height: TILE_SIZE, + }, + }), + graphics_mode: Cell::new(GraphicsMode { + frame: GraphicsFrame { + width: WIDTH as u16, + height: HEIGHT as u16, + }, + pixel_format: PixelFormat::Mono, + }), + app_write_buffer: TakeCell::new(app_write_buffer), + bus_write_buffer: TakeCell::new(bus_write_buffer), + aux_write_buffer: TakeCell::new(aux_write_buffer), + write_buffer_len: Cell::new(0), + write_buffer_position: Cell::new(0), + command_sequence: TakeCell::new(command_sequence), + command_sequence_length: Cell::new(0), + command_sequence_position: Cell::new(0), + command_arguments: TakeCell::new(command_arguments), + initialization_complete: Cell::new(false), + screen_client: OptionalCell::empty(), + frame_buffer_client: OptionalCell::empty(), + initial_write: Cell::new(false), + deferred_caller, + handle: OptionalCell::empty(), + invert: Cell::new(false), + } + } + + pub fn init(&self) -> Result<(), ErrorCode> { + if self.status.get() == ScreenStatus::Idle { + self.status.set(ScreenStatus::Init); + self.do_next_op(); + Ok(()) + } else { + Err(ErrorCode::BUSY) + } + } + + pub fn initialize_callback_handle(&self, handle: DeferredCallHandle) { + self.handle.replace(handle); + } + + pub fn do_next_op(&self) { + match self.status.get() { + ScreenStatus::Init => { + self.status.set(ScreenStatus::Idle); + if let Err(err) = self.prepare_init_sequence() { + self.status.set(ScreenStatus::Error(err)); + } else { + self.command_sequence_position.set(0); + self.status.set(ScreenStatus::SendCommand); + } + self.do_next_op(); + } + ScreenStatus::Idle => {} + ScreenStatus::Error(err) => { + panic!("{:?}", err); + } + ScreenStatus::SendCommand => { + let position = self.command_sequence_position.get(); + if position < self.command_sequence_length.get() { + self.command_sequence.map_or_else( + || panic!("ssd1306: do next op has no command sequence buffer"), + |command_sequence| { + self.send_command(command_sequence[position]); + }, + ) + } else { + // todo commands done + self.status.set(ScreenStatus::Idle); + if !self.initialization_complete.get() { + self.initialization_complete.set(true); + self.command_sequence_position.set(0); + self.command_sequence_length.set(0); + } else { + self.do_next_op(); + } + } + } + ScreenStatus::SendCommandId(arguments, len) => { + if arguments { + self.status.set(ScreenStatus::SendCommandArguments(len)); + self.do_next_op(); + } else { + self.command_sequence_position + .set(self.command_sequence_position.get() + 1); + self.status.set(ScreenStatus::SendCommand); + self.do_next_op(); + } + } + ScreenStatus::SendCommandArguments(len) => { + self.send_arguments(len); + } + ScreenStatus::SendCommandArgumentsDone => { + self.command_sequence_position + .set(self.command_sequence_position.get() + 1); + self.status.set(ScreenStatus::SendCommand); + self.do_next_op(); + } + ScreenStatus::WriteData => { + self.prepare_write_buffer(); + self.status.set(ScreenStatus::SendCommand); + self.do_next_op(); + } + } + } + + fn send_arguments(&self, len: usize) { + self.command_arguments.take().map_or_else( + || panic!("ssd1306: send argument has no command arguments buffer"), + |arguments| { + self.status.set(ScreenStatus::SendCommandArgumentsDone); + let _ = self.bus.write(BusWidth::Bits8, arguments, len); + }, + ); + } + + fn prepare_write_buffer(&self) { + self.bus_write_buffer.map_or_else( + || panic!("write function has no write buffer"), + |bus_write_buffer| { + bus_write_buffer[0] = WRITE_COMMAND; + + self.aux_write_buffer.map_or_else( + || panic!("write function has no app write buffer"), + |app_write_buffer| { + let mut app_buf_index = 0; + let GraphicsMode { + frame: GraphicsFrame { width, height }, + pixel_format: _, + } = self.graphics_mode.get(); + let Point { x, y } = self.origin.get(); + for h in y..y + height { + for _l in x..x + width { + for index in 0..8 { + let bit = (app_write_buffer[app_buf_index] + & (1 << (7 - index))) + >> (7 - index); + let buffer_index = (app_buf_index % (width as usize / 8)) * 8 + + h as usize * WIDTH + + index + + x as usize; + let bit_index = ((app_buf_index % width as usize) + / (width as usize / 8)) + as u8; + + if bit == 0 { + bus_write_buffer[buffer_index] &= !(1 << bit_index); + } else if bit == 1 { + bus_write_buffer[buffer_index] |= 1 << bit_index; + } + } + app_buf_index += 1; + } + } + }, + ); + }, + ); + } + + fn send_command(&self, cmd: ScreenCommand) { + if cmd.id == CommandId::Write { + self.bus_write_buffer.take().map_or_else( + || panic!("ssd1306: send_command has no write buffer"), + |buffer| { + buffer[0] = WRITE_COMMAND; + if !self.initial_write.get() { + self.initial_write.set(true); + let GraphicsMode { + frame: GraphicsFrame { width, height }, + pixel_format: _, + } = self.graphics_mode.get(); + self.write_buffer_len.set((height * width) as usize / 8); + for i in 0..self.write_buffer_len.get() { + buffer[i + 1] = 0x00; + } + } + for i in 1..buffer.len() { + buffer[i] = !buffer[i]; + } + self.status.set(ScreenStatus::SendCommandId(false, 0)); + let _ = self.bus.write(BusWidth::Bits8, buffer, buffer.len()); + }, + ) + } else { + let _ = self.bus.set_addr(BusWidth::Bits16LE, cmd.id as usize); + let new_state = if let Some(params) = cmd.parameters { + self.populate_arguments_buffer(cmd); + ScreenStatus::SendCommandId(true, params.len()) + } else { + ScreenStatus::SendCommandId(false, 0) + }; + self.status.set(new_state); + } + } + + fn populate_arguments_buffer(&self, cmd: ScreenCommand) { + self.command_arguments.map_or_else( + || panic!("ssd1306 populate arguments has no command arguments buffer"), + |command_buffer| { + if let Some(parameters) = cmd.parameters { + for (i, param) in parameters.iter().enumerate() { + command_buffer[i] = *param; + } + } + }, + ) + } + + fn prepare_init_sequence(&self) -> Result<(), ErrorCode> { + if self.status.get() == ScreenStatus::Idle { + self.command_sequence.map_or_else( + || panic!("ssd1306: init sequence has no command sequence buffer"), + |command_sequence| { + if SSD1306_INIT_SEQ.len() <= command_sequence.len() { + self.command_sequence_length.set(SSD1306_INIT_SEQ.len()); + for (i, cmd) in SSD1306_INIT_SEQ.iter().enumerate() { + command_sequence[i] = *cmd; + } + Ok(()) + } else { + Err(ErrorCode::NOMEM) + } + }, + ) + } else { + Err(ErrorCode::BUSY) + } + } + + fn prepare_write_sequence(&self) -> Result<(), ErrorCode> { + if self.status.get() == ScreenStatus::Idle { + self.command_sequence.map_or_else( + || panic!("ssd1306: write sequence has no command sequence buffer"), + |command_sequence| { + command_sequence[0] = ScreenCommand { + id: CommandId::SetPageAddr, + parameters: Some(&[CONTROL_COMMAND, 0x00, 0xFF]), + }; + command_sequence[1] = ScreenCommand { + id: CommandId::SetColumnAddr, + parameters: Some(&[CONTROL_COMMAND, 0x00, WIDTH as u8 - 1]), + }; + command_sequence[2] = ScreenCommand { + id: CommandId::Write, + parameters: None, + }; + self.command_sequence_length.set(3); + self.command_sequence_position.set(0); + Ok(()) + }, + ) + } else { + Err(ErrorCode::BUSY) + } + } +} + +impl<'a, B: Bus<'a>> bus::Client for SSD1306<'a, B> { + fn command_complete( + &self, + buffer: Option<&'static mut [u8]>, + _len: usize, + status: Result<(), kernel::ErrorCode>, + ) { + if let Some(buf) = buffer { + if self.status.get() == ScreenStatus::SendCommandArgumentsDone { + self.command_arguments.replace(buf); + } else { + // write command complete + self.bus_write_buffer.replace(buf); + self.frame_buffer_client.map_or_else( + || panic!("ssd1306: do next op has no screen client"), + |frame_buffer_client| { + // callback + self.write_buffer_len.replace(0); + self.write_buffer_position.replace(0); + frame_buffer_client.command_complete(status); + }, + ); + } + } + + if let Err(err) = status { + self.status.set(ScreenStatus::Error(err)); + } + + self.do_next_op(); + } +} + +impl<'a, B: Bus<'a>> FrameBuffer<'static> for SSD1306<'a, B> { + fn get_mode(&self) -> GraphicsMode { + self.graphics_mode.get() + } + + fn get_tile_format(&self) -> kernel::hil::display::Tile { + self.tile.get() + } + + fn set_write_frame(&self, origin: Point, size: GraphicsFrame) -> Result<(), ErrorCode> { + if !self.initialization_complete.get() { + Err(ErrorCode::OFF) + } else if self.status.get() == ScreenStatus::Idle { + let mut current_mode = self.graphics_mode.get(); + if (origin.x + size.width > WIDTH as u16) || (origin.y + size.height > HEIGHT as u16) { + return Err(ErrorCode::INVAL); + } + current_mode.frame.height = size.height / 8; + current_mode.frame.width = size.width; + self.graphics_mode.replace(current_mode); + self.origin.replace(Point { + x: origin.x, + y: origin.y / 8, + }); + self.async_status + .set(ScreenAsyncCommand::AsyncFrameBufferCommand(Ok(()))); + self.handle.map(|handle| self.deferred_caller.set(*handle)); + Ok(()) + } else { + Err(ErrorCode::BUSY) + } + } + + fn get_buffer_padding(&self) -> (usize, usize) { + (BUFFER_PADDING, 0) + } + + fn write( + &self, + buffer: &'static mut [u8], + len: usize, + reset_position: bool, + ) -> Result<(), ErrorCode> { + let ret = if !self.initialization_complete.get() { + Err(ErrorCode::OFF) + } else if self.status.get() == ScreenStatus::Idle { + if reset_position { + self.write_buffer_position.set(0); + self.write_buffer_len.set(0); + } + self.app_write_buffer.replace(buffer); + let mut status = Ok(()); + self.app_write_buffer.map_or_else( + || panic!("write has no app buffer"), + |app_buffer| { + self.aux_write_buffer.map_or_else( + || panic!("write has no aux buffer"), + |aux_buffer| { + let current_position = self.write_buffer_position.get(); + if len + current_position > aux_buffer.len() { + status = Err(ErrorCode::INVAL); + } else { + aux_buffer[current_position..(len + current_position)] + .copy_from_slice( + &app_buffer[BUFFER_PADDING..(len + BUFFER_PADDING)], + ); + self.write_buffer_position.replace(len + current_position); + } + self.write_buffer_len.set(len + current_position); + }, + ); + }, + ); + status + } else { + Err(ErrorCode::BUSY) + }; + self.async_status.set(ScreenAsyncCommand::Write(ret)); + self.handle.map(|handle| self.deferred_caller.set(*handle)); + ret + } + + fn flush(&self) -> Result<(), ErrorCode> { + if !self.initialization_complete.get() { + Err(ErrorCode::OFF) + } else if self.status.get() == ScreenStatus::Idle { + if self.bus_write_buffer.is_none() { + Err(ErrorCode::NOSUPPORT) + } else { + if let Err(err) = self.prepare_write_sequence() { + self.status.set(ScreenStatus::Error(err)); + } else { + self.status.set(ScreenStatus::WriteData); + } + self.do_next_op(); + Ok(()) + } + } else { + Err(ErrorCode::BUSY) + } + } + + fn set_client(&self, client: Option<&'static dyn FrameBufferClient>) { + if let Some(client) = client { + self.frame_buffer_client.set(client); + } else { + self.frame_buffer_client.clear(); + } + } +} + +impl<'a, B: Bus<'a>> Screen<'static> for SSD1306<'a, B> { + fn get_rotation(&self) -> Rotation { + self.rotation.get() + } + + fn set_client(&self, client: Option<&'static dyn ScreenClient>) { + if let Some(client) = client { + self.screen_client.set(client); + } else { + self.screen_client.clear(); + } + } + + fn set_brightness(&self, _brightness: u16) -> Result<(), kernel::ErrorCode> { + self.async_status + .set(ScreenAsyncCommand::AsyncScreenCommand(Ok(()))); + self.handle.map(|handle| self.deferred_caller.set(*handle)); + Ok(()) + } + + fn set_power(&self, _enabled: bool) -> Result<(), kernel::ErrorCode> { + self.async_status + .set(ScreenAsyncCommand::AsyncScreenCommand(Ok(()))); + self.handle.map(|handle| self.deferred_caller.set(*handle)); + Ok(()) + } + + fn set_invert(&self, enabled: bool) -> Result<(), kernel::ErrorCode> { + self.invert.replace(enabled); + self.async_status + .set(ScreenAsyncCommand::AsyncScreenCommand(Ok(()))); + self.handle.map(|handle| self.deferred_caller.set(*handle)); + Ok(()) + } + + fn set_rotation(&self, rotation: Rotation) -> Result<(), ErrorCode> { + self.rotation.set(rotation); + // todo update origin and graphics mode + self.async_status + .set(ScreenAsyncCommand::AsyncScreenCommand(Ok(()))); + self.handle.map(|handle| self.deferred_caller.set(*handle)); + Ok(()) + } +} + +impl<'a, B: Bus<'a>> FrameBufferSetup<'static> for SSD1306<'a, B> { + fn set_mode(&self, mode: GraphicsMode) -> Result<(), ErrorCode> { + self.graphics_mode.replace(mode); + Ok(()) + } + + fn get_num_supported_modes(&self) -> usize { + 1 + } + + fn get_supported_mode(&self, index: usize) -> Option { + match index { + 0 => Some(self.graphics_mode.get()), + _ => None, + } + } +} + +impl<'a, B: Bus<'a>> DynamicDeferredCallClient for SSD1306<'a, B> { + fn call(&self, _: DeferredCallHandle) { + match self.async_status.get() { + ScreenAsyncCommand::Idle => panic!("Received dynamic call without a caller"), + ScreenAsyncCommand::AsyncScreenCommand(res) => { + self.screen_client.map_or_else( + || panic!("ssd1306: dynamic deferred call client has no screen setup client"), + |screen_client| { + self.async_status.set(ScreenAsyncCommand::Idle); + screen_client.command_complete(res); + }, + ); + } + ScreenAsyncCommand::AsyncFrameBufferCommand(res) => { + self.frame_buffer_client.map_or_else( + || panic!("ssd1306: dynamic deferred call client has no frame buffer client"), + |frame_buffer_client| { + self.async_status.set(ScreenAsyncCommand::Idle); + frame_buffer_client.command_complete(res); + }, + ); + } + ScreenAsyncCommand::Write(res) => { + self.frame_buffer_client.map_or_else( + || panic!("ssd1306: dynamic deferred call client has no frame buffer client"), + |frame_buffer_client| { + self.app_write_buffer.take().map_or_else( + || panic!("ssd1306: dynamic deferred call has no app write buffer"), + |buffer| { + self.async_status.set(ScreenAsyncCommand::Idle); + frame_buffer_client.write_complete(buffer, res); + }, + ); + }, + ); + } + } + } +} diff --git a/kernel/src/hil/display.rs b/kernel/src/hil/display.rs new file mode 100644 index 0000000000..e803994b0a --- /dev/null +++ b/kernel/src/hil/display.rs @@ -0,0 +1,414 @@ +//! Interface for screens and displays. +use core::ops::Add; +use core::ops::Sub; +use crate::ErrorCode; + +pub const MAX_BRIGHTNESS: u16 = 65535; + +#[derive(Copy, Clone, PartialEq)] +pub enum Rotation { + Normal, + Rotated90, + Rotated180, + Rotated270, +} + +impl Add for Rotation { + type Output = Self; + + fn add(self, other: Self) -> Self { + match (self, other) { + (Rotation::Normal, _) => other, + (_, Rotation::Normal) => self, + (Rotation::Rotated90, Rotation::Rotated90) => Rotation::Rotated180, + (Rotation::Rotated90, Rotation::Rotated180) => Rotation::Rotated270, + (Rotation::Rotated90, Rotation::Rotated270) => Rotation::Normal, + + (Rotation::Rotated180, Rotation::Rotated90) => Rotation::Rotated270, + (Rotation::Rotated180, Rotation::Rotated180) => Rotation::Normal, + (Rotation::Rotated180, Rotation::Rotated270) => Rotation::Rotated90, + + (Rotation::Rotated270, Rotation::Rotated90) => Rotation::Normal, + (Rotation::Rotated270, Rotation::Rotated180) => Rotation::Rotated90, + (Rotation::Rotated270, Rotation::Rotated270) => Rotation::Rotated180, + } + } +} + +impl Sub for Rotation { + type Output = Self; + + fn sub(self, other: Self) -> Self { + match (self, other) { + (_, Rotation::Normal) => self, + + (Rotation::Normal, Rotation::Rotated90) => Rotation::Rotated270, + (Rotation::Normal, Rotation::Rotated180) => Rotation::Rotated180, + (Rotation::Normal, Rotation::Rotated270) => Rotation::Rotated90, + + (Rotation::Rotated90, Rotation::Rotated90) => Rotation::Normal, + (Rotation::Rotated90, Rotation::Rotated180) => Rotation::Rotated270, + (Rotation::Rotated90, Rotation::Rotated270) => Rotation::Rotated180, + + (Rotation::Rotated180, Rotation::Rotated90) => Rotation::Rotated90, + (Rotation::Rotated180, Rotation::Rotated180) => Rotation::Normal, + (Rotation::Rotated180, Rotation::Rotated270) => Rotation::Rotated270, + + (Rotation::Rotated270, Rotation::Rotated90) => Rotation::Rotated180, + (Rotation::Rotated270, Rotation::Rotated180) => Rotation::Rotated90, + (Rotation::Rotated270, Rotation::Rotated270) => Rotation::Normal, + } + } +} + +#[derive(Copy, Clone, PartialEq)] +#[allow(non_camel_case_types)] +#[non_exhaustive] +pub enum PixelFormat { + /// Pixels encoded as 1-bit, used for monochromatic displays + Mono, + /// Pixels encoded as 2-bit red channel, 3-bit green channel, 3-bit blue channel. + RGB_233, + /// Pixels encoded as 5-bit red channel, 6-bit green channel, 5-bit blue channel. + RGB_565, + /// Pixels encoded as 8-bit red channel, 8-bit green channel, 8-bit blue channel. + RGB_888, + /// Pixels encoded as 8-bit alpha channel, 8-bit red channel, 8-bit green channel, 8-bit blue channel. + ARGB_8888, + // other pixel formats may be defined. +} + +impl PixelFormat { + pub fn get_bits_per_pixel(&self) -> usize { + match self { + Self::Mono => 1, + Self::RGB_233 => 8, + Self::RGB_565 => 16, + Self::RGB_888 => 24, + Self::ARGB_8888 => 32, + } + } +} + +#[derive(Copy, Clone, PartialEq)] +#[allow(non_camel_case_types)] +#[non_exhaustive] +pub enum CharacterFormat { + /// Characters are encoded using 8 bits ASCII, used for monochromatic displays + ASCII, + /// Characters are encoded using UTF8, used for monochromatic displays + UTF8, + /// Characters are encoded using 16 bits, as in the VGA text mode + /// https://en.wikipedia.org/wiki/VGA_text_mode + /// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + /// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + /// | B |Background | Foreground | Code Point | + /// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + /// B - blink + VGA, +} + +#[derive(Copy, Clone, PartialEq)] +pub struct GraphicsMode { + pub frame: GraphicsFrame, + pub pixel_format: PixelFormat, +} + +#[derive(Copy, Clone, PartialEq)] +pub struct TextMode { + pub frame: TextFrame, + pub character_format: CharacterFormat, +} + +#[derive(Copy, Clone, PartialEq)] +pub struct Align { + pub horizontal: usize, + pub vertical: usize, +} + +#[derive(Copy, Clone, PartialEq)] +pub struct GraphicsFrame { + pub width: u16, + pub height: u16, +} + +#[derive(Copy, Clone, PartialEq)] +pub struct TextFrame { + columns: u16, + lines: u16, +} + +#[derive(Copy, Clone, PartialEq)] +pub struct Tile { + pub align: Align, + pub size: GraphicsFrame, +} + +#[derive(Copy, Clone, PartialEq)] +pub struct Point { + pub x: u16, + pub y: u16, +} + +/* TextBuffer */ +pub trait TextBuffer<'a> { + fn set_client(&self, client: Option<&'a dyn TextBufferClient>); + + /// Returns a tuple (width, height) with the resolution of the + /// screen that is being used. This function is synchronous as the + /// resolution is known by the driver at any moment. + /// + /// The resolution is constant. + fn get_mode(&self) -> TextMode; + + /// Sends a write command to the driver, and the buffer to write from + /// and the len are sent as arguments. When the `write` operation is + /// finished, the driver will call the `write_complete()` callback. + /// + /// Return values: + /// - `Ok(())`: The write command is valid and will be sent to the driver. + /// - `BUSY`: The driver is busy with another command. + fn print( + &self, + buffer: &'static mut [u8], + len: usize, + ) -> Result<(), (ErrorCode, &'static mut [u8])>; + + /// Sends to the driver a command to set the cursor at a given position + /// (x_position, y_position). When finished, the driver will call the + /// `command_complete()` callback. + /// + /// Return values: + /// - `Ok(())`: The command is valid and will be sent to the driver. + /// - `BUSY`: Another command is in progress. + fn set_cursor_position(&self, position: Point) -> Result<(), ErrorCode>; + + /// Sends to the driver a command to show the cursor. When finished, + /// the driver will call the `command_complete()` callback. + /// + /// Return values: + /// - `Ok(())`: The command is valid and will be sent to the driver. + /// - `BUSY`: Another command is in progress. + fn set_show_cursor(&self, show: bool) -> Result<(), ErrorCode>; + + /// Sends to the driver a command to turn on the blinking cursor. When finished, + /// the driver will call the `command_complete()` callback. + /// + /// Return values: + /// - `Ok(())`: The command is valid and will be sent to the driver. + /// - `BUSY`: Another command is in progress. + fn set_blink_cursor(&self, blink: bool) -> Result<(), ErrorCode>; + + /// Sends to the driver a command to clear the display of the screen. + /// When finished, the driver will call the `command_complete()` callback. + /// + /// Return values: + /// - `Ok(())`: The command is valid and will be sent to the driver. + /// - `BUSY`: Another command is in progress. + fn clear(&self) -> Result<(), ErrorCode>; +} + +pub trait TextBufferClient { + /// The driver calls this function when any command (but a write one) + /// finishes executing. + fn command_complete(&self, r: Result<(), ErrorCode>); + + /// The driver calls this function when a write command finishes executing. + fn write_complete(&self, buffer: &'static mut [u8], len: usize, r: Result<(), ErrorCode>); +} + +/* FrameBuffer */ + +pub trait FrameBuffer<'a> { + /// Returns a GraphicsMode struct with the current resolution (in pixels) and + /// the pixel format of the display. This function is synchronous as the + /// driver should know this value without requesting it from the screen. + /// + /// Note that width and height may change due to rotation + fn get_mode(&self) -> GraphicsMode; + + /// Returns the format of minimum tile (in bytes) that can be written to the framebuffer. + /// + /// Due to hardware constraints, framebuffer writes have to be rounded up to a tile size. + /// This means that the size of the write buffer has to be a multiple of the tile. An + /// example use case is a framebuffer that has the minimum write unit a full line on + /// the display. This means that clients can only write entire lines to the framebuffer + /// as opossed to single pixels. + fn get_tile_format(&self) -> Tile; + + /// Sets the video memory frame. + /// This function has to be called before the first call to the write function. + /// This will generate a `command_complete()` callback when finished. + /// + /// Return values: + /// - `Ok(())`: The write frame is valid. + /// - `INVAL`: The parameters of the write frame are not valid. + /// - `BUSY`: Unable to set the write frame on the device. + fn set_write_frame(&self, origin: Point, size: GraphicsFrame) -> Result<(), ErrorCode>; + + /// Returns the required buffer padding in the format of + /// a tuble (free bytes before, free bytes after). + /// + /// The supplied buffer has to be + /// +----------------------+------------+---------------------+ + /// | before padding bytes | frame data | after padding bytes | + /// +----------------------+------------+---------------------+ + /// + /// Some displays,like the SSD1306, require some command bytes placed before + /// and after the actual framebuffer data. Without this padding, the display + /// driver would have to keep another buffer and additional data copy. + /// + /// The HIL's user has to fill in data only in between the padding + /// bytes. Any data written to the padding bytes might be overwritten + /// by the underlying display driver. + fn get_buffer_padding(&self) -> (usize, usize); + + /// Sends a write command to write data in the selected video memory frame. + /// When finished, the driver will call the `write_complete()` callback. + /// + /// Return values: + /// - `Ok(())`: Write is valid and will be sent to the screen. + /// - `INVAL`: Write is invalid or length is wrong. + /// - `BUSY`: Another write is in progress. + fn write( + &self, + buffer: &'static mut [u8], + len: usize, + reset_position: bool, + ) -> Result<(), ErrorCode>; + + /// Flush the framebuffer changes to the hardware device. + /// + /// Some framebuffers keep in a temporary memory the changes and require a flush command + /// to send the changes to the hardware. + /// + /// Return values: + /// - `Ok(())`: Flush is in progress and the client will receive + /// a call to `command_complete`. + /// - `ENOSUPPORT`: Flush has been done synchronous or there is no + /// no need to flush the framebuffer. + /// - `BUSY`: Another write or flush is in progress. + fn flush(&self) -> Result<(), ErrorCode>; + + /// Set the object to receive the asynchronous command callbacks. + fn set_client(&self, client: Option<&'a dyn FrameBufferClient>); +} + +pub trait FrameBufferClient { + /// The framebuffer will call this function to notify that the write command has finished. + /// This is different from `command_complete` as it has to pass back the write buffer + fn write_complete(&self, buffer: &'static mut [u8], r: Result<(), ErrorCode>); + + /// The framebuffer will call this function to notify that a command (except `write` and + /// `write_continue`) has finished. + fn command_complete(&self, r: Result<(), ErrorCode>); +} + +pub trait FrameBufferSetup<'a>: FrameBuffer<'a> { + /// Sets the graphics mode of the display. Returns ENOSUPPORT if the resolution is + /// not supported. The function should return Ok(()) if the request is registered + /// and will be sent to the screen. + /// Upon Ok(()), the caller has to wait for the `command_complete()` callback function + /// that will return the actual Result<(), ErrorCode> after setting the resolution. + fn set_mode(&self, mode: GraphicsMode) -> Result<(), ErrorCode>; + + /// Returns the number of the graphic modes supported. Should return at least + /// one (the current resolution). This function is synchronous as the driver + /// should know this value without requesting it from the screen (most + /// screens do not support such a request, resolutions and pixel formats + /// are described in the data sheet). + /// + /// If the screen supports such a feature, the driver should request this information + /// from the screen upfront. + fn get_num_supported_modes(&self) -> usize; + + /// Can be called with an index from 0 .. count-1 and will return a + /// GraphicsMode struct with the current resolution and pixel format. + /// + /// Note that width and height may change due to rotation + /// + /// This function is synchronous as the driver should know this value without + /// requesting it from the screen. + fn get_supported_mode(&self, index: usize) -> Option; +} + +/* Screen */ +pub trait Screen<'a> { + /// Returns the current rotation. + /// This function is synchronous as the driver should know this value without + /// requesting it from the screen. + fn get_rotation(&self) -> Rotation; + + /// Sets the rotation of the display. + /// The function should return Ok(()) if the request is registered + /// and will be sent to the screen. + /// Upon Ok(()), the caller has to wait for the `command_complete` callback function + /// that will return the actual Result<(), ErrorCode> after setting the rotation. + /// + /// Note that in the case of `Rotated90` or `Rotated270`, this will swap the width and height. + fn set_rotation(&self, rotation: Rotation) -> Result<(), ErrorCode>; + + /// Controls the screen power supply. + /// + /// Use it to initialize the display device. + /// + /// For screens where display needs nonzero brightness (e.g. LED), + /// this shall set brightness to a default value + /// if `set_brightness` was not called first. + /// + /// The device may implement power independently from brightness, + /// so call `set_brightness` to turn on/off the module completely. + /// + /// When finished, calls `ScreenClient::screen_is_ready`, + /// both when power was enabled and disabled. + fn set_power(&self, enabled: bool) -> Result<(), ErrorCode>; + + /// Set on or off the inversion of colors. + fn set_invert(&self, inverted: bool) -> Result<(), ErrorCode>; + + /// Sets the display brightness value + /// + /// Depending on the display, this may not cause any actual changes + /// until and unless power is enabled (see `set_power`). + /// + /// The following values must be supported: + /// - 0 - completely no light emitted + /// - 1..MAX_BRIGHTNESS - on, set brightness to the given level + /// + /// The display should interpret the brightness value as *lightness* + /// (each increment should change preceived brightness the same). + /// 1 shall be the minimum supported brightness, + /// `MAX_BRIGHTNESS` and greater represent the maximum. + /// Values in between should approximate the intermediate values; + /// minimum and maximum included (e.g. when there is only 1 level). + fn set_brightness(&self, brightness: u16) -> Result<(), ErrorCode>; + + /// Set the object to receive the asynchronous command callbacks. + fn set_client(&self, client: Option<&'a dyn ScreenClient>); +} + +pub trait ScreenClient { + /// The screen will call this function to notify that a command (except write) has finished. + fn command_complete(&self, r: Result<(), ErrorCode>); +} + +/* Text Display */ + +pub trait TextDisplay<'a>: TextBuffer<'a> + Screen<'a> {} + +// Provide blanket implementation for trait group +impl<'a, T: Screen<'a> + TextBuffer<'a>> TextDisplay<'a> for T {} + +/* Graphic Display */ + +pub trait GraphicDisplay<'a>: Screen<'a> + FrameBuffer<'a> {} + +// Provide blanket implementations for trait group +impl<'a, T: Screen<'a> + FrameBuffer<'a>> GraphicDisplay<'a> for T {} + +/* Display Advanced */ + +pub trait FullGraphicDisplay<'a>: GraphicDisplay<'a> + FrameBufferSetup<'a> {} + +// Provide blanket implementations for trait group +impl<'a, T: GraphicDisplay<'a> + FrameBufferSetup<'a>> FullGraphicDisplay<'a> for T {} diff --git a/kernel/src/hil/mod.rs b/kernel/src/hil/mod.rs index 0eb367d21a..989dec7c7a 100644 --- a/kernel/src/hil/mod.rs +++ b/kernel/src/hil/mod.rs @@ -14,6 +14,7 @@ pub mod crc; pub mod dac; pub mod date_time; pub mod digest; +pub mod display; pub mod eic; pub mod entropy; pub mod flash; From 3ad8bfb9b66129b49bdccce9bff3e08785cce785 Mon Sep 17 00:00:00 2001 From: Lazar Cristian-Stefan Date: Tue, 16 Jan 2024 13:16:52 +0200 Subject: [PATCH 2/9] Moddified all kernel::dynamic_dereffed_call uses to use kernel::dereffed_call module instead --- boards/clue_nrf52840/src/main.rs | 6 ++-- boards/components/src/graphic_display.rs | 2 +- boards/components/src/ssd1306.rs | 16 ++++----- boards/pico_explorer_base/src/main.rs | 6 ++-- boards/stm32f412gdiscovery/src/main.rs | 6 ++-- capsules/extra/src/graphics_display.rs | 2 +- capsules/extra/src/ssd1306.rs | 43 ++++++++++++++---------- 7 files changed, 44 insertions(+), 37 deletions(-) diff --git a/boards/clue_nrf52840/src/main.rs b/boards/clue_nrf52840/src/main.rs index f0736413e9..1badea6195 100644 --- a/boards/clue_nrf52840/src/main.rs +++ b/boards/clue_nrf52840/src/main.rs @@ -158,7 +158,7 @@ pub struct Platform { 2, >, button: &'static capsules_core::button::Button<'static, nrf52::gpio::GPIOPin<'static>>, - screen: &'static capsules_extra::graphics_display::Screen<'static>, + screen: &'static capsules_extra::screen::Screen<'static>, rng: &'static capsules_core::rng::RngDriver<'static>, ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>, alarm: &'static capsules_core::alarm::AlarmDriver< @@ -199,7 +199,7 @@ impl SyscallDriverLookup for Platform { capsules_core::led::DRIVER_NUM => f(Some(self.led)), capsules_core::button::DRIVER_NUM => f(Some(self.button)), capsules_core::adc::DRIVER_NUM => f(Some(self.adc)), - capsules_extra::graphics_display::DRIVER_NUM => f(Some(self.screen)), + capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)), capsules_core::rng::DRIVER_NUM => f(Some(self.rng)), capsules_extra::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)), capsules_extra::ieee802154::DRIVER_NUM => f(Some(self.ieee802154_radio)), @@ -678,7 +678,7 @@ pub unsafe fn main() { let screen = components::screen::ScreenComponent::new( board_kernel, - capsules_extra::graphics_display::DRIVER_NUM, + capsules_extra::screen::DRIVER_NUM, tft, Some(tft), ) diff --git a/boards/components/src/graphic_display.rs b/boards/components/src/graphic_display.rs index 3fd6346cd0..7cf4297c73 100644 --- a/boards/components/src/graphic_display.rs +++ b/boards/components/src/graphic_display.rs @@ -27,7 +27,7 @@ //! ``` use core::mem::MaybeUninit; -use capsules_extra::graphics_display::graphics_display::GraphicDisplay; +use capsules_extra::graphics_display::GraphicDisplay; use kernel::hil::display; use kernel::capabilities; use kernel::component::Component; diff --git a/boards/components/src/ssd1306.rs b/boards/components/src/ssd1306.rs index c21a11dd45..0192c1d4eb 100644 --- a/boards/components/src/ssd1306.rs +++ b/boards/components/src/ssd1306.rs @@ -2,7 +2,8 @@ use core::mem::MaybeUninit; use capsules_extra::bus; use capsules_extra::ssd1306; use kernel::component::Component; -use kernel::dynamic_deferred_call::DynamicDeferredCall; +use kernel::deferred_call::DeferredCall; +use kernel::deferred_call::DeferredCallClient; #[macro_export] macro_rules! ssd1306_component_static { @@ -37,17 +38,14 @@ macro_rules! ssd1306_component_static { pub struct SSD1306Component> { bus: &'static B, - deferred_caller: &'static DynamicDeferredCall, + deferred_caller: DeferredCall, } impl> SSD1306Component { - pub fn new( - bus: &'static B, - deferred_caller: &'static DynamicDeferredCall, - ) -> SSD1306Component { + pub fn new(bus: &'static B) -> SSD1306Component { SSD1306Component { bus, - deferred_caller, + deferred_caller: DeferredCall::new(), } } } @@ -99,7 +97,9 @@ impl> Component for SSD1306Component { )); self.bus.set_client(ssd1306); - ssd1306.initialize_callback_handle(self.deferred_caller.register(ssd1306).unwrap()); + // todo remove ssd1306.initialize_callback_handle(self.deferred_caller.register(ssd1306).unwrap()); + + ssd1306.register(); ssd1306 } } diff --git a/boards/pico_explorer_base/src/main.rs b/boards/pico_explorer_base/src/main.rs index 04feff525a..44ae6c0af7 100644 --- a/boards/pico_explorer_base/src/main.rs +++ b/boards/pico_explorer_base/src/main.rs @@ -94,7 +94,7 @@ pub struct PicoExplorerBase { >, >, button: &'static capsules_core::button::Button<'static, RPGpioPin<'static>>, - screen: &'static capsules_extra::graphics_display::Screen<'static>, + screen: &'static capsules_extra::screen::Screen<'static>, scheduler: &'static RoundRobinSched<'static>, systick: cortexm0p::systick::SysTick, @@ -115,7 +115,7 @@ impl SyscallDriverLookup for PicoExplorerBase { capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)), capsules_extra::buzzer_driver::DRIVER_NUM => f(Some(self.buzzer_driver)), capsules_core::button::DRIVER_NUM => f(Some(self.button)), - capsules_extra::graphics_display::DRIVER_NUM => f(Some(self.screen)), + capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)), _ => f(None), } } @@ -523,7 +523,7 @@ pub unsafe fn main() { let screen = components::screen::ScreenComponent::new( board_kernel, - capsules_extra::graphics_display::DRIVER_NUM, + capsules_extra::screen::DRIVER_NUM, tft, Some(tft), ) diff --git a/boards/stm32f412gdiscovery/src/main.rs b/boards/stm32f412gdiscovery/src/main.rs index 8dfa026a8f..b2fe43ea96 100644 --- a/boards/stm32f412gdiscovery/src/main.rs +++ b/boards/stm32f412gdiscovery/src/main.rs @@ -63,7 +63,7 @@ struct STM32F412GDiscovery { gpio: &'static capsules_core::gpio::GPIO<'static, stm32f412g::gpio::Pin<'static>>, adc: &'static capsules_core::adc::AdcVirtualized<'static>, touch: &'static capsules_extra::touch::Touch<'static>, - screen: &'static capsules_extra::graphics_display::Screen<'static>, + screen: &'static capsules_extra::screen::Screen<'static>, temperature: &'static capsules_extra::temperature::TemperatureSensor<'static>, rng: &'static capsules_core::rng::RngDriver<'static>, @@ -86,7 +86,7 @@ impl SyscallDriverLookup for STM32F412GDiscovery { capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)), capsules_core::adc::DRIVER_NUM => f(Some(self.adc)), capsules_extra::touch::DRIVER_NUM => f(Some(self.touch)), - capsules_extra::graphics_display::DRIVER_NUM => f(Some(self.screen)), + capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)), capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)), capsules_core::rng::DRIVER_NUM => f(Some(self.rng)), _ => f(None), @@ -645,7 +645,7 @@ pub unsafe fn main() { let screen = components::screen::ScreenComponent::new( board_kernel, - capsules_extra::graphics_display::DRIVER_NUM, + capsules_extra::screen::DRIVER_NUM, tft, Some(tft), ) diff --git a/capsules/extra/src/graphics_display.rs b/capsules/extra/src/graphics_display.rs index 10518af034..40a965245b 100644 --- a/capsules/extra/src/graphics_display.rs +++ b/capsules/extra/src/graphics_display.rs @@ -308,7 +308,7 @@ impl<'a> GraphicDisplay<'a> { || 0, |process_id| { self.apps - .enter(*process_id, |app, kernel_data| { + .enter(process_id, |app, kernel_data| { let position = app.write_position; let mut len = app.write_len; // debug!("position is {} and len is {}, (before, after) - ({}, {})", position, len, before, after); diff --git a/capsules/extra/src/ssd1306.rs b/capsules/extra/src/ssd1306.rs index ba470918c1..79b588a07b 100644 --- a/capsules/extra/src/ssd1306.rs +++ b/capsules/extra/src/ssd1306.rs @@ -3,9 +3,8 @@ use kernel::{ ErrorCode, }; -//TODO; wtf is this? use kernel::deferred_call::{ - DeferredCallHandle, DynamicDeferredCall, DynamicDeferredCallClient, + DeferredCall, DeferredCallClient }; use crate::bus::{self, Bus, BusWidth}; @@ -325,8 +324,7 @@ pub struct SSD1306<'a, B: Bus<'a>> { screen_client: OptionalCell<&'static dyn ScreenClient>, frame_buffer_client: OptionalCell<&'static dyn FrameBufferClient>, - deferred_caller: &'a DynamicDeferredCall, - handle: OptionalCell, + deferred_caller: DeferredCall, initial_write: Cell, invert: Cell, @@ -340,7 +338,7 @@ impl<'a, B: Bus<'a>> SSD1306<'a, B> { app_write_buffer: &'static mut [u8], bus_write_buffer: &'static mut [u8], aux_write_buffer: &'static mut [u8], - deferred_caller: &'a DynamicDeferredCall, + deferred_caller: DeferredCall, ) -> SSD1306<'a, B> { SSD1306 { bus, @@ -378,8 +376,7 @@ impl<'a, B: Bus<'a>> SSD1306<'a, B> { screen_client: OptionalCell::empty(), frame_buffer_client: OptionalCell::empty(), initial_write: Cell::new(false), - deferred_caller, - handle: OptionalCell::empty(), + deferred_caller: deferred_caller, invert: Cell::new(false), } } @@ -394,9 +391,9 @@ impl<'a, B: Bus<'a>> SSD1306<'a, B> { } } - pub fn initialize_callback_handle(&self, handle: DeferredCallHandle) { - self.handle.replace(handle); - } + // todo remove pub fn initialize_callback_handle(&self, handle: DeferredCallHandle) { + // self.handle.replace(handle); + // } pub fn do_next_op(&self) { match self.status.get() { @@ -674,7 +671,8 @@ impl<'a, B: Bus<'a>> FrameBuffer<'static> for SSD1306<'a, B> { }); self.async_status .set(ScreenAsyncCommand::AsyncFrameBufferCommand(Ok(()))); - self.handle.map(|handle| self.deferred_caller.set(*handle)); + // todo remove self.handle.map(|handle| self.deferred_caller.set(*handle)); + self.deferred_caller.set(); Ok(()) } else { Err(ErrorCode::BUSY) @@ -726,7 +724,8 @@ impl<'a, B: Bus<'a>> FrameBuffer<'static> for SSD1306<'a, B> { Err(ErrorCode::BUSY) }; self.async_status.set(ScreenAsyncCommand::Write(ret)); - self.handle.map(|handle| self.deferred_caller.set(*handle)); + // todo removeself.handle.map(|handle| self.deferred_caller.set(*handle)); + self.deferred_caller.set(); ret } @@ -775,14 +774,16 @@ impl<'a, B: Bus<'a>> Screen<'static> for SSD1306<'a, B> { fn set_brightness(&self, _brightness: u16) -> Result<(), kernel::ErrorCode> { self.async_status .set(ScreenAsyncCommand::AsyncScreenCommand(Ok(()))); - self.handle.map(|handle| self.deferred_caller.set(*handle)); + // todo remove self.handle.map(|handle| self.deferred_caller.set(*handle)); + self.deferred_caller.set(); Ok(()) } fn set_power(&self, _enabled: bool) -> Result<(), kernel::ErrorCode> { self.async_status .set(ScreenAsyncCommand::AsyncScreenCommand(Ok(()))); - self.handle.map(|handle| self.deferred_caller.set(*handle)); + // todo remove self.handle.map(|handle| self.deferred_caller.set(*handle)); + self.deferred_caller.set(); Ok(()) } @@ -790,7 +791,8 @@ impl<'a, B: Bus<'a>> Screen<'static> for SSD1306<'a, B> { self.invert.replace(enabled); self.async_status .set(ScreenAsyncCommand::AsyncScreenCommand(Ok(()))); - self.handle.map(|handle| self.deferred_caller.set(*handle)); + //todo remove self.handle.map(|handle| self.deferred_caller.set(*handle)); + self.deferred_caller.set(); Ok(()) } @@ -799,7 +801,8 @@ impl<'a, B: Bus<'a>> Screen<'static> for SSD1306<'a, B> { // todo update origin and graphics mode self.async_status .set(ScreenAsyncCommand::AsyncScreenCommand(Ok(()))); - self.handle.map(|handle| self.deferred_caller.set(*handle)); + //todo remove self.handle.map(|handle| self.deferred_caller.set(*handle)); + self.deferred_caller.set(); Ok(()) } } @@ -822,8 +825,8 @@ impl<'a, B: Bus<'a>> FrameBufferSetup<'static> for SSD1306<'a, B> { } } -impl<'a, B: Bus<'a>> DynamicDeferredCallClient for SSD1306<'a, B> { - fn call(&self, _: DeferredCallHandle) { +impl<'a, B: Bus<'a>> DeferredCallClient for SSD1306<'a, B> { + fn handle_deferred_call(&self) { match self.async_status.get() { ScreenAsyncCommand::Idle => panic!("Received dynamic call without a caller"), ScreenAsyncCommand::AsyncScreenCommand(res) => { @@ -860,4 +863,8 @@ impl<'a, B: Bus<'a>> DynamicDeferredCallClient for SSD1306<'a, B> { } } } + + fn register(&'static self) { + self.deferred_caller.register(self); + } } From 53f615f7ca9010aaa772b531b0615429a28a546c Mon Sep 17 00:00:00 2001 From: Lazar Cristian-Stefan Date: Tue, 16 Jan 2024 17:23:02 +0200 Subject: [PATCH 3/9] Added new main.rs for nucleo-f429zi and partially integrated it --- boards/components/src/graphic_display.rs | 2 +- boards/nucleo_f429zi/Cargo.toml | 1 + boards/nucleo_f429zi/src/main.rs | 444 +++++++---- boards/nucleo_f429zi/src/main_org.rs | 715 ++++++++++++++++++ ...graphics_display.rs => graphic_display.rs} | 0 capsules/extra/src/lib.rs | 2 +- 6 files changed, 1029 insertions(+), 135 deletions(-) create mode 100644 boards/nucleo_f429zi/src/main_org.rs rename capsules/extra/src/{graphics_display.rs => graphic_display.rs} (100%) diff --git a/boards/components/src/graphic_display.rs b/boards/components/src/graphic_display.rs index 7cf4297c73..86ef56d998 100644 --- a/boards/components/src/graphic_display.rs +++ b/boards/components/src/graphic_display.rs @@ -27,7 +27,7 @@ //! ``` use core::mem::MaybeUninit; -use capsules_extra::graphics_display::GraphicDisplay; +use capsules_extra::graphic_display::GraphicDisplay; use kernel::hil::display; use kernel::capabilities; use kernel::component::Component; diff --git a/boards/nucleo_f429zi/Cargo.toml b/boards/nucleo_f429zi/Cargo.toml index 8c202fd811..12c03a6502 100644 --- a/boards/nucleo_f429zi/Cargo.toml +++ b/boards/nucleo_f429zi/Cargo.toml @@ -14,6 +14,7 @@ components = { path = "../components" } cortexm4 = { path = "../../arch/cortex-m4" } kernel = { path = "../../kernel" } stm32f429zi = { path = "../../chips/stm32f429zi" } +stm32f4xx = { path = "../../chips/stm32f4xx" } capsules-core = { path = "../../capsules/core" } capsules-extra = { path = "../../capsules/extra" } diff --git a/boards/nucleo_f429zi/src/main.rs b/boards/nucleo_f429zi/src/main.rs index 9e45ad5603..e748aa22d1 100644 --- a/boards/nucleo_f429zi/src/main.rs +++ b/boards/nucleo_f429zi/src/main.rs @@ -1,7 +1,3 @@ -// Licensed under the Apache License, Version 2.0 or the MIT License. -// SPDX-License-Identifier: Apache-2.0 OR MIT -// Copyright Tock Contributors 2022. - //! Board file for Nucleo-F429ZI development board //! //! - @@ -11,19 +7,28 @@ // https://github.com/rust-lang/rust/issues/62184. #![cfg_attr(not(doc), no_main)] #![deny(missing_docs)] +#![feature(core_intrinsics)] +use kernel::hil::gpio::FloatingState; +use kernel::hil::led::LedLow; use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; use components::gpio::GpioComponent; use kernel::capabilities; use kernel::component::Component; -use kernel::hil::led::LedHigh; +use kernel::deferred_call::{DeferredCall, DeferredCallClient}; use kernel::platform::{KernelResources, SyscallDriverLookup}; use kernel::scheduler::round_robin::RoundRobinSched; use kernel::{create_capability, debug, static_init}; +use capsules_core::virtualizers::virtual_i2c::MuxI2C; +use kernel::hil::i2c::I2CMaster; use stm32f429zi::gpio::{AlternateFunction, Mode, PinId, PortId}; use stm32f429zi::interrupt_service::Stm32f429ziDefaultPeripherals; +use stm32f429zi::{rcc, rcc::Rcc}; +use stm32f4xx::{flash, i2c, pwr, utils}; +use stm32f429zi::pwr; +use core::intrinsics::breakpoint; /// Support routines for debugging I/O. pub mod io; @@ -53,12 +58,11 @@ struct NucleoF429ZI { ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>, led: &'static capsules_core::led::LedDriver< 'static, - LedHigh<'static, stm32f429zi::gpio::Pin<'static>>, + LedLow<'static, stm32f429zi::gpio::Pin<'static>>, 3, >, button: &'static capsules_core::button::Button<'static, stm32f429zi::gpio::Pin<'static>>, adc: &'static capsules_core::adc::AdcVirtualized<'static>, - dac: &'static capsules_extra::dac::Dac<'static>, alarm: &'static capsules_core::alarm::AlarmDriver< 'static, VirtualMuxAlarm<'static, stm32f429zi::tim2::Tim2<'static>>, @@ -69,11 +73,15 @@ struct NucleoF429ZI { scheduler: &'static RoundRobinSched<'static>, systick: cortexm4::systick::SysTick, - can: &'static capsules_extra::can::CanCapsule<'static, stm32f429zi::can::Can<'static>>, - date_time: &'static capsules_extra::date_time::DateTimeCapsule< + + display: &'static capsules_extra::graphic_display::GraphicDisplay<'static>, + ipc_comm: &'static kernel::ipc::IPC<00000>, + pwm: &'static capsules_extra::pwm::Pwm<'static, 1>, + measurement: &'static capsules_extra::measurement::MeasurementCapsule< //todo implemente capsule 'static, - stm32f429zi::rtc::Rtc<'static>, + stm32f4xx::tim3::Tim2_5<'static>, //todo check >, + can: &'static capsules_extra::can::CanCapsule<'static, stm32f429zi::can::Can<'static>>, } /// Mapping of integer syscalls to objects that implement syscalls. @@ -92,9 +100,11 @@ impl SyscallDriverLookup for NucleoF429ZI { kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)), capsules_core::rng::DRIVER_NUM => f(Some(self.rng)), + capsules_extra::graphic_display::DRIVER_NUM => f(Some(self.display)), + kernel::ipc::DRIVER_NUM => f(Some(self.ipc_comm)), + capsules_extra::pwm::DRIVER_NUM => f(Some(self.pwm)), + capsules_extra::measurement::DRIVER_NUM => f(Some(self.measurement)), // impl measurement capsules_extra::can::DRIVER_NUM => f(Some(self.can)), - capsules_extra::dac::DRIVER_NUM => f(Some(self.dac)), - capsules_extra::date_time::DRIVER_NUM => f(Some(self.date_time)), _ => f(None), } } @@ -176,46 +186,48 @@ unsafe fn setup_dma( unsafe fn set_pin_primary_functions( syscfg: &stm32f429zi::syscfg::Syscfg, gpio_ports: &'static stm32f429zi::gpio::GpioPorts<'static>, + i2c1: &stm32f4xx::i2c::I2C, ) { - use kernel::hil::gpio::Configure; + use apis::gpio::Configure; syscfg.enable_clock(); gpio_ports.get_port_from_port_id(PortId::B).enable_clock(); // User LD2 is connected to PB07. Configure PB07 as `debug_gpio!(0, ...)` - gpio_ports.get_pin(PinId::PB07).map(|pin| { + if let Some(pin) = gpio_ports.get_pin(PinId::PB07) { pin.make_output(); // Configure kernel debug gpios as early as possible kernel::debug::assign_gpios(Some(pin), None, None); - }); + }; gpio_ports.get_port_from_port_id(PortId::D).enable_clock(); // pd8 and pd9 (USART3) is connected to ST-LINK virtual COM port - gpio_ports.get_pin(PinId::PD08).map(|pin| { + if let Some(pin) = gpio_ports.get_pin(PinId::PD08) { pin.set_mode(Mode::AlternateFunctionMode); // AF7 is USART2_TX pin.set_alternate_function(AlternateFunction::AF7); - }); - gpio_ports.get_pin(PinId::PD09).map(|pin| { + }; + if let Some(pin) = gpio_ports.get_pin(PinId::PD09) { pin.set_mode(Mode::AlternateFunctionMode); // AF7 is USART2_RX pin.set_alternate_function(AlternateFunction::AF7); - }); + }; gpio_ports.get_port_from_port_id(PortId::C).enable_clock(); - // button is connected on pc13 - gpio_ports.get_pin(PinId::PC13).map(|pin| { + // button is connected on pa6 + if let Some(pin) = gpio_ports.get_pin(PinId::PA06) { + pin.set_mode(Mode::Input); pin.enable_interrupt(); - }); + } // set interrupt for pin D0 - gpio_ports.get_pin(PinId::PG09).map(|pin| { + if let Some(pin) = gpio_ports.get_pin(PinId::PG09) { pin.enable_interrupt(); - }); + } // Enable clocks for GPIO Ports // Disable some of them if you don't need some of the GPIOs @@ -227,35 +239,98 @@ unsafe fn set_pin_primary_functions( gpio_ports.get_port_from_port_id(PortId::H).enable_clock(); // Arduino A0 - gpio_ports.get_pin(PinId::PA03).map(|pin| { + if let Some(pin) = gpio_ports.get_pin(PinId::PC00) { pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + } + + // // Arduino A1 + // if let Some(pin) = gpio_ports.get_pin(PinId::PC00) { + // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // } + + // // Arduino A2 + // if let Some(pin) = gpio_ports.get_pin(PinId::PC03) { + // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // } + + // // Arduino A6 + // if let Some(pin) = gpio_ports.get_pin(PinId::PB01) { + // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // } + + // // Arduino A7 + // if let Some(pin) = gpio_ports.get_pin(PinId::PC02) { + // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // } + + if let Some(pin) = gpio_ports.get_pin(PinId::PB08) { + pin.set_mode(Mode::AlternateFunctionMode); + pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); + pin.set_mode_output_opendrain(); + // AF4 is I2C + pin.set_speed(); + pin.set_alternate_function(AlternateFunction::AF4); + }; + if let Some(pin) = gpio_ports.get_pin(PinId::PB09) { + pin.make_output(); + pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); + pin.set_speed(); + pin.set_mode(Mode::AlternateFunctionMode); + pin.set_mode_output_opendrain(); + // AF4 is I2C + pin.set_alternate_function(AlternateFunction::AF4); + }; + + i2c1.enable_clock(); + i2c1.set_speed(i2c::I2CSpeed::Speed100k, 8); + + // PE11 is connected to motor driver IN2 + gpio_ports.get_pin(PinId::PE11).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + // AF1 is TIM1/2 + pin.set_alternate_function(AlternateFunction::AF1); }); - // Arduino A1 - gpio_ports.get_pin(PinId::PC00).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // PE13 is connected to motor driver IN1 + gpio_ports.get_pin(PinId::PE13).map(|pin| { + pin.set_mode(Mode::GeneralPurposeOutputMode); + // pin.set_mode(Mode::AlternateFunctionMode); + // // AF1 is TIM1/2 + // pin.set_alternate_function(AlternateFunction::AF1); }); - // Arduino A2 - gpio_ports.get_pin(PinId::PC03).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // PA7 is Encoder pulse counting + gpio_ports.get_pin(PinId::PA07).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + pin.set_floating_state(FloatingState::PullDown); + //pin.set_mode(Mode::AlternateFunctionMode); + pin.set_alternate_function(AlternateFunction::AF2); }); - // Arduino A6 - gpio_ports.get_pin(PinId::PB01).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // PA3 is Encoder pulse counting + gpio_ports.get_pin(PinId::PA03).map(|pin| { + pin.make_input(); + pin.set_floating_state(FloatingState::PullNone); }); - // Arduino A7 - gpio_ports.get_pin(PinId::PC02).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // PA08 is Clock Output MCO1 + gpio_ports.get_pin(PinId::PA08).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + // AF0 is Clock output (MCO1) + pin.set_alternate_function(AlternateFunction::AF0); + }); + + // PC09 is ClockOutput MCO2 + gpio_ports.get_pin(PinId::PC09).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + pin.set_alternate_function(AlternateFunction::AF0); }); gpio_ports.get_pin(PinId::PD00).map(|pin| { pin.set_mode(Mode::AlternateFunctionMode); // AF9 is CAN_RX pin.set_alternate_function(AlternateFunction::AF9); - pin.set_floating_state(kernel::hil::gpio::FloatingState::PullDown); + pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); }); gpio_ports.get_pin(PinId::PD01).map(|pin| { pin.set_mode(Mode::AlternateFunctionMode); @@ -263,9 +338,8 @@ unsafe fn set_pin_primary_functions( pin.set_alternate_function(AlternateFunction::AF9); }); - // DAC Channel 1 - gpio_ports.get_pin(PinId::PA04).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + gpio_ports.get_pin(PinId::PE08).map(|pin| { + pin.make_output(); }); } @@ -273,8 +347,9 @@ unsafe fn set_pin_primary_functions( unsafe fn setup_peripherals( tim2: &stm32f429zi::tim2::Tim2, trng: &stm32f429zi::trng::Trng, + tim1: &stm32f4xx::tim1::Tim1_8, + tim3: &stm32f4xx::tim3::Tim2_5, can1: &'static stm32f429zi::can::Can, - rtc: &'static stm32f429zi::rtc::Rtc, ) { // USART3 IRQn is 39 cortexm4::nvic::Nvic::new(stm32f429zi::nvic::USART3).enable(); @@ -287,11 +362,14 @@ unsafe fn setup_peripherals( // RNG trng.enable_clock(); + tim1.enable_clock(); + tim1.start(); + // tim1.start_pwm(&stm32f4xx::tim1::TimOutputs::OutputCh2, 2000, 800); + tim3.enable_clock(); + tim3.start(); + // CAN can1.enable_clock(); - - // RTC - rtc.enable_clock(); } /// Statically initialize the core peripherals for the chip. @@ -300,14 +378,14 @@ unsafe fn setup_peripherals( /// removed when this function returns. Otherwise, the stack space used for /// these static_inits is wasted. #[inline(never)] -unsafe fn create_peripherals() -> ( +unsafe fn get_peripherals() -> ( &'static mut Stm32f429ziDefaultPeripherals<'static>, &'static stm32f429zi::syscfg::Syscfg<'static>, &'static stm32f429zi::dma::Dma1<'static>, + &'static stm32f429zi::rcc::Rcc, ) { // We use the default HSI 16Mhz clock let rcc = static_init!(stm32f429zi::rcc::Rcc, stm32f429zi::rcc::Rcc::new()); - let syscfg = static_init!( stm32f429zi::syscfg::Syscfg, stm32f429zi::syscfg::Syscfg::new(rcc) @@ -323,28 +401,97 @@ unsafe fn create_peripherals() -> ( Stm32f429ziDefaultPeripherals, Stm32f429ziDefaultPeripherals::new(rcc, exti, dma1, dma2) ); - (peripherals, syscfg, dma1) + (peripherals, syscfg, dma1, rcc) +} + +/// Initialize clock tree and related peripherals (flash, pwr) +/// +/// In order to start the PLL, the pwr scaling needs to be configured. In order to increase the system clock to 180MHz, the flash latency needs to be increased and pwr overdrive needs to be enabled. +/// see: RM0090 ch. 5.1.4 pg 123 +unsafe fn try_init_clocks(rcc: &Rcc) -> Result<(), ()> { + // only PWR peripheral should be enabled, HSI -> SystemClock + rcc::enable_boot_esential_clocks()?; + pwr::configure_voltage_scaling(1)?; + + // uncomment these lines in order to measure internal clocks + rcc.configure_prescaler(&rcc::RccClockDestination::MClockOutput1, 5); + rcc.configure_prescaler(&rcc::RccClockDestination::MClockOutput2, 5); + + // HSI -> PLL, wait for HSI to be stable + utils::wait_for_condition( + 1_000, + || rcc.is_clock_stable(&rcc::RccClockSource::HsiRc), + || (), + )?; + + // HSI = 16MHz + // PLL output = (16/8)*180/2 = 180 MHz + rcc.configure_pll(8, 180, 2); + rcc.enable(rcc::RccClockSource::Pll); + + pwr::enable_overdrive()?; + flash::set_latency(5); + + let _ = utils::wait_for_condition( + 1_000, + || rcc.is_clock_stable(&rcc::RccClockSource::Pll), + || (), + ); + rcc.configure_prescaler(&rcc::RccClockDestination::Apb1, 4); + rcc.configure_prescaler(&rcc::RccClockDestination::Apb2, 4); + rcc.route( + &rcc::RccClockSource::Pll, + &rcc::RccClockDestination::SystemClock, + )?; + + Ok(()) +} + +/// Initialize clock tree, if it fails it reverts to default configuration (HSI-> SystemClcok) +pub unsafe fn init_clocks(rcc: &Rcc) { + match try_init_clocks(&rcc) { + Ok(_) => {} + Err(_) => { + let _ = rcc.route( + &rcc::RccClockSource::HsiRc, + &rcc::RccClockDestination::SystemClock, + ); + } + } + if rcc.compute_nominal_frequency().is_err() { + breakpoint(); + } } /// Main function. /// +/// # Safety +/// This function needs to be marked unsafe allows ... +/// /// This is called after RAM initialization is complete. #[no_mangle] pub unsafe fn main() { stm32f429zi::init(); - let (peripherals, syscfg, dma1) = create_peripherals(); + let (peripherals, syscfg, dma1, rcc) = get_peripherals(); peripherals.init(); + + init_clocks(rcc); let base_peripherals = &peripherals.stm32f4; setup_peripherals( &base_peripherals.tim2, &peripherals.trng, + &base_peripherals.tim1, + &base_peripherals.tim3, &peripherals.can1, - &peripherals.rtc, ); - set_pin_primary_functions(syscfg, &base_peripherals.gpio_ports); + set_pin_primary_functions( + syscfg, + &base_peripherals.gpio_ports, + &peripherals.stm32f4.i2c1, + ); setup_dma( dma1, @@ -354,6 +501,14 @@ pub unsafe fn main() { let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); + let dynamic_deferred_call_clients = + static_init!([DynamicDeferredCallClientState; 3], Default::default()); + let dynamic_deferred_caller = static_init!( + DynamicDeferredCall, + DynamicDeferredCall::new(dynamic_deferred_call_clients) + ); + DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); + let chip = static_init!( stm32f429zi::chip::Stm32f4xx, stm32f429zi::chip::Stm32f4xx::new(peripherals) @@ -364,8 +519,12 @@ pub unsafe fn main() { // Create a shared UART channel for kernel debug. base_peripherals.usart3.enable_clock(); - let uart_mux = components::console::UartMuxComponent::new(&base_peripherals.usart3, 115200) - .finalize(components::uart_mux_component_static!()); + let uart_mux = components::console::UartMuxComponent::new( + &base_peripherals.usart3, + 115200, + dynamic_deferred_caller, + ) + .finalize(components::uart_mux_component_static!()); io::WRITER.set_initialized(); @@ -379,7 +538,7 @@ pub unsafe fn main() { // Setup the console. let console = components::console::ConsoleComponent::new( board_kernel, - capsules_core::console::DRIVER_NUM, + capsules::console::DRIVER_NUM, uart_mux, ) .finalize(components::console_component_static!()); @@ -393,22 +552,26 @@ pub unsafe fn main() { let gpio_ports = &base_peripherals.gpio_ports; let led = components::led::LedsComponent::new().finalize(components::led_component_static!( - LedHigh<'static, stm32f429zi::gpio::Pin>, - LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB00).unwrap()), - LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB07).unwrap()), - LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB14).unwrap()), + LedLow<'static, stm32f429zi::gpio::Pin>, + LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PD15).unwrap()), + LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PD14).unwrap()), + LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PA05).unwrap()), )); + // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB00).unwrap()), + // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB07).unwrap()), + // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB14).unwrap()), + // BUTTONs let button = components::button::ButtonComponent::new( board_kernel, - capsules_core::button::DRIVER_NUM, + capsules::button::DRIVER_NUM, components::button_component_helper!( stm32f429zi::gpio::Pin, ( - gpio_ports.get_pin(stm32f429zi::gpio::PinId::PC13).unwrap(), - kernel::hil::gpio::ActivationMode::ActiveHigh, - kernel::hil::gpio::FloatingState::PullNone + gpio_ports.get_pin(stm32f429zi::gpio::PinId::PA06).unwrap(), + apis::gpio::ActivationMode::ActiveHigh, + apis::gpio::FloatingState::PullDown ) ), ) @@ -423,7 +586,7 @@ pub unsafe fn main() { let alarm = components::alarm::AlarmDriverComponent::new( board_kernel, - capsules_core::alarm::DRIVER_NUM, + capsules::alarm::DRIVER_NUM, mux_alarm, ) .finalize(components::alarm_component_static!(stm32f429zi::tim2::Tim2)); @@ -431,7 +594,7 @@ pub unsafe fn main() { // GPIO let gpio = GpioComponent::new( board_kernel, - capsules_core::gpio::DRIVER_NUM, + capsules::gpio::DRIVER_NUM, components::gpio_component_helper!( stm32f429zi::gpio::Pin, // Arduino like RX/TX @@ -440,16 +603,16 @@ pub unsafe fn main() { 2 => gpio_ports.pins[5][15].as_ref().unwrap(), //D2 3 => gpio_ports.pins[4][13].as_ref().unwrap(), //D3 4 => gpio_ports.pins[5][14].as_ref().unwrap(), //D4 - 5 => gpio_ports.pins[4][11].as_ref().unwrap(), //D5 - 6 => gpio_ports.pins[4][9].as_ref().unwrap(), //D6 + // 5 => gpio_ports.pins[4][11].as_ref().unwrap(), //D5 + // 6 => gpio_ports.pins[4][9].as_ref().unwrap(), //D6 7 => gpio_ports.pins[5][13].as_ref().unwrap(), //D7 8 => gpio_ports.pins[5][12].as_ref().unwrap(), //D8 - 9 => gpio_ports.pins[3][15].as_ref().unwrap(), //D9 + // 9 => gpio_ports.pins[3][15].as_ref().unwrap(), //D9 // SPI Pins - 10 => gpio_ports.pins[3][14].as_ref().unwrap(), //D10 - 11 => gpio_ports.pins[0][7].as_ref().unwrap(), //D11 - 12 => gpio_ports.pins[0][6].as_ref().unwrap(), //D12 - 13 => gpio_ports.pins[0][5].as_ref().unwrap(), //D13 + // 10 => gpio_ports.pins[3][14].as_ref().unwrap(), //D10 + // 11 => gpio_ports.pins[0][7].as_ref().unwrap(), //D11 + // 12 => gpio_ports.pins[0][6].as_ref().unwrap(), //D12 + // 13 => gpio_ports.pins[0][5].as_ref().unwrap(), //D13 // I2C Pins 14 => gpio_ports.pins[1][9].as_ref().unwrap(), //D14 15 => gpio_ports.pins[1][8].as_ref().unwrap(), //D15 @@ -508,8 +671,8 @@ pub unsafe fn main() { 63 => gpio_ports.pins[5][9].as_ref().unwrap(), //D63 64 => gpio_ports.pins[6][1].as_ref().unwrap(), //D64 65 => gpio_ports.pins[6][0].as_ref().unwrap(), //D65 - 66 => gpio_ports.pins[3][1].as_ref().unwrap(), //D66 - 67 => gpio_ports.pins[3][0].as_ref().unwrap(), //D67 + // 66 => gpio_ports.pins[3][1].as_ref().unwrap(), //D66 + // 67 => gpio_ports.pins[3][0].as_ref().unwrap(), //D67 68 => gpio_ports.pins[5][0].as_ref().unwrap(), //D68 69 => gpio_ports.pins[5][1].as_ref().unwrap(), //D69 70 => gpio_ports.pins[5][2].as_ref().unwrap(), //D70 @@ -520,7 +683,7 @@ pub unsafe fn main() { // 72 => gpio_ports.pins[0][3].as_ref().unwrap(), //A0 // 73 => gpio_ports.pins[2][0].as_ref().unwrap(), //A1 // 74 => gpio_ports.pins[2][3].as_ref().unwrap(), //A2 - 75 => gpio_ports.pins[5][3].as_ref().unwrap(), //A3 + // 75 => gpio_ports.pins[5][3].as_ref().unwrap(), //A3 76 => gpio_ports.pins[5][5].as_ref().unwrap(), //A4 77 => gpio_ports.pins[5][10].as_ref().unwrap(), //A5 // 78 => gpio_ports.pins[1][1].as_ref().unwrap(), //A6 @@ -554,43 +717,19 @@ pub unsafe fn main() { kernel::hil::sensors::TemperatureDriver::set_client(temp_sensor, temp); let adc_channel_0 = - components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel3) - .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - - let adc_channel_1 = components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel10) .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - let adc_channel_2 = - components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel13) - .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - - let adc_channel_3 = - components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel9) - .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - - let adc_channel_4 = - components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel12) - .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - let adc_syscall = components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM) .finalize(components::adc_syscall_component_helper!( adc_channel_0, - adc_channel_1, - adc_channel_2, - adc_channel_3, - adc_channel_4, )); let process_printer = components::process_printer::ProcessPrinterTextComponent::new() .finalize(components::process_printer_text_component_static!()); PROCESS_PRINTER = Some(process_printer); - // DAC - let dac = components::dac::DacComponent::new(&base_peripherals.dac) - .finalize(components::dac_component_static!()); - // RNG let rng = components::rng::RngComponent::new( board_kernel, @@ -599,8 +738,24 @@ pub unsafe fn main() { ) .finalize(components::rng_component_static!()); - // CAN - let can = components::can::CanComponent::new( + // PROCESS CONSOLE + let process_console = components::process_console::ProcessConsoleComponent::new( + board_kernel, + uart_mux, + mux_alarm, + process_printer, + None, + ) + .finalize(components::process_console_component_static!( + stm32f429zi::tim2::Tim2 + )); + let _ = process_console.start(); + + let ipc_comm = + driver_setup::ipc::IPCComponent::new(board_kernel, drivers::communication::DRIVER_NUM) + .finalize(driver_setup::ipc_component_static!()); + + let can = driver_setup::can::CanComponent::new( board_kernel, capsules_extra::can::DRIVER_NUM, &peripherals.can1, @@ -609,64 +764,87 @@ pub unsafe fn main() { stm32f429zi::can::Can<'static> )); - // RTC DATE TIME - match peripherals.rtc.rtc_init() { - Err(e) => debug!("{:?}", e), - _ => (), - }; + // I2C SSD1306 screen + let i2c_mux = static_init!( + MuxI2C<'static>, + MuxI2C::new(&peripherals.stm32f4.i2c1, None, dynamic_deferred_caller) + ); + peripherals.stm32f4.i2c1.set_master_client(i2c_mux); - let date_time = components::date_time::DateTimeComponent::new( - board_kernel, - capsules_extra::date_time::DRIVER_NUM, - &peripherals.rtc, + let bus = components::bus::I2CMasterBusComponent::new( + i2c_mux, + capsules_extra::ssd1306::SLAVE_ADDRESS_WRITE, ) - .finalize(components::date_time_component_static!( - stm32f429zi::rtc::Rtc<'static> - )); + .finalize(components::i2c_master_bus_component_static!(2)); - // PROCESS CONSOLE - let process_console = components::process_console::ProcessConsoleComponent::new( + let ssd1306_screen = components::ssd1306::SSD1306Component::new(bus, dynamic_deferred_caller) + .finalize(components::ssd1306_component_static!( + capsules_extra::bus::I2CMasterBus<'static, capsules_core::virtualizers::virtual_i2c::I2CDevice<'static>>, + )); + + let _ = ssd1306_screen.init(); + + let display = components::graphic_display::GraphicDisplayComponent::new( board_kernel, - uart_mux, - mux_alarm, - process_printer, - Some(cortexm4::support::reset), + capsules_extra::graphic_display::DRIVER_NUM, + ssd1306_screen, + Some(ssd1306_screen), ) - .finalize(components::process_console_component_static!( - stm32f429zi::tim2::Tim2 - )); - let _ = process_console.start(); + .finalize(components::graphic_display_component_static!(1025)); + + let mux_pwm = components::pwm::PwmMuxComponent::new(&base_peripherals.tim1).finalize( + components::pwm_mux_component_static!(stm32f4xx::tim1::Tim1_8), + ); + + let pwm = components::pwm::PwmVirtualComponent::new(board_kernel, capsules_extra::pwm::DRIVER_NUM) + .finalize(components::pwm_syscall_component_helper!( + components::pwm::PwmPinComponent::new( + &mux_pwm, + stm32f4xx::tim1::TimOutputs::OutputCh2, + //gpio_ports.get_pin(stm32f429zi: gpio::PinId::PE11).unwrap() + ) + .finalize(components::pwm_pin_user_component_static!( + stm32f4xx::tim1::Tim1_8 + )) + )); + + let measurement = components::measurement::MeasurementComponent::new(&base_peripherals.tim3) + .finalize(components::measurement_component_static!(stm32f4xx::tim3::Tim2_5)); let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) .finalize(components::round_robin_component_static!(NUM_PROCS)); let nucleo_f429zi = NucleoF429ZI { - console: console, + console, ipc: kernel::ipc::IPC::new( board_kernel, kernel::ipc::DRIVER_NUM, &memory_allocation_capability, ), adc: adc_syscall, - dac: dac, - led: led, + led, temperature: temp, - button: button, - alarm: alarm, - gpio: gpio, - rng: rng, + button, + alarm, + gpio, + rng, scheduler, - systick: cortexm4::systick::SysTick::new(), - can: can, - date_time, + systick: cortexm4::systick::SysTick::new_with_calibration( + rcc.get_nominal_frequency_(&rcc::PeripheralClockType::AHB1(rcc::HCLK1::SysTick)), + ), + + display, + ipc_comm, + pwm, + measurement, + can, }; // // Optional kernel tests // // // // See comment in `boards/imix/src/main.rs` // virtual_uart_rx_test::run_virtual_uart_receive(mux_uart); - debug!("Initialization complete. Entering main loop"); // These symbols are defined in the linker script. diff --git a/boards/nucleo_f429zi/src/main_org.rs b/boards/nucleo_f429zi/src/main_org.rs new file mode 100644 index 0000000000..9e45ad5603 --- /dev/null +++ b/boards/nucleo_f429zi/src/main_org.rs @@ -0,0 +1,715 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2022. + +//! Board file for Nucleo-F429ZI development board +//! +//! - + +#![no_std] +// Disable this attribute when documenting, as a workaround for +// https://github.com/rust-lang/rust/issues/62184. +#![cfg_attr(not(doc), no_main)] +#![deny(missing_docs)] + +use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; +use components::gpio::GpioComponent; +use kernel::capabilities; +use kernel::component::Component; +use kernel::hil::led::LedHigh; +use kernel::platform::{KernelResources, SyscallDriverLookup}; +use kernel::scheduler::round_robin::RoundRobinSched; +use kernel::{create_capability, debug, static_init}; + +use stm32f429zi::gpio::{AlternateFunction, Mode, PinId, PortId}; +use stm32f429zi::interrupt_service::Stm32f429ziDefaultPeripherals; + +/// Support routines for debugging I/O. +pub mod io; + +// Number of concurrent processes this platform supports. +const NUM_PROCS: usize = 4; + +// Actual memory for holding the active process structures. +static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] = + [None, None, None, None]; + +static mut CHIP: Option<&'static stm32f429zi::chip::Stm32f4xx> = + None; +static mut PROCESS_PRINTER: Option<&'static kernel::process::ProcessPrinterText> = None; + +// How should the kernel respond when a process faults. +const FAULT_RESPONSE: kernel::process::PanicFaultPolicy = kernel::process::PanicFaultPolicy {}; + +/// Dummy buffer that causes the linker to reserve enough space for the stack. +#[no_mangle] +#[link_section = ".stack_buffer"] +pub static mut STACK_MEMORY: [u8; 0x2000] = [0; 0x2000]; + +/// A structure representing this platform that holds references to all +/// capsules for this platform. +struct NucleoF429ZI { + console: &'static capsules_core::console::Console<'static>, + ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>, + led: &'static capsules_core::led::LedDriver< + 'static, + LedHigh<'static, stm32f429zi::gpio::Pin<'static>>, + 3, + >, + button: &'static capsules_core::button::Button<'static, stm32f429zi::gpio::Pin<'static>>, + adc: &'static capsules_core::adc::AdcVirtualized<'static>, + dac: &'static capsules_extra::dac::Dac<'static>, + alarm: &'static capsules_core::alarm::AlarmDriver< + 'static, + VirtualMuxAlarm<'static, stm32f429zi::tim2::Tim2<'static>>, + >, + temperature: &'static capsules_extra::temperature::TemperatureSensor<'static>, + gpio: &'static capsules_core::gpio::GPIO<'static, stm32f429zi::gpio::Pin<'static>>, + rng: &'static capsules_core::rng::RngDriver<'static>, + + scheduler: &'static RoundRobinSched<'static>, + systick: cortexm4::systick::SysTick, + can: &'static capsules_extra::can::CanCapsule<'static, stm32f429zi::can::Can<'static>>, + date_time: &'static capsules_extra::date_time::DateTimeCapsule< + 'static, + stm32f429zi::rtc::Rtc<'static>, + >, +} + +/// Mapping of integer syscalls to objects that implement syscalls. +impl SyscallDriverLookup for NucleoF429ZI { + fn with_driver(&self, driver_num: usize, f: F) -> R + where + F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R, + { + match driver_num { + capsules_core::console::DRIVER_NUM => f(Some(self.console)), + capsules_core::led::DRIVER_NUM => f(Some(self.led)), + capsules_core::button::DRIVER_NUM => f(Some(self.button)), + capsules_core::adc::DRIVER_NUM => f(Some(self.adc)), + capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)), + capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)), + kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), + capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)), + capsules_core::rng::DRIVER_NUM => f(Some(self.rng)), + capsules_extra::can::DRIVER_NUM => f(Some(self.can)), + capsules_extra::dac::DRIVER_NUM => f(Some(self.dac)), + capsules_extra::date_time::DRIVER_NUM => f(Some(self.date_time)), + _ => f(None), + } + } +} + +impl + KernelResources< + stm32f429zi::chip::Stm32f4xx< + 'static, + stm32f429zi::interrupt_service::Stm32f429ziDefaultPeripherals<'static>, + >, + > for NucleoF429ZI +{ + type SyscallDriverLookup = Self; + type SyscallFilter = (); + type ProcessFault = (); + type CredentialsCheckingPolicy = (); + type Scheduler = RoundRobinSched<'static>; + type SchedulerTimer = cortexm4::systick::SysTick; + type WatchDog = (); + type ContextSwitchCallback = (); + + fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup { + self + } + fn syscall_filter(&self) -> &Self::SyscallFilter { + &() + } + fn process_fault(&self) -> &Self::ProcessFault { + &() + } + fn credentials_checking_policy(&self) -> &'static Self::CredentialsCheckingPolicy { + &() + } + fn scheduler(&self) -> &Self::Scheduler { + self.scheduler + } + fn scheduler_timer(&self) -> &Self::SchedulerTimer { + &self.systick + } + fn watchdog(&self) -> &Self::WatchDog { + &() + } + fn context_switch_callback(&self) -> &Self::ContextSwitchCallback { + &() + } +} + +/// Helper function called during bring-up that configures DMA. +unsafe fn setup_dma( + dma: &stm32f429zi::dma::Dma1, + dma_streams: &'static [stm32f429zi::dma::Stream; 8], + usart3: &'static stm32f429zi::usart::Usart, +) { + use stm32f429zi::dma::Dma1Peripheral; + use stm32f429zi::usart; + + dma.enable_clock(); + + let usart3_tx_stream = &dma_streams[Dma1Peripheral::USART3_TX.get_stream_idx()]; + let usart3_rx_stream = &dma_streams[Dma1Peripheral::USART3_RX.get_stream_idx()]; + + usart3.set_dma( + usart::TxDMA(usart3_tx_stream), + usart::RxDMA(usart3_rx_stream), + ); + + usart3_tx_stream.set_client(usart3); + usart3_rx_stream.set_client(usart3); + + usart3_tx_stream.setup(Dma1Peripheral::USART3_TX); + usart3_rx_stream.setup(Dma1Peripheral::USART3_RX); + + cortexm4::nvic::Nvic::new(Dma1Peripheral::USART3_TX.get_stream_irqn()).enable(); + cortexm4::nvic::Nvic::new(Dma1Peripheral::USART3_RX.get_stream_irqn()).enable(); +} + +/// Helper function called during bring-up that configures multiplexed I/O. +unsafe fn set_pin_primary_functions( + syscfg: &stm32f429zi::syscfg::Syscfg, + gpio_ports: &'static stm32f429zi::gpio::GpioPorts<'static>, +) { + use kernel::hil::gpio::Configure; + + syscfg.enable_clock(); + + gpio_ports.get_port_from_port_id(PortId::B).enable_clock(); + + // User LD2 is connected to PB07. Configure PB07 as `debug_gpio!(0, ...)` + gpio_ports.get_pin(PinId::PB07).map(|pin| { + pin.make_output(); + + // Configure kernel debug gpios as early as possible + kernel::debug::assign_gpios(Some(pin), None, None); + }); + + gpio_ports.get_port_from_port_id(PortId::D).enable_clock(); + + // pd8 and pd9 (USART3) is connected to ST-LINK virtual COM port + gpio_ports.get_pin(PinId::PD08).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + // AF7 is USART2_TX + pin.set_alternate_function(AlternateFunction::AF7); + }); + gpio_ports.get_pin(PinId::PD09).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + // AF7 is USART2_RX + pin.set_alternate_function(AlternateFunction::AF7); + }); + + gpio_ports.get_port_from_port_id(PortId::C).enable_clock(); + + // button is connected on pc13 + gpio_ports.get_pin(PinId::PC13).map(|pin| { + pin.enable_interrupt(); + }); + + // set interrupt for pin D0 + gpio_ports.get_pin(PinId::PG09).map(|pin| { + pin.enable_interrupt(); + }); + + // Enable clocks for GPIO Ports + // Disable some of them if you don't need some of the GPIOs + gpio_ports.get_port_from_port_id(PortId::A).enable_clock(); + // Ports B, C and D are already enabled + gpio_ports.get_port_from_port_id(PortId::E).enable_clock(); + gpio_ports.get_port_from_port_id(PortId::F).enable_clock(); + gpio_ports.get_port_from_port_id(PortId::G).enable_clock(); + gpio_ports.get_port_from_port_id(PortId::H).enable_clock(); + + // Arduino A0 + gpio_ports.get_pin(PinId::PA03).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + }); + + // Arduino A1 + gpio_ports.get_pin(PinId::PC00).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + }); + + // Arduino A2 + gpio_ports.get_pin(PinId::PC03).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + }); + + // Arduino A6 + gpio_ports.get_pin(PinId::PB01).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + }); + + // Arduino A7 + gpio_ports.get_pin(PinId::PC02).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + }); + + gpio_ports.get_pin(PinId::PD00).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + // AF9 is CAN_RX + pin.set_alternate_function(AlternateFunction::AF9); + pin.set_floating_state(kernel::hil::gpio::FloatingState::PullDown); + }); + gpio_ports.get_pin(PinId::PD01).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + // AF9 is CAN_TX + pin.set_alternate_function(AlternateFunction::AF9); + }); + + // DAC Channel 1 + gpio_ports.get_pin(PinId::PA04).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + }); +} + +/// Helper function for miscellaneous peripheral functions +unsafe fn setup_peripherals( + tim2: &stm32f429zi::tim2::Tim2, + trng: &stm32f429zi::trng::Trng, + can1: &'static stm32f429zi::can::Can, + rtc: &'static stm32f429zi::rtc::Rtc, +) { + // USART3 IRQn is 39 + cortexm4::nvic::Nvic::new(stm32f429zi::nvic::USART3).enable(); + + // TIM2 IRQn is 28 + tim2.enable_clock(); + tim2.start(); + cortexm4::nvic::Nvic::new(stm32f429zi::nvic::TIM2).enable(); + + // RNG + trng.enable_clock(); + + // CAN + can1.enable_clock(); + + // RTC + rtc.enable_clock(); +} + +/// Statically initialize the core peripherals for the chip. +/// +/// This is in a separate, inline(never) function so that its stack frame is +/// removed when this function returns. Otherwise, the stack space used for +/// these static_inits is wasted. +#[inline(never)] +unsafe fn create_peripherals() -> ( + &'static mut Stm32f429ziDefaultPeripherals<'static>, + &'static stm32f429zi::syscfg::Syscfg<'static>, + &'static stm32f429zi::dma::Dma1<'static>, +) { + // We use the default HSI 16Mhz clock + let rcc = static_init!(stm32f429zi::rcc::Rcc, stm32f429zi::rcc::Rcc::new()); + + let syscfg = static_init!( + stm32f429zi::syscfg::Syscfg, + stm32f429zi::syscfg::Syscfg::new(rcc) + ); + let exti = static_init!( + stm32f429zi::exti::Exti, + stm32f429zi::exti::Exti::new(syscfg) + ); + let dma1 = static_init!(stm32f429zi::dma::Dma1, stm32f429zi::dma::Dma1::new(rcc)); + let dma2 = static_init!(stm32f429zi::dma::Dma2, stm32f429zi::dma::Dma2::new(rcc)); + + let peripherals = static_init!( + Stm32f429ziDefaultPeripherals, + Stm32f429ziDefaultPeripherals::new(rcc, exti, dma1, dma2) + ); + (peripherals, syscfg, dma1) +} + +/// Main function. +/// +/// This is called after RAM initialization is complete. +#[no_mangle] +pub unsafe fn main() { + stm32f429zi::init(); + + let (peripherals, syscfg, dma1) = create_peripherals(); + peripherals.init(); + let base_peripherals = &peripherals.stm32f4; + + setup_peripherals( + &base_peripherals.tim2, + &peripherals.trng, + &peripherals.can1, + &peripherals.rtc, + ); + + set_pin_primary_functions(syscfg, &base_peripherals.gpio_ports); + + setup_dma( + dma1, + &base_peripherals.dma1_streams, + &base_peripherals.usart3, + ); + + let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); + + let chip = static_init!( + stm32f429zi::chip::Stm32f4xx, + stm32f429zi::chip::Stm32f4xx::new(peripherals) + ); + CHIP = Some(chip); + + // UART + + // Create a shared UART channel for kernel debug. + base_peripherals.usart3.enable_clock(); + let uart_mux = components::console::UartMuxComponent::new(&base_peripherals.usart3, 115200) + .finalize(components::uart_mux_component_static!()); + + io::WRITER.set_initialized(); + + // Create capabilities that the board needs to call certain protected kernel + // functions. + let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability); + let main_loop_capability = create_capability!(capabilities::MainLoopCapability); + let process_management_capability = + create_capability!(capabilities::ProcessManagementCapability); + + // Setup the console. + let console = components::console::ConsoleComponent::new( + board_kernel, + capsules_core::console::DRIVER_NUM, + uart_mux, + ) + .finalize(components::console_component_static!()); + // Create the debugger object that handles calls to `debug!()`. + components::debug_writer::DebugWriterComponent::new(uart_mux) + .finalize(components::debug_writer_component_static!()); + + // LEDs + + // Clock to Port A is enabled in `set_pin_primary_functions()` + let gpio_ports = &base_peripherals.gpio_ports; + + let led = components::led::LedsComponent::new().finalize(components::led_component_static!( + LedHigh<'static, stm32f429zi::gpio::Pin>, + LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB00).unwrap()), + LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB07).unwrap()), + LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB14).unwrap()), + )); + + // BUTTONs + let button = components::button::ButtonComponent::new( + board_kernel, + capsules_core::button::DRIVER_NUM, + components::button_component_helper!( + stm32f429zi::gpio::Pin, + ( + gpio_ports.get_pin(stm32f429zi::gpio::PinId::PC13).unwrap(), + kernel::hil::gpio::ActivationMode::ActiveHigh, + kernel::hil::gpio::FloatingState::PullNone + ) + ), + ) + .finalize(components::button_component_static!(stm32f429zi::gpio::Pin)); + + // ALARM + + let tim2 = &base_peripherals.tim2; + let mux_alarm = components::alarm::AlarmMuxComponent::new(tim2).finalize( + components::alarm_mux_component_static!(stm32f429zi::tim2::Tim2), + ); + + let alarm = components::alarm::AlarmDriverComponent::new( + board_kernel, + capsules_core::alarm::DRIVER_NUM, + mux_alarm, + ) + .finalize(components::alarm_component_static!(stm32f429zi::tim2::Tim2)); + + // GPIO + let gpio = GpioComponent::new( + board_kernel, + capsules_core::gpio::DRIVER_NUM, + components::gpio_component_helper!( + stm32f429zi::gpio::Pin, + // Arduino like RX/TX + 0 => gpio_ports.get_pin(PinId::PG09).unwrap(), //D0 + 1 => gpio_ports.pins[6][14].as_ref().unwrap(), //D1 + 2 => gpio_ports.pins[5][15].as_ref().unwrap(), //D2 + 3 => gpio_ports.pins[4][13].as_ref().unwrap(), //D3 + 4 => gpio_ports.pins[5][14].as_ref().unwrap(), //D4 + 5 => gpio_ports.pins[4][11].as_ref().unwrap(), //D5 + 6 => gpio_ports.pins[4][9].as_ref().unwrap(), //D6 + 7 => gpio_ports.pins[5][13].as_ref().unwrap(), //D7 + 8 => gpio_ports.pins[5][12].as_ref().unwrap(), //D8 + 9 => gpio_ports.pins[3][15].as_ref().unwrap(), //D9 + // SPI Pins + 10 => gpio_ports.pins[3][14].as_ref().unwrap(), //D10 + 11 => gpio_ports.pins[0][7].as_ref().unwrap(), //D11 + 12 => gpio_ports.pins[0][6].as_ref().unwrap(), //D12 + 13 => gpio_ports.pins[0][5].as_ref().unwrap(), //D13 + // I2C Pins + 14 => gpio_ports.pins[1][9].as_ref().unwrap(), //D14 + 15 => gpio_ports.pins[1][8].as_ref().unwrap(), //D15 + 16 => gpio_ports.pins[2][6].as_ref().unwrap(), //D16 + 17 => gpio_ports.pins[1][15].as_ref().unwrap(), //D17 + 18 => gpio_ports.pins[1][13].as_ref().unwrap(), //D18 + 19 => gpio_ports.pins[1][12].as_ref().unwrap(), //D19 + 20 => gpio_ports.pins[0][15].as_ref().unwrap(), //D20 + 21 => gpio_ports.pins[2][7].as_ref().unwrap(), //D21 + // SPI B Pins + // 22 => gpio_ports.pins[1][5].as_ref().unwrap(), //D22 + // 23 => gpio_ports.pins[1][3].as_ref().unwrap(), //D23 + // 24 => gpio_ports.pins[0][4].as_ref().unwrap(), //D24 + // 24 => gpio_ports.pins[1][4].as_ref().unwrap(), //D25 + // QSPI + 26 => gpio_ports.pins[1][6].as_ref().unwrap(), //D26 + 27 => gpio_ports.pins[1][2].as_ref().unwrap(), //D27 + 28 => gpio_ports.pins[3][13].as_ref().unwrap(), //D28 + 29 => gpio_ports.pins[3][12].as_ref().unwrap(), //D29 + 30 => gpio_ports.pins[3][11].as_ref().unwrap(), //D30 + 31 => gpio_ports.pins[4][2].as_ref().unwrap(), //D31 + // Timer Pins + 32 => gpio_ports.pins[0][0].as_ref().unwrap(), //D32 + 33 => gpio_ports.pins[1][0].as_ref().unwrap(), //D33 + 34 => gpio_ports.pins[4][0].as_ref().unwrap(), //D34 + 35 => gpio_ports.pins[1][11].as_ref().unwrap(), //D35 + 36 => gpio_ports.pins[1][10].as_ref().unwrap(), //D36 + 37 => gpio_ports.pins[4][15].as_ref().unwrap(), //D37 + 38 => gpio_ports.pins[4][14].as_ref().unwrap(), //D38 + 39 => gpio_ports.pins[4][12].as_ref().unwrap(), //D39 + 40 => gpio_ports.pins[4][10].as_ref().unwrap(), //D40 + 41 => gpio_ports.pins[4][7].as_ref().unwrap(), //D41 + 42 => gpio_ports.pins[4][8].as_ref().unwrap(), //D42 + // SDMMC + 43 => gpio_ports.pins[2][8].as_ref().unwrap(), //D43 + 44 => gpio_ports.pins[2][9].as_ref().unwrap(), //D44 + 45 => gpio_ports.pins[2][10].as_ref().unwrap(), //D45 + 46 => gpio_ports.pins[2][11].as_ref().unwrap(), //D46 + 47 => gpio_ports.pins[2][12].as_ref().unwrap(), //D47 + 48 => gpio_ports.pins[3][2].as_ref().unwrap(), //D48 + 49 => gpio_ports.pins[6][2].as_ref().unwrap(), //D49 + 50 => gpio_ports.pins[6][3].as_ref().unwrap(), //D50 + // USART + 51 => gpio_ports.pins[3][7].as_ref().unwrap(), //D51 + 52 => gpio_ports.pins[3][6].as_ref().unwrap(), //D52 + 53 => gpio_ports.pins[3][5].as_ref().unwrap(), //D53 + 54 => gpio_ports.pins[3][4].as_ref().unwrap(), //D54 + 55 => gpio_ports.pins[3][3].as_ref().unwrap(), //D55 + 56 => gpio_ports.pins[4][2].as_ref().unwrap(), //D56 + 57 => gpio_ports.pins[4][4].as_ref().unwrap(), //D57 + 58 => gpio_ports.pins[4][5].as_ref().unwrap(), //D58 + 59 => gpio_ports.pins[4][6].as_ref().unwrap(), //D59 + 60 => gpio_ports.pins[4][3].as_ref().unwrap(), //D60 + 61 => gpio_ports.pins[5][8].as_ref().unwrap(), //D61 + 62 => gpio_ports.pins[5][7].as_ref().unwrap(), //D62 + 63 => gpio_ports.pins[5][9].as_ref().unwrap(), //D63 + 64 => gpio_ports.pins[6][1].as_ref().unwrap(), //D64 + 65 => gpio_ports.pins[6][0].as_ref().unwrap(), //D65 + 66 => gpio_ports.pins[3][1].as_ref().unwrap(), //D66 + 67 => gpio_ports.pins[3][0].as_ref().unwrap(), //D67 + 68 => gpio_ports.pins[5][0].as_ref().unwrap(), //D68 + 69 => gpio_ports.pins[5][1].as_ref().unwrap(), //D69 + 70 => gpio_ports.pins[5][2].as_ref().unwrap(), //D70 + 71 => gpio_ports.pins[0][7].as_ref().unwrap(), //D71 + + // ADC Pins + // Enable the to use the ADC pins as GPIO + // 72 => gpio_ports.pins[0][3].as_ref().unwrap(), //A0 + // 73 => gpio_ports.pins[2][0].as_ref().unwrap(), //A1 + // 74 => gpio_ports.pins[2][3].as_ref().unwrap(), //A2 + 75 => gpio_ports.pins[5][3].as_ref().unwrap(), //A3 + 76 => gpio_ports.pins[5][5].as_ref().unwrap(), //A4 + 77 => gpio_ports.pins[5][10].as_ref().unwrap(), //A5 + // 78 => gpio_ports.pins[1][1].as_ref().unwrap(), //A6 + // 79 => gpio_ports.pins[2][2].as_ref().unwrap(), //A7 + 80 => gpio_ports.pins[5][4].as_ref().unwrap() //A8 + ), + ) + .finalize(components::gpio_component_static!(stm32f429zi::gpio::Pin)); + + // ADC + let adc_mux = components::adc::AdcMuxComponent::new(&base_peripherals.adc1) + .finalize(components::adc_mux_component_static!(stm32f429zi::adc::Adc)); + + let temp_sensor = components::temperature_stm::TemperatureSTMComponent::new( + adc_mux, + stm32f429zi::adc::Channel::Channel18, + 2.5, + 0.76, + ) + .finalize(components::temperature_stm_adc_component_static!( + stm32f429zi::adc::Adc + )); + let grant_cap = create_capability!(capabilities::MemoryAllocationCapability); + let grant_temperature = + board_kernel.create_grant(capsules_extra::temperature::DRIVER_NUM, &grant_cap); + + let temp = static_init!( + capsules_extra::temperature::TemperatureSensor<'static>, + capsules_extra::temperature::TemperatureSensor::new(temp_sensor, grant_temperature) + ); + kernel::hil::sensors::TemperatureDriver::set_client(temp_sensor, temp); + + let adc_channel_0 = + components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel3) + .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + + let adc_channel_1 = + components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel10) + .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + + let adc_channel_2 = + components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel13) + .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + + let adc_channel_3 = + components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel9) + .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + + let adc_channel_4 = + components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel12) + .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + + let adc_syscall = + components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM) + .finalize(components::adc_syscall_component_helper!( + adc_channel_0, + adc_channel_1, + adc_channel_2, + adc_channel_3, + adc_channel_4, + )); + + let process_printer = components::process_printer::ProcessPrinterTextComponent::new() + .finalize(components::process_printer_text_component_static!()); + PROCESS_PRINTER = Some(process_printer); + + // DAC + let dac = components::dac::DacComponent::new(&base_peripherals.dac) + .finalize(components::dac_component_static!()); + + // RNG + let rng = components::rng::RngComponent::new( + board_kernel, + capsules_core::rng::DRIVER_NUM, + &peripherals.trng, + ) + .finalize(components::rng_component_static!()); + + // CAN + let can = components::can::CanComponent::new( + board_kernel, + capsules_extra::can::DRIVER_NUM, + &peripherals.can1, + ) + .finalize(components::can_component_static!( + stm32f429zi::can::Can<'static> + )); + + // RTC DATE TIME + match peripherals.rtc.rtc_init() { + Err(e) => debug!("{:?}", e), + _ => (), + }; + + let date_time = components::date_time::DateTimeComponent::new( + board_kernel, + capsules_extra::date_time::DRIVER_NUM, + &peripherals.rtc, + ) + .finalize(components::date_time_component_static!( + stm32f429zi::rtc::Rtc<'static> + )); + + // PROCESS CONSOLE + let process_console = components::process_console::ProcessConsoleComponent::new( + board_kernel, + uart_mux, + mux_alarm, + process_printer, + Some(cortexm4::support::reset), + ) + .finalize(components::process_console_component_static!( + stm32f429zi::tim2::Tim2 + )); + let _ = process_console.start(); + + let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) + .finalize(components::round_robin_component_static!(NUM_PROCS)); + + let nucleo_f429zi = NucleoF429ZI { + console: console, + ipc: kernel::ipc::IPC::new( + board_kernel, + kernel::ipc::DRIVER_NUM, + &memory_allocation_capability, + ), + adc: adc_syscall, + dac: dac, + led: led, + temperature: temp, + button: button, + alarm: alarm, + gpio: gpio, + rng: rng, + + scheduler, + systick: cortexm4::systick::SysTick::new(), + can: can, + date_time, + }; + + // // Optional kernel tests + // // + // // See comment in `boards/imix/src/main.rs` + // virtual_uart_rx_test::run_virtual_uart_receive(mux_uart); + + debug!("Initialization complete. Entering main loop"); + + // These symbols are defined in the linker script. + extern "C" { + /// Beginning of the ROM region containing app images. + static _sapps: u8; + /// End of the ROM region containing app images. + static _eapps: u8; + /// Beginning of the RAM region for app memory. + static mut _sappmem: u8; + /// End of the RAM region for app memory. + static _eappmem: u8; + } + + kernel::process::load_processes( + board_kernel, + chip, + core::slice::from_raw_parts( + &_sapps as *const u8, + &_eapps as *const u8 as usize - &_sapps as *const u8 as usize, + ), + core::slice::from_raw_parts_mut( + &mut _sappmem as *mut u8, + &_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize, + ), + &mut PROCESSES, + &FAULT_RESPONSE, + &process_management_capability, + ) + .unwrap_or_else(|err| { + debug!("Error loading processes!"); + debug!("{:?}", err); + }); + + //Uncomment to run multi alarm test + /*components::test::multi_alarm_test::MultiAlarmTestComponent::new(mux_alarm) + .finalize(components::multi_alarm_test_component_buf!(stm32f429zi::tim2::Tim2)) + .run();*/ + + board_kernel.kernel_loop( + &nucleo_f429zi, + chip, + Some(&nucleo_f429zi.ipc), + &main_loop_capability, + ); +} diff --git a/capsules/extra/src/graphics_display.rs b/capsules/extra/src/graphic_display.rs similarity index 100% rename from capsules/extra/src/graphics_display.rs rename to capsules/extra/src/graphic_display.rs diff --git a/capsules/extra/src/lib.rs b/capsules/extra/src/lib.rs index 455795fb74..680e1536bb 100644 --- a/capsules/extra/src/lib.rs +++ b/capsules/extra/src/lib.rs @@ -36,7 +36,7 @@ pub mod fm25cl; pub mod ft6x06; pub mod fxos8700cq; pub mod gpio_async; -pub mod graphics_display; +pub mod graphic_display; pub mod hd44780; pub mod hmac; pub mod hmac_sha256; From ab3066532173208beb0129093e426c0cfeeea7cd Mon Sep 17 00:00:00 2001 From: Lazar Cristian-Stefan Date: Tue, 16 Jan 2024 19:52:59 +0200 Subject: [PATCH 4/9] Added partial code sequence for initializing display capsules --- boards/components/src/graphic_display.rs | 2 +- boards/components/src/ssd1306.rs | 18 +- boards/nucleo_f429zi/src/main.rs | 442 ++++++----------- .../src/{main_org.rs => main_old.rs} | 444 ++++++++++++------ 4 files changed, 468 insertions(+), 438 deletions(-) rename boards/nucleo_f429zi/src/{main_org.rs => main_old.rs} (65%) diff --git a/boards/components/src/graphic_display.rs b/boards/components/src/graphic_display.rs index 86ef56d998..9861a9bf67 100644 --- a/boards/components/src/graphic_display.rs +++ b/boards/components/src/graphic_display.rs @@ -37,7 +37,7 @@ use kernel::create_capability; macro_rules! graphic_display_component_static { ($s:literal $(,)?) => {{ let buffer = kernel::static_buf!([u8; $s]); - let screen = kernel::static_buf!(drivers::graphic_display::GraphicDisplay); + let screen = kernel::static_buf!(capsules_extra::graphic_display::GraphicDisplay); (buffer, screen) };}; diff --git a/boards/components/src/ssd1306.rs b/boards/components/src/ssd1306.rs index 0192c1d4eb..dc13068a9a 100644 --- a/boards/components/src/ssd1306.rs +++ b/boards/components/src/ssd1306.rs @@ -8,23 +8,23 @@ use kernel::deferred_call::DeferredCallClient; #[macro_export] macro_rules! ssd1306_component_static { ($B: ty, $(,)?) => {{ - let buffer = kernel::static_buf!([u8; drivers::ssd1306::BUFFER_SIZE]); + let buffer = kernel::static_buf!([u8; capsules_extra::ssd1306::BUFFER_SIZE]); let app_write_buffer = kernel::static_buf!( - [u8; drivers::ssd1306::WIDTH * drivers::ssd1306::HEIGHT / 8 - + drivers::ssd1306::BUFFER_PADDING] + [u8; capsules_extra::ssd1306::WIDTH * capsules_extra::ssd1306::HEIGHT / 8 + + capsules_extra::ssd1306::BUFFER_PADDING] ); let bus_write_buffer = kernel::static_buf!( - [u8; drivers::ssd1306::WIDTH * drivers::ssd1306::HEIGHT / 8 - + drivers::ssd1306::BUFFER_PADDING] + [u8; capsules_extra::ssd1306::WIDTH * capsules_extra::ssd1306::HEIGHT / 8 + + capsules_extra::ssd1306::BUFFER_PADDING] ); let aux_write_buffer = kernel::static_buf!( - [u8; drivers::ssd1306::WIDTH * drivers::ssd1306::HEIGHT / 8 - + drivers::ssd1306::BUFFER_PADDING] + [u8; capsules_extra::ssd1306::WIDTH * capsules_extra::ssd1306::HEIGHT / 8 + + capsules_extra::ssd1306::BUFFER_PADDING] ); let command_sequence = kernel::static_buf!( - [drivers::ssd1306::ScreenCommand; drivers::ssd1306::SEQUENCE_BUFFER_SIZE] + [capsules_extra::ssd1306::ScreenCommand; capsules_extra::ssd1306::SEQUENCE_BUFFER_SIZE] ); - let ssd1306 = kernel::static_buf!(drivers::ssd1306::SSD1306<'static, $B>); + let ssd1306 = kernel::static_buf!(capsules_extra::ssd1306::SSD1306<'static, $B>); ( ssd1306, command_sequence, diff --git a/boards/nucleo_f429zi/src/main.rs b/boards/nucleo_f429zi/src/main.rs index e748aa22d1..2e58c33017 100644 --- a/boards/nucleo_f429zi/src/main.rs +++ b/boards/nucleo_f429zi/src/main.rs @@ -1,3 +1,7 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2022. + //! Board file for Nucleo-F429ZI development board //! //! - @@ -7,28 +11,19 @@ // https://github.com/rust-lang/rust/issues/62184. #![cfg_attr(not(doc), no_main)] #![deny(missing_docs)] -#![feature(core_intrinsics)] -use kernel::hil::gpio::FloatingState; -use kernel::hil::led::LedLow; use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; use components::gpio::GpioComponent; use kernel::capabilities; use kernel::component::Component; -use kernel::deferred_call::{DeferredCall, DeferredCallClient}; +use kernel::hil::led::LedHigh; use kernel::platform::{KernelResources, SyscallDriverLookup}; use kernel::scheduler::round_robin::RoundRobinSched; use kernel::{create_capability, debug, static_init}; -use capsules_core::virtualizers::virtual_i2c::MuxI2C; -use kernel::hil::i2c::I2CMaster; use stm32f429zi::gpio::{AlternateFunction, Mode, PinId, PortId}; use stm32f429zi::interrupt_service::Stm32f429ziDefaultPeripherals; -use stm32f429zi::{rcc, rcc::Rcc}; -use stm32f4xx::{flash, i2c, pwr, utils}; -use stm32f429zi::pwr; -use core::intrinsics::breakpoint; /// Support routines for debugging I/O. pub mod io; @@ -58,11 +53,12 @@ struct NucleoF429ZI { ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>, led: &'static capsules_core::led::LedDriver< 'static, - LedLow<'static, stm32f429zi::gpio::Pin<'static>>, + LedHigh<'static, stm32f429zi::gpio::Pin<'static>>, 3, >, button: &'static capsules_core::button::Button<'static, stm32f429zi::gpio::Pin<'static>>, adc: &'static capsules_core::adc::AdcVirtualized<'static>, + dac: &'static capsules_extra::dac::Dac<'static>, alarm: &'static capsules_core::alarm::AlarmDriver< 'static, VirtualMuxAlarm<'static, stm32f429zi::tim2::Tim2<'static>>, @@ -73,15 +69,11 @@ struct NucleoF429ZI { scheduler: &'static RoundRobinSched<'static>, systick: cortexm4::systick::SysTick, - - display: &'static capsules_extra::graphic_display::GraphicDisplay<'static>, - ipc_comm: &'static kernel::ipc::IPC<00000>, - pwm: &'static capsules_extra::pwm::Pwm<'static, 1>, - measurement: &'static capsules_extra::measurement::MeasurementCapsule< //todo implemente capsule + can: &'static capsules_extra::can::CanCapsule<'static, stm32f429zi::can::Can<'static>>, + date_time: &'static capsules_extra::date_time::DateTimeCapsule< 'static, - stm32f4xx::tim3::Tim2_5<'static>, //todo check + stm32f429zi::rtc::Rtc<'static>, >, - can: &'static capsules_extra::can::CanCapsule<'static, stm32f429zi::can::Can<'static>>, } /// Mapping of integer syscalls to objects that implement syscalls. @@ -100,11 +92,9 @@ impl SyscallDriverLookup for NucleoF429ZI { kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)), capsules_core::rng::DRIVER_NUM => f(Some(self.rng)), - capsules_extra::graphic_display::DRIVER_NUM => f(Some(self.display)), - kernel::ipc::DRIVER_NUM => f(Some(self.ipc_comm)), - capsules_extra::pwm::DRIVER_NUM => f(Some(self.pwm)), - capsules_extra::measurement::DRIVER_NUM => f(Some(self.measurement)), // impl measurement capsules_extra::can::DRIVER_NUM => f(Some(self.can)), + capsules_extra::dac::DRIVER_NUM => f(Some(self.dac)), + capsules_extra::date_time::DRIVER_NUM => f(Some(self.date_time)), _ => f(None), } } @@ -186,48 +176,46 @@ unsafe fn setup_dma( unsafe fn set_pin_primary_functions( syscfg: &stm32f429zi::syscfg::Syscfg, gpio_ports: &'static stm32f429zi::gpio::GpioPorts<'static>, - i2c1: &stm32f4xx::i2c::I2C, ) { - use apis::gpio::Configure; + use kernel::hil::gpio::Configure; syscfg.enable_clock(); gpio_ports.get_port_from_port_id(PortId::B).enable_clock(); // User LD2 is connected to PB07. Configure PB07 as `debug_gpio!(0, ...)` - if let Some(pin) = gpio_ports.get_pin(PinId::PB07) { + gpio_ports.get_pin(PinId::PB07).map(|pin| { pin.make_output(); // Configure kernel debug gpios as early as possible kernel::debug::assign_gpios(Some(pin), None, None); - }; + }); gpio_ports.get_port_from_port_id(PortId::D).enable_clock(); // pd8 and pd9 (USART3) is connected to ST-LINK virtual COM port - if let Some(pin) = gpio_ports.get_pin(PinId::PD08) { + gpio_ports.get_pin(PinId::PD08).map(|pin| { pin.set_mode(Mode::AlternateFunctionMode); // AF7 is USART2_TX pin.set_alternate_function(AlternateFunction::AF7); - }; - if let Some(pin) = gpio_ports.get_pin(PinId::PD09) { + }); + gpio_ports.get_pin(PinId::PD09).map(|pin| { pin.set_mode(Mode::AlternateFunctionMode); // AF7 is USART2_RX pin.set_alternate_function(AlternateFunction::AF7); - }; + }); gpio_ports.get_port_from_port_id(PortId::C).enable_clock(); - // button is connected on pa6 - if let Some(pin) = gpio_ports.get_pin(PinId::PA06) { - pin.set_mode(Mode::Input); + // button is connected on pc13 + gpio_ports.get_pin(PinId::PC13).map(|pin| { pin.enable_interrupt(); - } + }); // set interrupt for pin D0 - if let Some(pin) = gpio_ports.get_pin(PinId::PG09) { + gpio_ports.get_pin(PinId::PG09).map(|pin| { pin.enable_interrupt(); - } + }); // Enable clocks for GPIO Ports // Disable some of them if you don't need some of the GPIOs @@ -239,98 +227,35 @@ unsafe fn set_pin_primary_functions( gpio_ports.get_port_from_port_id(PortId::H).enable_clock(); // Arduino A0 - if let Some(pin) = gpio_ports.get_pin(PinId::PC00) { + gpio_ports.get_pin(PinId::PA03).map(|pin| { pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - } - - // // Arduino A1 - // if let Some(pin) = gpio_ports.get_pin(PinId::PC00) { - // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - // } - - // // Arduino A2 - // if let Some(pin) = gpio_ports.get_pin(PinId::PC03) { - // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - // } - - // // Arduino A6 - // if let Some(pin) = gpio_ports.get_pin(PinId::PB01) { - // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - // } - - // // Arduino A7 - // if let Some(pin) = gpio_ports.get_pin(PinId::PC02) { - // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - // } - - if let Some(pin) = gpio_ports.get_pin(PinId::PB08) { - pin.set_mode(Mode::AlternateFunctionMode); - pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); - pin.set_mode_output_opendrain(); - // AF4 is I2C - pin.set_speed(); - pin.set_alternate_function(AlternateFunction::AF4); - }; - if let Some(pin) = gpio_ports.get_pin(PinId::PB09) { - pin.make_output(); - pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); - pin.set_speed(); - pin.set_mode(Mode::AlternateFunctionMode); - pin.set_mode_output_opendrain(); - // AF4 is I2C - pin.set_alternate_function(AlternateFunction::AF4); - }; - - i2c1.enable_clock(); - i2c1.set_speed(i2c::I2CSpeed::Speed100k, 8); - - // PE11 is connected to motor driver IN2 - gpio_ports.get_pin(PinId::PE11).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - // AF1 is TIM1/2 - pin.set_alternate_function(AlternateFunction::AF1); - }); - - // PE13 is connected to motor driver IN1 - gpio_ports.get_pin(PinId::PE13).map(|pin| { - pin.set_mode(Mode::GeneralPurposeOutputMode); - // pin.set_mode(Mode::AlternateFunctionMode); - // // AF1 is TIM1/2 - // pin.set_alternate_function(AlternateFunction::AF1); }); - // PA7 is Encoder pulse counting - gpio_ports.get_pin(PinId::PA07).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - pin.set_floating_state(FloatingState::PullDown); - //pin.set_mode(Mode::AlternateFunctionMode); - pin.set_alternate_function(AlternateFunction::AF2); + // Arduino A1 + gpio_ports.get_pin(PinId::PC00).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); }); - // PA3 is Encoder pulse counting - gpio_ports.get_pin(PinId::PA03).map(|pin| { - pin.make_input(); - pin.set_floating_state(FloatingState::PullNone); + // Arduino A2 + gpio_ports.get_pin(PinId::PC03).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); }); - // PA08 is Clock Output MCO1 - gpio_ports.get_pin(PinId::PA08).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - // AF0 is Clock output (MCO1) - pin.set_alternate_function(AlternateFunction::AF0); + // Arduino A6 + gpio_ports.get_pin(PinId::PB01).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); }); - // PC09 is ClockOutput MCO2 - gpio_ports.get_pin(PinId::PC09).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - pin.set_alternate_function(AlternateFunction::AF0); + // Arduino A7 + gpio_ports.get_pin(PinId::PC02).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); }); gpio_ports.get_pin(PinId::PD00).map(|pin| { pin.set_mode(Mode::AlternateFunctionMode); // AF9 is CAN_RX pin.set_alternate_function(AlternateFunction::AF9); - pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); + pin.set_floating_state(kernel::hil::gpio::FloatingState::PullDown); }); gpio_ports.get_pin(PinId::PD01).map(|pin| { pin.set_mode(Mode::AlternateFunctionMode); @@ -338,8 +263,9 @@ unsafe fn set_pin_primary_functions( pin.set_alternate_function(AlternateFunction::AF9); }); - gpio_ports.get_pin(PinId::PE08).map(|pin| { - pin.make_output(); + // DAC Channel 1 + gpio_ports.get_pin(PinId::PA04).map(|pin| { + pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); }); } @@ -347,9 +273,8 @@ unsafe fn set_pin_primary_functions( unsafe fn setup_peripherals( tim2: &stm32f429zi::tim2::Tim2, trng: &stm32f429zi::trng::Trng, - tim1: &stm32f4xx::tim1::Tim1_8, - tim3: &stm32f4xx::tim3::Tim2_5, can1: &'static stm32f429zi::can::Can, + rtc: &'static stm32f429zi::rtc::Rtc, ) { // USART3 IRQn is 39 cortexm4::nvic::Nvic::new(stm32f429zi::nvic::USART3).enable(); @@ -362,14 +287,11 @@ unsafe fn setup_peripherals( // RNG trng.enable_clock(); - tim1.enable_clock(); - tim1.start(); - // tim1.start_pwm(&stm32f4xx::tim1::TimOutputs::OutputCh2, 2000, 800); - tim3.enable_clock(); - tim3.start(); - // CAN can1.enable_clock(); + + // RTC + rtc.enable_clock(); } /// Statically initialize the core peripherals for the chip. @@ -378,14 +300,14 @@ unsafe fn setup_peripherals( /// removed when this function returns. Otherwise, the stack space used for /// these static_inits is wasted. #[inline(never)] -unsafe fn get_peripherals() -> ( +unsafe fn create_peripherals() -> ( &'static mut Stm32f429ziDefaultPeripherals<'static>, &'static stm32f429zi::syscfg::Syscfg<'static>, &'static stm32f429zi::dma::Dma1<'static>, - &'static stm32f429zi::rcc::Rcc, ) { // We use the default HSI 16Mhz clock let rcc = static_init!(stm32f429zi::rcc::Rcc, stm32f429zi::rcc::Rcc::new()); + let syscfg = static_init!( stm32f429zi::syscfg::Syscfg, stm32f429zi::syscfg::Syscfg::new(rcc) @@ -401,97 +323,28 @@ unsafe fn get_peripherals() -> ( Stm32f429ziDefaultPeripherals, Stm32f429ziDefaultPeripherals::new(rcc, exti, dma1, dma2) ); - (peripherals, syscfg, dma1, rcc) -} - -/// Initialize clock tree and related peripherals (flash, pwr) -/// -/// In order to start the PLL, the pwr scaling needs to be configured. In order to increase the system clock to 180MHz, the flash latency needs to be increased and pwr overdrive needs to be enabled. -/// see: RM0090 ch. 5.1.4 pg 123 -unsafe fn try_init_clocks(rcc: &Rcc) -> Result<(), ()> { - // only PWR peripheral should be enabled, HSI -> SystemClock - rcc::enable_boot_esential_clocks()?; - pwr::configure_voltage_scaling(1)?; - - // uncomment these lines in order to measure internal clocks - rcc.configure_prescaler(&rcc::RccClockDestination::MClockOutput1, 5); - rcc.configure_prescaler(&rcc::RccClockDestination::MClockOutput2, 5); - - // HSI -> PLL, wait for HSI to be stable - utils::wait_for_condition( - 1_000, - || rcc.is_clock_stable(&rcc::RccClockSource::HsiRc), - || (), - )?; - - // HSI = 16MHz - // PLL output = (16/8)*180/2 = 180 MHz - rcc.configure_pll(8, 180, 2); - rcc.enable(rcc::RccClockSource::Pll); - - pwr::enable_overdrive()?; - flash::set_latency(5); - - let _ = utils::wait_for_condition( - 1_000, - || rcc.is_clock_stable(&rcc::RccClockSource::Pll), - || (), - ); - rcc.configure_prescaler(&rcc::RccClockDestination::Apb1, 4); - rcc.configure_prescaler(&rcc::RccClockDestination::Apb2, 4); - rcc.route( - &rcc::RccClockSource::Pll, - &rcc::RccClockDestination::SystemClock, - )?; - - Ok(()) -} - -/// Initialize clock tree, if it fails it reverts to default configuration (HSI-> SystemClcok) -pub unsafe fn init_clocks(rcc: &Rcc) { - match try_init_clocks(&rcc) { - Ok(_) => {} - Err(_) => { - let _ = rcc.route( - &rcc::RccClockSource::HsiRc, - &rcc::RccClockDestination::SystemClock, - ); - } - } - if rcc.compute_nominal_frequency().is_err() { - breakpoint(); - } + (peripherals, syscfg, dma1) } /// Main function. /// -/// # Safety -/// This function needs to be marked unsafe allows ... -/// /// This is called after RAM initialization is complete. #[no_mangle] pub unsafe fn main() { stm32f429zi::init(); - let (peripherals, syscfg, dma1, rcc) = get_peripherals(); + let (peripherals, syscfg, dma1) = create_peripherals(); peripherals.init(); - - init_clocks(rcc); let base_peripherals = &peripherals.stm32f4; setup_peripherals( &base_peripherals.tim2, &peripherals.trng, - &base_peripherals.tim1, - &base_peripherals.tim3, &peripherals.can1, + &peripherals.rtc, ); - set_pin_primary_functions( - syscfg, - &base_peripherals.gpio_ports, - &peripherals.stm32f4.i2c1, - ); + set_pin_primary_functions(syscfg, &base_peripherals.gpio_ports); setup_dma( dma1, @@ -501,14 +354,6 @@ pub unsafe fn main() { let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); - let dynamic_deferred_call_clients = - static_init!([DynamicDeferredCallClientState; 3], Default::default()); - let dynamic_deferred_caller = static_init!( - DynamicDeferredCall, - DynamicDeferredCall::new(dynamic_deferred_call_clients) - ); - DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); - let chip = static_init!( stm32f429zi::chip::Stm32f4xx, stm32f429zi::chip::Stm32f4xx::new(peripherals) @@ -519,12 +364,8 @@ pub unsafe fn main() { // Create a shared UART channel for kernel debug. base_peripherals.usart3.enable_clock(); - let uart_mux = components::console::UartMuxComponent::new( - &base_peripherals.usart3, - 115200, - dynamic_deferred_caller, - ) - .finalize(components::uart_mux_component_static!()); + let uart_mux = components::console::UartMuxComponent::new(&base_peripherals.usart3, 115200) + .finalize(components::uart_mux_component_static!()); io::WRITER.set_initialized(); @@ -538,7 +379,7 @@ pub unsafe fn main() { // Setup the console. let console = components::console::ConsoleComponent::new( board_kernel, - capsules::console::DRIVER_NUM, + capsules_core::console::DRIVER_NUM, uart_mux, ) .finalize(components::console_component_static!()); @@ -552,26 +393,22 @@ pub unsafe fn main() { let gpio_ports = &base_peripherals.gpio_ports; let led = components::led::LedsComponent::new().finalize(components::led_component_static!( - LedLow<'static, stm32f429zi::gpio::Pin>, - LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PD15).unwrap()), - LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PD14).unwrap()), - LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PA05).unwrap()), + LedHigh<'static, stm32f429zi::gpio::Pin>, + LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB00).unwrap()), + LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB07).unwrap()), + LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB14).unwrap()), )); - // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB00).unwrap()), - // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB07).unwrap()), - // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB14).unwrap()), - // BUTTONs let button = components::button::ButtonComponent::new( board_kernel, - capsules::button::DRIVER_NUM, + capsules_core::button::DRIVER_NUM, components::button_component_helper!( stm32f429zi::gpio::Pin, ( - gpio_ports.get_pin(stm32f429zi::gpio::PinId::PA06).unwrap(), - apis::gpio::ActivationMode::ActiveHigh, - apis::gpio::FloatingState::PullDown + gpio_ports.get_pin(stm32f429zi::gpio::PinId::PC13).unwrap(), + kernel::hil::gpio::ActivationMode::ActiveHigh, + kernel::hil::gpio::FloatingState::PullNone ) ), ) @@ -586,7 +423,7 @@ pub unsafe fn main() { let alarm = components::alarm::AlarmDriverComponent::new( board_kernel, - capsules::alarm::DRIVER_NUM, + capsules_core::alarm::DRIVER_NUM, mux_alarm, ) .finalize(components::alarm_component_static!(stm32f429zi::tim2::Tim2)); @@ -594,7 +431,7 @@ pub unsafe fn main() { // GPIO let gpio = GpioComponent::new( board_kernel, - capsules::gpio::DRIVER_NUM, + capsules_core::gpio::DRIVER_NUM, components::gpio_component_helper!( stm32f429zi::gpio::Pin, // Arduino like RX/TX @@ -603,16 +440,16 @@ pub unsafe fn main() { 2 => gpio_ports.pins[5][15].as_ref().unwrap(), //D2 3 => gpio_ports.pins[4][13].as_ref().unwrap(), //D3 4 => gpio_ports.pins[5][14].as_ref().unwrap(), //D4 - // 5 => gpio_ports.pins[4][11].as_ref().unwrap(), //D5 - // 6 => gpio_ports.pins[4][9].as_ref().unwrap(), //D6 + 5 => gpio_ports.pins[4][11].as_ref().unwrap(), //D5 + 6 => gpio_ports.pins[4][9].as_ref().unwrap(), //D6 7 => gpio_ports.pins[5][13].as_ref().unwrap(), //D7 8 => gpio_ports.pins[5][12].as_ref().unwrap(), //D8 - // 9 => gpio_ports.pins[3][15].as_ref().unwrap(), //D9 + 9 => gpio_ports.pins[3][15].as_ref().unwrap(), //D9 // SPI Pins - // 10 => gpio_ports.pins[3][14].as_ref().unwrap(), //D10 - // 11 => gpio_ports.pins[0][7].as_ref().unwrap(), //D11 - // 12 => gpio_ports.pins[0][6].as_ref().unwrap(), //D12 - // 13 => gpio_ports.pins[0][5].as_ref().unwrap(), //D13 + 10 => gpio_ports.pins[3][14].as_ref().unwrap(), //D10 + 11 => gpio_ports.pins[0][7].as_ref().unwrap(), //D11 + 12 => gpio_ports.pins[0][6].as_ref().unwrap(), //D12 + 13 => gpio_ports.pins[0][5].as_ref().unwrap(), //D13 // I2C Pins 14 => gpio_ports.pins[1][9].as_ref().unwrap(), //D14 15 => gpio_ports.pins[1][8].as_ref().unwrap(), //D15 @@ -671,8 +508,8 @@ pub unsafe fn main() { 63 => gpio_ports.pins[5][9].as_ref().unwrap(), //D63 64 => gpio_ports.pins[6][1].as_ref().unwrap(), //D64 65 => gpio_ports.pins[6][0].as_ref().unwrap(), //D65 - // 66 => gpio_ports.pins[3][1].as_ref().unwrap(), //D66 - // 67 => gpio_ports.pins[3][0].as_ref().unwrap(), //D67 + 66 => gpio_ports.pins[3][1].as_ref().unwrap(), //D66 + 67 => gpio_ports.pins[3][0].as_ref().unwrap(), //D67 68 => gpio_ports.pins[5][0].as_ref().unwrap(), //D68 69 => gpio_ports.pins[5][1].as_ref().unwrap(), //D69 70 => gpio_ports.pins[5][2].as_ref().unwrap(), //D70 @@ -683,7 +520,7 @@ pub unsafe fn main() { // 72 => gpio_ports.pins[0][3].as_ref().unwrap(), //A0 // 73 => gpio_ports.pins[2][0].as_ref().unwrap(), //A1 // 74 => gpio_ports.pins[2][3].as_ref().unwrap(), //A2 - // 75 => gpio_ports.pins[5][3].as_ref().unwrap(), //A3 + 75 => gpio_ports.pins[5][3].as_ref().unwrap(), //A3 76 => gpio_ports.pins[5][5].as_ref().unwrap(), //A4 77 => gpio_ports.pins[5][10].as_ref().unwrap(), //A5 // 78 => gpio_ports.pins[1][1].as_ref().unwrap(), //A6 @@ -717,19 +554,43 @@ pub unsafe fn main() { kernel::hil::sensors::TemperatureDriver::set_client(temp_sensor, temp); let adc_channel_0 = + components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel3) + .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + + let adc_channel_1 = components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel10) .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + let adc_channel_2 = + components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel13) + .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + + let adc_channel_3 = + components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel9) + .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + + let adc_channel_4 = + components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel12) + .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); + let adc_syscall = components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM) .finalize(components::adc_syscall_component_helper!( adc_channel_0, + adc_channel_1, + adc_channel_2, + adc_channel_3, + adc_channel_4, )); let process_printer = components::process_printer::ProcessPrinterTextComponent::new() .finalize(components::process_printer_text_component_static!()); PROCESS_PRINTER = Some(process_printer); + // DAC + let dac = components::dac::DacComponent::new(&base_peripherals.dac) + .finalize(components::dac_component_static!()); + // RNG let rng = components::rng::RngComponent::new( board_kernel, @@ -738,48 +599,49 @@ pub unsafe fn main() { ) .finalize(components::rng_component_static!()); - // PROCESS CONSOLE - let process_console = components::process_console::ProcessConsoleComponent::new( + // CAN + let can = components::can::CanComponent::new( board_kernel, - uart_mux, - mux_alarm, - process_printer, - None, + capsules_extra::can::DRIVER_NUM, + &peripherals.can1, ) - .finalize(components::process_console_component_static!( - stm32f429zi::tim2::Tim2 + .finalize(components::can_component_static!( + stm32f429zi::can::Can<'static> )); - let _ = process_console.start(); - let ipc_comm = - driver_setup::ipc::IPCComponent::new(board_kernel, drivers::communication::DRIVER_NUM) - .finalize(driver_setup::ipc_component_static!()); + // RTC DATE TIME + match peripherals.rtc.rtc_init() { + Err(e) => debug!("{:?}", e), + _ => (), + }; - let can = driver_setup::can::CanComponent::new( + let date_time = components::date_time::DateTimeComponent::new( board_kernel, - capsules_extra::can::DRIVER_NUM, - &peripherals.can1, + capsules_extra::date_time::DRIVER_NUM, + &peripherals.rtc, ) - .finalize(components::can_component_static!( - stm32f429zi::can::Can<'static> + .finalize(components::date_time_component_static!( + stm32f429zi::rtc::Rtc<'static> )); // I2C SSD1306 screen - let i2c_mux = static_init!( - MuxI2C<'static>, - MuxI2C::new(&peripherals.stm32f4.i2c1, None, dynamic_deferred_caller) - ); - peripherals.stm32f4.i2c1.set_master_client(i2c_mux); + let i2c_mux = components::i2c::I2CMuxComponent::new(&peripherals.stm32f4.i2c1, None).finalize( + components::i2c_mux_component_static!(stm32f4xx::i2c::I2C<'static>)); + // static_init!( + // MuxI2C<'static, stm32f4xx::i2c::I2C>, + // MuxI2C::new(&peripherals.stm32f4.i2c1, None) + // ); + kernel::deferred_call::DeferredCallClient::register(i2c_mux); let bus = components::bus::I2CMasterBusComponent::new( i2c_mux, capsules_extra::ssd1306::SLAVE_ADDRESS_WRITE, ) - .finalize(components::i2c_master_bus_component_static!(2)); + .finalize(components::i2c_master_bus_component_static!()); //todo - let ssd1306_screen = components::ssd1306::SSD1306Component::new(bus, dynamic_deferred_caller) + let ssd1306_screen = components::ssd1306::SSD1306Component::new(bus) .finalize(components::ssd1306_component_static!( - capsules_extra::bus::I2CMasterBus<'static, capsules_core::virtualizers::virtual_i2c::I2CDevice<'static>>, + capsules_extra::bus::I2CMasterBus<'static, capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, stm32f4xx::i2c::I2C>>, )); let _ = ssd1306_screen.init(); @@ -792,59 +654,49 @@ pub unsafe fn main() { ) .finalize(components::graphic_display_component_static!(1025)); - let mux_pwm = components::pwm::PwmMuxComponent::new(&base_peripherals.tim1).finalize( - components::pwm_mux_component_static!(stm32f4xx::tim1::Tim1_8), - ); - - let pwm = components::pwm::PwmVirtualComponent::new(board_kernel, capsules_extra::pwm::DRIVER_NUM) - .finalize(components::pwm_syscall_component_helper!( - components::pwm::PwmPinComponent::new( - &mux_pwm, - stm32f4xx::tim1::TimOutputs::OutputCh2, - //gpio_ports.get_pin(stm32f429zi: gpio::PinId::PE11).unwrap() - ) - .finalize(components::pwm_pin_user_component_static!( - stm32f4xx::tim1::Tim1_8 - )) - )); - - let measurement = components::measurement::MeasurementComponent::new(&base_peripherals.tim3) - .finalize(components::measurement_component_static!(stm32f4xx::tim3::Tim2_5)); + // PROCESS CONSOLE + let process_console = components::process_console::ProcessConsoleComponent::new( + board_kernel, + uart_mux, + mux_alarm, + process_printer, + Some(cortexm4::support::reset), + ) + .finalize(components::process_console_component_static!( + stm32f429zi::tim2::Tim2 + )); + let _ = process_console.start(); let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) .finalize(components::round_robin_component_static!(NUM_PROCS)); let nucleo_f429zi = NucleoF429ZI { - console, + console: console, ipc: kernel::ipc::IPC::new( board_kernel, kernel::ipc::DRIVER_NUM, &memory_allocation_capability, ), adc: adc_syscall, - led, + dac: dac, + led: led, temperature: temp, - button, - alarm, - gpio, - rng, + button: button, + alarm: alarm, + gpio: gpio, + rng: rng, scheduler, - systick: cortexm4::systick::SysTick::new_with_calibration( - rcc.get_nominal_frequency_(&rcc::PeripheralClockType::AHB1(rcc::HCLK1::SysTick)), - ), - - display, - ipc_comm, - pwm, - measurement, - can, + systick: cortexm4::systick::SysTick::new(), + can: can, + date_time, }; // // Optional kernel tests // // // // See comment in `boards/imix/src/main.rs` // virtual_uart_rx_test::run_virtual_uart_receive(mux_uart); + debug!("Initialization complete. Entering main loop"); // These symbols are defined in the linker script. diff --git a/boards/nucleo_f429zi/src/main_org.rs b/boards/nucleo_f429zi/src/main_old.rs similarity index 65% rename from boards/nucleo_f429zi/src/main_org.rs rename to boards/nucleo_f429zi/src/main_old.rs index 9e45ad5603..e748aa22d1 100644 --- a/boards/nucleo_f429zi/src/main_org.rs +++ b/boards/nucleo_f429zi/src/main_old.rs @@ -1,7 +1,3 @@ -// Licensed under the Apache License, Version 2.0 or the MIT License. -// SPDX-License-Identifier: Apache-2.0 OR MIT -// Copyright Tock Contributors 2022. - //! Board file for Nucleo-F429ZI development board //! //! - @@ -11,19 +7,28 @@ // https://github.com/rust-lang/rust/issues/62184. #![cfg_attr(not(doc), no_main)] #![deny(missing_docs)] +#![feature(core_intrinsics)] +use kernel::hil::gpio::FloatingState; +use kernel::hil::led::LedLow; use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; use components::gpio::GpioComponent; use kernel::capabilities; use kernel::component::Component; -use kernel::hil::led::LedHigh; +use kernel::deferred_call::{DeferredCall, DeferredCallClient}; use kernel::platform::{KernelResources, SyscallDriverLookup}; use kernel::scheduler::round_robin::RoundRobinSched; use kernel::{create_capability, debug, static_init}; +use capsules_core::virtualizers::virtual_i2c::MuxI2C; +use kernel::hil::i2c::I2CMaster; use stm32f429zi::gpio::{AlternateFunction, Mode, PinId, PortId}; use stm32f429zi::interrupt_service::Stm32f429ziDefaultPeripherals; +use stm32f429zi::{rcc, rcc::Rcc}; +use stm32f4xx::{flash, i2c, pwr, utils}; +use stm32f429zi::pwr; +use core::intrinsics::breakpoint; /// Support routines for debugging I/O. pub mod io; @@ -53,12 +58,11 @@ struct NucleoF429ZI { ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>, led: &'static capsules_core::led::LedDriver< 'static, - LedHigh<'static, stm32f429zi::gpio::Pin<'static>>, + LedLow<'static, stm32f429zi::gpio::Pin<'static>>, 3, >, button: &'static capsules_core::button::Button<'static, stm32f429zi::gpio::Pin<'static>>, adc: &'static capsules_core::adc::AdcVirtualized<'static>, - dac: &'static capsules_extra::dac::Dac<'static>, alarm: &'static capsules_core::alarm::AlarmDriver< 'static, VirtualMuxAlarm<'static, stm32f429zi::tim2::Tim2<'static>>, @@ -69,11 +73,15 @@ struct NucleoF429ZI { scheduler: &'static RoundRobinSched<'static>, systick: cortexm4::systick::SysTick, - can: &'static capsules_extra::can::CanCapsule<'static, stm32f429zi::can::Can<'static>>, - date_time: &'static capsules_extra::date_time::DateTimeCapsule< + + display: &'static capsules_extra::graphic_display::GraphicDisplay<'static>, + ipc_comm: &'static kernel::ipc::IPC<00000>, + pwm: &'static capsules_extra::pwm::Pwm<'static, 1>, + measurement: &'static capsules_extra::measurement::MeasurementCapsule< //todo implemente capsule 'static, - stm32f429zi::rtc::Rtc<'static>, + stm32f4xx::tim3::Tim2_5<'static>, //todo check >, + can: &'static capsules_extra::can::CanCapsule<'static, stm32f429zi::can::Can<'static>>, } /// Mapping of integer syscalls to objects that implement syscalls. @@ -92,9 +100,11 @@ impl SyscallDriverLookup for NucleoF429ZI { kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)), capsules_core::rng::DRIVER_NUM => f(Some(self.rng)), + capsules_extra::graphic_display::DRIVER_NUM => f(Some(self.display)), + kernel::ipc::DRIVER_NUM => f(Some(self.ipc_comm)), + capsules_extra::pwm::DRIVER_NUM => f(Some(self.pwm)), + capsules_extra::measurement::DRIVER_NUM => f(Some(self.measurement)), // impl measurement capsules_extra::can::DRIVER_NUM => f(Some(self.can)), - capsules_extra::dac::DRIVER_NUM => f(Some(self.dac)), - capsules_extra::date_time::DRIVER_NUM => f(Some(self.date_time)), _ => f(None), } } @@ -176,46 +186,48 @@ unsafe fn setup_dma( unsafe fn set_pin_primary_functions( syscfg: &stm32f429zi::syscfg::Syscfg, gpio_ports: &'static stm32f429zi::gpio::GpioPorts<'static>, + i2c1: &stm32f4xx::i2c::I2C, ) { - use kernel::hil::gpio::Configure; + use apis::gpio::Configure; syscfg.enable_clock(); gpio_ports.get_port_from_port_id(PortId::B).enable_clock(); // User LD2 is connected to PB07. Configure PB07 as `debug_gpio!(0, ...)` - gpio_ports.get_pin(PinId::PB07).map(|pin| { + if let Some(pin) = gpio_ports.get_pin(PinId::PB07) { pin.make_output(); // Configure kernel debug gpios as early as possible kernel::debug::assign_gpios(Some(pin), None, None); - }); + }; gpio_ports.get_port_from_port_id(PortId::D).enable_clock(); // pd8 and pd9 (USART3) is connected to ST-LINK virtual COM port - gpio_ports.get_pin(PinId::PD08).map(|pin| { + if let Some(pin) = gpio_ports.get_pin(PinId::PD08) { pin.set_mode(Mode::AlternateFunctionMode); // AF7 is USART2_TX pin.set_alternate_function(AlternateFunction::AF7); - }); - gpio_ports.get_pin(PinId::PD09).map(|pin| { + }; + if let Some(pin) = gpio_ports.get_pin(PinId::PD09) { pin.set_mode(Mode::AlternateFunctionMode); // AF7 is USART2_RX pin.set_alternate_function(AlternateFunction::AF7); - }); + }; gpio_ports.get_port_from_port_id(PortId::C).enable_clock(); - // button is connected on pc13 - gpio_ports.get_pin(PinId::PC13).map(|pin| { + // button is connected on pa6 + if let Some(pin) = gpio_ports.get_pin(PinId::PA06) { + pin.set_mode(Mode::Input); pin.enable_interrupt(); - }); + } // set interrupt for pin D0 - gpio_ports.get_pin(PinId::PG09).map(|pin| { + if let Some(pin) = gpio_ports.get_pin(PinId::PG09) { pin.enable_interrupt(); - }); + } // Enable clocks for GPIO Ports // Disable some of them if you don't need some of the GPIOs @@ -227,35 +239,98 @@ unsafe fn set_pin_primary_functions( gpio_ports.get_port_from_port_id(PortId::H).enable_clock(); // Arduino A0 - gpio_ports.get_pin(PinId::PA03).map(|pin| { + if let Some(pin) = gpio_ports.get_pin(PinId::PC00) { pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + } + + // // Arduino A1 + // if let Some(pin) = gpio_ports.get_pin(PinId::PC00) { + // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // } + + // // Arduino A2 + // if let Some(pin) = gpio_ports.get_pin(PinId::PC03) { + // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // } + + // // Arduino A6 + // if let Some(pin) = gpio_ports.get_pin(PinId::PB01) { + // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // } + + // // Arduino A7 + // if let Some(pin) = gpio_ports.get_pin(PinId::PC02) { + // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // } + + if let Some(pin) = gpio_ports.get_pin(PinId::PB08) { + pin.set_mode(Mode::AlternateFunctionMode); + pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); + pin.set_mode_output_opendrain(); + // AF4 is I2C + pin.set_speed(); + pin.set_alternate_function(AlternateFunction::AF4); + }; + if let Some(pin) = gpio_ports.get_pin(PinId::PB09) { + pin.make_output(); + pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); + pin.set_speed(); + pin.set_mode(Mode::AlternateFunctionMode); + pin.set_mode_output_opendrain(); + // AF4 is I2C + pin.set_alternate_function(AlternateFunction::AF4); + }; + + i2c1.enable_clock(); + i2c1.set_speed(i2c::I2CSpeed::Speed100k, 8); + + // PE11 is connected to motor driver IN2 + gpio_ports.get_pin(PinId::PE11).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + // AF1 is TIM1/2 + pin.set_alternate_function(AlternateFunction::AF1); }); - // Arduino A1 - gpio_ports.get_pin(PinId::PC00).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // PE13 is connected to motor driver IN1 + gpio_ports.get_pin(PinId::PE13).map(|pin| { + pin.set_mode(Mode::GeneralPurposeOutputMode); + // pin.set_mode(Mode::AlternateFunctionMode); + // // AF1 is TIM1/2 + // pin.set_alternate_function(AlternateFunction::AF1); }); - // Arduino A2 - gpio_ports.get_pin(PinId::PC03).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // PA7 is Encoder pulse counting + gpio_ports.get_pin(PinId::PA07).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + pin.set_floating_state(FloatingState::PullDown); + //pin.set_mode(Mode::AlternateFunctionMode); + pin.set_alternate_function(AlternateFunction::AF2); }); - // Arduino A6 - gpio_ports.get_pin(PinId::PB01).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // PA3 is Encoder pulse counting + gpio_ports.get_pin(PinId::PA03).map(|pin| { + pin.make_input(); + pin.set_floating_state(FloatingState::PullNone); }); - // Arduino A7 - gpio_ports.get_pin(PinId::PC02).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + // PA08 is Clock Output MCO1 + gpio_ports.get_pin(PinId::PA08).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + // AF0 is Clock output (MCO1) + pin.set_alternate_function(AlternateFunction::AF0); + }); + + // PC09 is ClockOutput MCO2 + gpio_ports.get_pin(PinId::PC09).map(|pin| { + pin.set_mode(Mode::AlternateFunctionMode); + pin.set_alternate_function(AlternateFunction::AF0); }); gpio_ports.get_pin(PinId::PD00).map(|pin| { pin.set_mode(Mode::AlternateFunctionMode); // AF9 is CAN_RX pin.set_alternate_function(AlternateFunction::AF9); - pin.set_floating_state(kernel::hil::gpio::FloatingState::PullDown); + pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); }); gpio_ports.get_pin(PinId::PD01).map(|pin| { pin.set_mode(Mode::AlternateFunctionMode); @@ -263,9 +338,8 @@ unsafe fn set_pin_primary_functions( pin.set_alternate_function(AlternateFunction::AF9); }); - // DAC Channel 1 - gpio_ports.get_pin(PinId::PA04).map(|pin| { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); + gpio_ports.get_pin(PinId::PE08).map(|pin| { + pin.make_output(); }); } @@ -273,8 +347,9 @@ unsafe fn set_pin_primary_functions( unsafe fn setup_peripherals( tim2: &stm32f429zi::tim2::Tim2, trng: &stm32f429zi::trng::Trng, + tim1: &stm32f4xx::tim1::Tim1_8, + tim3: &stm32f4xx::tim3::Tim2_5, can1: &'static stm32f429zi::can::Can, - rtc: &'static stm32f429zi::rtc::Rtc, ) { // USART3 IRQn is 39 cortexm4::nvic::Nvic::new(stm32f429zi::nvic::USART3).enable(); @@ -287,11 +362,14 @@ unsafe fn setup_peripherals( // RNG trng.enable_clock(); + tim1.enable_clock(); + tim1.start(); + // tim1.start_pwm(&stm32f4xx::tim1::TimOutputs::OutputCh2, 2000, 800); + tim3.enable_clock(); + tim3.start(); + // CAN can1.enable_clock(); - - // RTC - rtc.enable_clock(); } /// Statically initialize the core peripherals for the chip. @@ -300,14 +378,14 @@ unsafe fn setup_peripherals( /// removed when this function returns. Otherwise, the stack space used for /// these static_inits is wasted. #[inline(never)] -unsafe fn create_peripherals() -> ( +unsafe fn get_peripherals() -> ( &'static mut Stm32f429ziDefaultPeripherals<'static>, &'static stm32f429zi::syscfg::Syscfg<'static>, &'static stm32f429zi::dma::Dma1<'static>, + &'static stm32f429zi::rcc::Rcc, ) { // We use the default HSI 16Mhz clock let rcc = static_init!(stm32f429zi::rcc::Rcc, stm32f429zi::rcc::Rcc::new()); - let syscfg = static_init!( stm32f429zi::syscfg::Syscfg, stm32f429zi::syscfg::Syscfg::new(rcc) @@ -323,28 +401,97 @@ unsafe fn create_peripherals() -> ( Stm32f429ziDefaultPeripherals, Stm32f429ziDefaultPeripherals::new(rcc, exti, dma1, dma2) ); - (peripherals, syscfg, dma1) + (peripherals, syscfg, dma1, rcc) +} + +/// Initialize clock tree and related peripherals (flash, pwr) +/// +/// In order to start the PLL, the pwr scaling needs to be configured. In order to increase the system clock to 180MHz, the flash latency needs to be increased and pwr overdrive needs to be enabled. +/// see: RM0090 ch. 5.1.4 pg 123 +unsafe fn try_init_clocks(rcc: &Rcc) -> Result<(), ()> { + // only PWR peripheral should be enabled, HSI -> SystemClock + rcc::enable_boot_esential_clocks()?; + pwr::configure_voltage_scaling(1)?; + + // uncomment these lines in order to measure internal clocks + rcc.configure_prescaler(&rcc::RccClockDestination::MClockOutput1, 5); + rcc.configure_prescaler(&rcc::RccClockDestination::MClockOutput2, 5); + + // HSI -> PLL, wait for HSI to be stable + utils::wait_for_condition( + 1_000, + || rcc.is_clock_stable(&rcc::RccClockSource::HsiRc), + || (), + )?; + + // HSI = 16MHz + // PLL output = (16/8)*180/2 = 180 MHz + rcc.configure_pll(8, 180, 2); + rcc.enable(rcc::RccClockSource::Pll); + + pwr::enable_overdrive()?; + flash::set_latency(5); + + let _ = utils::wait_for_condition( + 1_000, + || rcc.is_clock_stable(&rcc::RccClockSource::Pll), + || (), + ); + rcc.configure_prescaler(&rcc::RccClockDestination::Apb1, 4); + rcc.configure_prescaler(&rcc::RccClockDestination::Apb2, 4); + rcc.route( + &rcc::RccClockSource::Pll, + &rcc::RccClockDestination::SystemClock, + )?; + + Ok(()) +} + +/// Initialize clock tree, if it fails it reverts to default configuration (HSI-> SystemClcok) +pub unsafe fn init_clocks(rcc: &Rcc) { + match try_init_clocks(&rcc) { + Ok(_) => {} + Err(_) => { + let _ = rcc.route( + &rcc::RccClockSource::HsiRc, + &rcc::RccClockDestination::SystemClock, + ); + } + } + if rcc.compute_nominal_frequency().is_err() { + breakpoint(); + } } /// Main function. /// +/// # Safety +/// This function needs to be marked unsafe allows ... +/// /// This is called after RAM initialization is complete. #[no_mangle] pub unsafe fn main() { stm32f429zi::init(); - let (peripherals, syscfg, dma1) = create_peripherals(); + let (peripherals, syscfg, dma1, rcc) = get_peripherals(); peripherals.init(); + + init_clocks(rcc); let base_peripherals = &peripherals.stm32f4; setup_peripherals( &base_peripherals.tim2, &peripherals.trng, + &base_peripherals.tim1, + &base_peripherals.tim3, &peripherals.can1, - &peripherals.rtc, ); - set_pin_primary_functions(syscfg, &base_peripherals.gpio_ports); + set_pin_primary_functions( + syscfg, + &base_peripherals.gpio_ports, + &peripherals.stm32f4.i2c1, + ); setup_dma( dma1, @@ -354,6 +501,14 @@ pub unsafe fn main() { let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); + let dynamic_deferred_call_clients = + static_init!([DynamicDeferredCallClientState; 3], Default::default()); + let dynamic_deferred_caller = static_init!( + DynamicDeferredCall, + DynamicDeferredCall::new(dynamic_deferred_call_clients) + ); + DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); + let chip = static_init!( stm32f429zi::chip::Stm32f4xx, stm32f429zi::chip::Stm32f4xx::new(peripherals) @@ -364,8 +519,12 @@ pub unsafe fn main() { // Create a shared UART channel for kernel debug. base_peripherals.usart3.enable_clock(); - let uart_mux = components::console::UartMuxComponent::new(&base_peripherals.usart3, 115200) - .finalize(components::uart_mux_component_static!()); + let uart_mux = components::console::UartMuxComponent::new( + &base_peripherals.usart3, + 115200, + dynamic_deferred_caller, + ) + .finalize(components::uart_mux_component_static!()); io::WRITER.set_initialized(); @@ -379,7 +538,7 @@ pub unsafe fn main() { // Setup the console. let console = components::console::ConsoleComponent::new( board_kernel, - capsules_core::console::DRIVER_NUM, + capsules::console::DRIVER_NUM, uart_mux, ) .finalize(components::console_component_static!()); @@ -393,22 +552,26 @@ pub unsafe fn main() { let gpio_ports = &base_peripherals.gpio_ports; let led = components::led::LedsComponent::new().finalize(components::led_component_static!( - LedHigh<'static, stm32f429zi::gpio::Pin>, - LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB00).unwrap()), - LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB07).unwrap()), - LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB14).unwrap()), + LedLow<'static, stm32f429zi::gpio::Pin>, + LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PD15).unwrap()), + LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PD14).unwrap()), + LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PA05).unwrap()), )); + // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB00).unwrap()), + // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB07).unwrap()), + // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB14).unwrap()), + // BUTTONs let button = components::button::ButtonComponent::new( board_kernel, - capsules_core::button::DRIVER_NUM, + capsules::button::DRIVER_NUM, components::button_component_helper!( stm32f429zi::gpio::Pin, ( - gpio_ports.get_pin(stm32f429zi::gpio::PinId::PC13).unwrap(), - kernel::hil::gpio::ActivationMode::ActiveHigh, - kernel::hil::gpio::FloatingState::PullNone + gpio_ports.get_pin(stm32f429zi::gpio::PinId::PA06).unwrap(), + apis::gpio::ActivationMode::ActiveHigh, + apis::gpio::FloatingState::PullDown ) ), ) @@ -423,7 +586,7 @@ pub unsafe fn main() { let alarm = components::alarm::AlarmDriverComponent::new( board_kernel, - capsules_core::alarm::DRIVER_NUM, + capsules::alarm::DRIVER_NUM, mux_alarm, ) .finalize(components::alarm_component_static!(stm32f429zi::tim2::Tim2)); @@ -431,7 +594,7 @@ pub unsafe fn main() { // GPIO let gpio = GpioComponent::new( board_kernel, - capsules_core::gpio::DRIVER_NUM, + capsules::gpio::DRIVER_NUM, components::gpio_component_helper!( stm32f429zi::gpio::Pin, // Arduino like RX/TX @@ -440,16 +603,16 @@ pub unsafe fn main() { 2 => gpio_ports.pins[5][15].as_ref().unwrap(), //D2 3 => gpio_ports.pins[4][13].as_ref().unwrap(), //D3 4 => gpio_ports.pins[5][14].as_ref().unwrap(), //D4 - 5 => gpio_ports.pins[4][11].as_ref().unwrap(), //D5 - 6 => gpio_ports.pins[4][9].as_ref().unwrap(), //D6 + // 5 => gpio_ports.pins[4][11].as_ref().unwrap(), //D5 + // 6 => gpio_ports.pins[4][9].as_ref().unwrap(), //D6 7 => gpio_ports.pins[5][13].as_ref().unwrap(), //D7 8 => gpio_ports.pins[5][12].as_ref().unwrap(), //D8 - 9 => gpio_ports.pins[3][15].as_ref().unwrap(), //D9 + // 9 => gpio_ports.pins[3][15].as_ref().unwrap(), //D9 // SPI Pins - 10 => gpio_ports.pins[3][14].as_ref().unwrap(), //D10 - 11 => gpio_ports.pins[0][7].as_ref().unwrap(), //D11 - 12 => gpio_ports.pins[0][6].as_ref().unwrap(), //D12 - 13 => gpio_ports.pins[0][5].as_ref().unwrap(), //D13 + // 10 => gpio_ports.pins[3][14].as_ref().unwrap(), //D10 + // 11 => gpio_ports.pins[0][7].as_ref().unwrap(), //D11 + // 12 => gpio_ports.pins[0][6].as_ref().unwrap(), //D12 + // 13 => gpio_ports.pins[0][5].as_ref().unwrap(), //D13 // I2C Pins 14 => gpio_ports.pins[1][9].as_ref().unwrap(), //D14 15 => gpio_ports.pins[1][8].as_ref().unwrap(), //D15 @@ -508,8 +671,8 @@ pub unsafe fn main() { 63 => gpio_ports.pins[5][9].as_ref().unwrap(), //D63 64 => gpio_ports.pins[6][1].as_ref().unwrap(), //D64 65 => gpio_ports.pins[6][0].as_ref().unwrap(), //D65 - 66 => gpio_ports.pins[3][1].as_ref().unwrap(), //D66 - 67 => gpio_ports.pins[3][0].as_ref().unwrap(), //D67 + // 66 => gpio_ports.pins[3][1].as_ref().unwrap(), //D66 + // 67 => gpio_ports.pins[3][0].as_ref().unwrap(), //D67 68 => gpio_ports.pins[5][0].as_ref().unwrap(), //D68 69 => gpio_ports.pins[5][1].as_ref().unwrap(), //D69 70 => gpio_ports.pins[5][2].as_ref().unwrap(), //D70 @@ -520,7 +683,7 @@ pub unsafe fn main() { // 72 => gpio_ports.pins[0][3].as_ref().unwrap(), //A0 // 73 => gpio_ports.pins[2][0].as_ref().unwrap(), //A1 // 74 => gpio_ports.pins[2][3].as_ref().unwrap(), //A2 - 75 => gpio_ports.pins[5][3].as_ref().unwrap(), //A3 + // 75 => gpio_ports.pins[5][3].as_ref().unwrap(), //A3 76 => gpio_ports.pins[5][5].as_ref().unwrap(), //A4 77 => gpio_ports.pins[5][10].as_ref().unwrap(), //A5 // 78 => gpio_ports.pins[1][1].as_ref().unwrap(), //A6 @@ -554,43 +717,19 @@ pub unsafe fn main() { kernel::hil::sensors::TemperatureDriver::set_client(temp_sensor, temp); let adc_channel_0 = - components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel3) - .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - - let adc_channel_1 = components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel10) .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - let adc_channel_2 = - components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel13) - .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - - let adc_channel_3 = - components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel9) - .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - - let adc_channel_4 = - components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel12) - .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - let adc_syscall = components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM) .finalize(components::adc_syscall_component_helper!( adc_channel_0, - adc_channel_1, - adc_channel_2, - adc_channel_3, - adc_channel_4, )); let process_printer = components::process_printer::ProcessPrinterTextComponent::new() .finalize(components::process_printer_text_component_static!()); PROCESS_PRINTER = Some(process_printer); - // DAC - let dac = components::dac::DacComponent::new(&base_peripherals.dac) - .finalize(components::dac_component_static!()); - // RNG let rng = components::rng::RngComponent::new( board_kernel, @@ -599,8 +738,24 @@ pub unsafe fn main() { ) .finalize(components::rng_component_static!()); - // CAN - let can = components::can::CanComponent::new( + // PROCESS CONSOLE + let process_console = components::process_console::ProcessConsoleComponent::new( + board_kernel, + uart_mux, + mux_alarm, + process_printer, + None, + ) + .finalize(components::process_console_component_static!( + stm32f429zi::tim2::Tim2 + )); + let _ = process_console.start(); + + let ipc_comm = + driver_setup::ipc::IPCComponent::new(board_kernel, drivers::communication::DRIVER_NUM) + .finalize(driver_setup::ipc_component_static!()); + + let can = driver_setup::can::CanComponent::new( board_kernel, capsules_extra::can::DRIVER_NUM, &peripherals.can1, @@ -609,64 +764,87 @@ pub unsafe fn main() { stm32f429zi::can::Can<'static> )); - // RTC DATE TIME - match peripherals.rtc.rtc_init() { - Err(e) => debug!("{:?}", e), - _ => (), - }; + // I2C SSD1306 screen + let i2c_mux = static_init!( + MuxI2C<'static>, + MuxI2C::new(&peripherals.stm32f4.i2c1, None, dynamic_deferred_caller) + ); + peripherals.stm32f4.i2c1.set_master_client(i2c_mux); - let date_time = components::date_time::DateTimeComponent::new( - board_kernel, - capsules_extra::date_time::DRIVER_NUM, - &peripherals.rtc, + let bus = components::bus::I2CMasterBusComponent::new( + i2c_mux, + capsules_extra::ssd1306::SLAVE_ADDRESS_WRITE, ) - .finalize(components::date_time_component_static!( - stm32f429zi::rtc::Rtc<'static> - )); + .finalize(components::i2c_master_bus_component_static!(2)); - // PROCESS CONSOLE - let process_console = components::process_console::ProcessConsoleComponent::new( + let ssd1306_screen = components::ssd1306::SSD1306Component::new(bus, dynamic_deferred_caller) + .finalize(components::ssd1306_component_static!( + capsules_extra::bus::I2CMasterBus<'static, capsules_core::virtualizers::virtual_i2c::I2CDevice<'static>>, + )); + + let _ = ssd1306_screen.init(); + + let display = components::graphic_display::GraphicDisplayComponent::new( board_kernel, - uart_mux, - mux_alarm, - process_printer, - Some(cortexm4::support::reset), + capsules_extra::graphic_display::DRIVER_NUM, + ssd1306_screen, + Some(ssd1306_screen), ) - .finalize(components::process_console_component_static!( - stm32f429zi::tim2::Tim2 - )); - let _ = process_console.start(); + .finalize(components::graphic_display_component_static!(1025)); + + let mux_pwm = components::pwm::PwmMuxComponent::new(&base_peripherals.tim1).finalize( + components::pwm_mux_component_static!(stm32f4xx::tim1::Tim1_8), + ); + + let pwm = components::pwm::PwmVirtualComponent::new(board_kernel, capsules_extra::pwm::DRIVER_NUM) + .finalize(components::pwm_syscall_component_helper!( + components::pwm::PwmPinComponent::new( + &mux_pwm, + stm32f4xx::tim1::TimOutputs::OutputCh2, + //gpio_ports.get_pin(stm32f429zi: gpio::PinId::PE11).unwrap() + ) + .finalize(components::pwm_pin_user_component_static!( + stm32f4xx::tim1::Tim1_8 + )) + )); + + let measurement = components::measurement::MeasurementComponent::new(&base_peripherals.tim3) + .finalize(components::measurement_component_static!(stm32f4xx::tim3::Tim2_5)); let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) .finalize(components::round_robin_component_static!(NUM_PROCS)); let nucleo_f429zi = NucleoF429ZI { - console: console, + console, ipc: kernel::ipc::IPC::new( board_kernel, kernel::ipc::DRIVER_NUM, &memory_allocation_capability, ), adc: adc_syscall, - dac: dac, - led: led, + led, temperature: temp, - button: button, - alarm: alarm, - gpio: gpio, - rng: rng, + button, + alarm, + gpio, + rng, scheduler, - systick: cortexm4::systick::SysTick::new(), - can: can, - date_time, + systick: cortexm4::systick::SysTick::new_with_calibration( + rcc.get_nominal_frequency_(&rcc::PeripheralClockType::AHB1(rcc::HCLK1::SysTick)), + ), + + display, + ipc_comm, + pwm, + measurement, + can, }; // // Optional kernel tests // // // // See comment in `boards/imix/src/main.rs` // virtual_uart_rx_test::run_virtual_uart_receive(mux_uart); - debug!("Initialization complete. Entering main loop"); // These symbols are defined in the linker script. From a1e212e5fe2a68460381161c0e86f6b5ee9cbc3a Mon Sep 17 00:00:00 2001 From: Lazar Cristian-Stefan Date: Fri, 19 Jan 2024 18:16:27 +0200 Subject: [PATCH 5/9] Deleted old tock hierarchy main.rs --- boards/nucleo_f429zi/src/main_old.rs | 893 --------------------------- 1 file changed, 893 deletions(-) delete mode 100644 boards/nucleo_f429zi/src/main_old.rs diff --git a/boards/nucleo_f429zi/src/main_old.rs b/boards/nucleo_f429zi/src/main_old.rs deleted file mode 100644 index e748aa22d1..0000000000 --- a/boards/nucleo_f429zi/src/main_old.rs +++ /dev/null @@ -1,893 +0,0 @@ -//! Board file for Nucleo-F429ZI development board -//! -//! - - -#![no_std] -// Disable this attribute when documenting, as a workaround for -// https://github.com/rust-lang/rust/issues/62184. -#![cfg_attr(not(doc), no_main)] -#![deny(missing_docs)] -#![feature(core_intrinsics)] - -use kernel::hil::gpio::FloatingState; -use kernel::hil::led::LedLow; -use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; -use components::gpio::GpioComponent; -use kernel::capabilities; -use kernel::component::Component; -use kernel::deferred_call::{DeferredCall, DeferredCallClient}; -use kernel::platform::{KernelResources, SyscallDriverLookup}; -use kernel::scheduler::round_robin::RoundRobinSched; -use kernel::{create_capability, debug, static_init}; - -use capsules_core::virtualizers::virtual_i2c::MuxI2C; -use kernel::hil::i2c::I2CMaster; -use stm32f429zi::gpio::{AlternateFunction, Mode, PinId, PortId}; -use stm32f429zi::interrupt_service::Stm32f429ziDefaultPeripherals; -use stm32f429zi::{rcc, rcc::Rcc}; -use stm32f4xx::{flash, i2c, pwr, utils}; -use stm32f429zi::pwr; - -use core::intrinsics::breakpoint; -/// Support routines for debugging I/O. -pub mod io; - -// Number of concurrent processes this platform supports. -const NUM_PROCS: usize = 4; - -// Actual memory for holding the active process structures. -static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] = - [None, None, None, None]; - -static mut CHIP: Option<&'static stm32f429zi::chip::Stm32f4xx> = - None; -static mut PROCESS_PRINTER: Option<&'static kernel::process::ProcessPrinterText> = None; - -// How should the kernel respond when a process faults. -const FAULT_RESPONSE: kernel::process::PanicFaultPolicy = kernel::process::PanicFaultPolicy {}; - -/// Dummy buffer that causes the linker to reserve enough space for the stack. -#[no_mangle] -#[link_section = ".stack_buffer"] -pub static mut STACK_MEMORY: [u8; 0x2000] = [0; 0x2000]; - -/// A structure representing this platform that holds references to all -/// capsules for this platform. -struct NucleoF429ZI { - console: &'static capsules_core::console::Console<'static>, - ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>, - led: &'static capsules_core::led::LedDriver< - 'static, - LedLow<'static, stm32f429zi::gpio::Pin<'static>>, - 3, - >, - button: &'static capsules_core::button::Button<'static, stm32f429zi::gpio::Pin<'static>>, - adc: &'static capsules_core::adc::AdcVirtualized<'static>, - alarm: &'static capsules_core::alarm::AlarmDriver< - 'static, - VirtualMuxAlarm<'static, stm32f429zi::tim2::Tim2<'static>>, - >, - temperature: &'static capsules_extra::temperature::TemperatureSensor<'static>, - gpio: &'static capsules_core::gpio::GPIO<'static, stm32f429zi::gpio::Pin<'static>>, - rng: &'static capsules_core::rng::RngDriver<'static>, - - scheduler: &'static RoundRobinSched<'static>, - systick: cortexm4::systick::SysTick, - - display: &'static capsules_extra::graphic_display::GraphicDisplay<'static>, - ipc_comm: &'static kernel::ipc::IPC<00000>, - pwm: &'static capsules_extra::pwm::Pwm<'static, 1>, - measurement: &'static capsules_extra::measurement::MeasurementCapsule< //todo implemente capsule - 'static, - stm32f4xx::tim3::Tim2_5<'static>, //todo check - >, - can: &'static capsules_extra::can::CanCapsule<'static, stm32f429zi::can::Can<'static>>, -} - -/// Mapping of integer syscalls to objects that implement syscalls. -impl SyscallDriverLookup for NucleoF429ZI { - fn with_driver(&self, driver_num: usize, f: F) -> R - where - F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R, - { - match driver_num { - capsules_core::console::DRIVER_NUM => f(Some(self.console)), - capsules_core::led::DRIVER_NUM => f(Some(self.led)), - capsules_core::button::DRIVER_NUM => f(Some(self.button)), - capsules_core::adc::DRIVER_NUM => f(Some(self.adc)), - capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)), - capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)), - kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), - capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)), - capsules_core::rng::DRIVER_NUM => f(Some(self.rng)), - capsules_extra::graphic_display::DRIVER_NUM => f(Some(self.display)), - kernel::ipc::DRIVER_NUM => f(Some(self.ipc_comm)), - capsules_extra::pwm::DRIVER_NUM => f(Some(self.pwm)), - capsules_extra::measurement::DRIVER_NUM => f(Some(self.measurement)), // impl measurement - capsules_extra::can::DRIVER_NUM => f(Some(self.can)), - _ => f(None), - } - } -} - -impl - KernelResources< - stm32f429zi::chip::Stm32f4xx< - 'static, - stm32f429zi::interrupt_service::Stm32f429ziDefaultPeripherals<'static>, - >, - > for NucleoF429ZI -{ - type SyscallDriverLookup = Self; - type SyscallFilter = (); - type ProcessFault = (); - type CredentialsCheckingPolicy = (); - type Scheduler = RoundRobinSched<'static>; - type SchedulerTimer = cortexm4::systick::SysTick; - type WatchDog = (); - type ContextSwitchCallback = (); - - fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup { - self - } - fn syscall_filter(&self) -> &Self::SyscallFilter { - &() - } - fn process_fault(&self) -> &Self::ProcessFault { - &() - } - fn credentials_checking_policy(&self) -> &'static Self::CredentialsCheckingPolicy { - &() - } - fn scheduler(&self) -> &Self::Scheduler { - self.scheduler - } - fn scheduler_timer(&self) -> &Self::SchedulerTimer { - &self.systick - } - fn watchdog(&self) -> &Self::WatchDog { - &() - } - fn context_switch_callback(&self) -> &Self::ContextSwitchCallback { - &() - } -} - -/// Helper function called during bring-up that configures DMA. -unsafe fn setup_dma( - dma: &stm32f429zi::dma::Dma1, - dma_streams: &'static [stm32f429zi::dma::Stream; 8], - usart3: &'static stm32f429zi::usart::Usart, -) { - use stm32f429zi::dma::Dma1Peripheral; - use stm32f429zi::usart; - - dma.enable_clock(); - - let usart3_tx_stream = &dma_streams[Dma1Peripheral::USART3_TX.get_stream_idx()]; - let usart3_rx_stream = &dma_streams[Dma1Peripheral::USART3_RX.get_stream_idx()]; - - usart3.set_dma( - usart::TxDMA(usart3_tx_stream), - usart::RxDMA(usart3_rx_stream), - ); - - usart3_tx_stream.set_client(usart3); - usart3_rx_stream.set_client(usart3); - - usart3_tx_stream.setup(Dma1Peripheral::USART3_TX); - usart3_rx_stream.setup(Dma1Peripheral::USART3_RX); - - cortexm4::nvic::Nvic::new(Dma1Peripheral::USART3_TX.get_stream_irqn()).enable(); - cortexm4::nvic::Nvic::new(Dma1Peripheral::USART3_RX.get_stream_irqn()).enable(); -} - -/// Helper function called during bring-up that configures multiplexed I/O. -unsafe fn set_pin_primary_functions( - syscfg: &stm32f429zi::syscfg::Syscfg, - gpio_ports: &'static stm32f429zi::gpio::GpioPorts<'static>, - i2c1: &stm32f4xx::i2c::I2C, -) { - use apis::gpio::Configure; - - syscfg.enable_clock(); - - gpio_ports.get_port_from_port_id(PortId::B).enable_clock(); - - // User LD2 is connected to PB07. Configure PB07 as `debug_gpio!(0, ...)` - if let Some(pin) = gpio_ports.get_pin(PinId::PB07) { - pin.make_output(); - - // Configure kernel debug gpios as early as possible - kernel::debug::assign_gpios(Some(pin), None, None); - }; - - gpio_ports.get_port_from_port_id(PortId::D).enable_clock(); - - // pd8 and pd9 (USART3) is connected to ST-LINK virtual COM port - if let Some(pin) = gpio_ports.get_pin(PinId::PD08) { - pin.set_mode(Mode::AlternateFunctionMode); - // AF7 is USART2_TX - pin.set_alternate_function(AlternateFunction::AF7); - }; - if let Some(pin) = gpio_ports.get_pin(PinId::PD09) { - pin.set_mode(Mode::AlternateFunctionMode); - // AF7 is USART2_RX - pin.set_alternate_function(AlternateFunction::AF7); - }; - - gpio_ports.get_port_from_port_id(PortId::C).enable_clock(); - - // button is connected on pa6 - if let Some(pin) = gpio_ports.get_pin(PinId::PA06) { - pin.set_mode(Mode::Input); - pin.enable_interrupt(); - } - - // set interrupt for pin D0 - if let Some(pin) = gpio_ports.get_pin(PinId::PG09) { - pin.enable_interrupt(); - } - - // Enable clocks for GPIO Ports - // Disable some of them if you don't need some of the GPIOs - gpio_ports.get_port_from_port_id(PortId::A).enable_clock(); - // Ports B, C and D are already enabled - gpio_ports.get_port_from_port_id(PortId::E).enable_clock(); - gpio_ports.get_port_from_port_id(PortId::F).enable_clock(); - gpio_ports.get_port_from_port_id(PortId::G).enable_clock(); - gpio_ports.get_port_from_port_id(PortId::H).enable_clock(); - - // Arduino A0 - if let Some(pin) = gpio_ports.get_pin(PinId::PC00) { - pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - } - - // // Arduino A1 - // if let Some(pin) = gpio_ports.get_pin(PinId::PC00) { - // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - // } - - // // Arduino A2 - // if let Some(pin) = gpio_ports.get_pin(PinId::PC03) { - // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - // } - - // // Arduino A6 - // if let Some(pin) = gpio_ports.get_pin(PinId::PB01) { - // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - // } - - // // Arduino A7 - // if let Some(pin) = gpio_ports.get_pin(PinId::PC02) { - // pin.set_mode(stm32f429zi::gpio::Mode::AnalogMode); - // } - - if let Some(pin) = gpio_ports.get_pin(PinId::PB08) { - pin.set_mode(Mode::AlternateFunctionMode); - pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); - pin.set_mode_output_opendrain(); - // AF4 is I2C - pin.set_speed(); - pin.set_alternate_function(AlternateFunction::AF4); - }; - if let Some(pin) = gpio_ports.get_pin(PinId::PB09) { - pin.make_output(); - pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); - pin.set_speed(); - pin.set_mode(Mode::AlternateFunctionMode); - pin.set_mode_output_opendrain(); - // AF4 is I2C - pin.set_alternate_function(AlternateFunction::AF4); - }; - - i2c1.enable_clock(); - i2c1.set_speed(i2c::I2CSpeed::Speed100k, 8); - - // PE11 is connected to motor driver IN2 - gpio_ports.get_pin(PinId::PE11).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - // AF1 is TIM1/2 - pin.set_alternate_function(AlternateFunction::AF1); - }); - - // PE13 is connected to motor driver IN1 - gpio_ports.get_pin(PinId::PE13).map(|pin| { - pin.set_mode(Mode::GeneralPurposeOutputMode); - // pin.set_mode(Mode::AlternateFunctionMode); - // // AF1 is TIM1/2 - // pin.set_alternate_function(AlternateFunction::AF1); - }); - - // PA7 is Encoder pulse counting - gpio_ports.get_pin(PinId::PA07).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - pin.set_floating_state(FloatingState::PullDown); - //pin.set_mode(Mode::AlternateFunctionMode); - pin.set_alternate_function(AlternateFunction::AF2); - }); - - // PA3 is Encoder pulse counting - gpio_ports.get_pin(PinId::PA03).map(|pin| { - pin.make_input(); - pin.set_floating_state(FloatingState::PullNone); - }); - - // PA08 is Clock Output MCO1 - gpio_ports.get_pin(PinId::PA08).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - // AF0 is Clock output (MCO1) - pin.set_alternate_function(AlternateFunction::AF0); - }); - - // PC09 is ClockOutput MCO2 - gpio_ports.get_pin(PinId::PC09).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - pin.set_alternate_function(AlternateFunction::AF0); - }); - - gpio_ports.get_pin(PinId::PD00).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - // AF9 is CAN_RX - pin.set_alternate_function(AlternateFunction::AF9); - pin.set_floating_state(kernel::hil::gpio::FloatingState::PullNone); - }); - gpio_ports.get_pin(PinId::PD01).map(|pin| { - pin.set_mode(Mode::AlternateFunctionMode); - // AF9 is CAN_TX - pin.set_alternate_function(AlternateFunction::AF9); - }); - - gpio_ports.get_pin(PinId::PE08).map(|pin| { - pin.make_output(); - }); -} - -/// Helper function for miscellaneous peripheral functions -unsafe fn setup_peripherals( - tim2: &stm32f429zi::tim2::Tim2, - trng: &stm32f429zi::trng::Trng, - tim1: &stm32f4xx::tim1::Tim1_8, - tim3: &stm32f4xx::tim3::Tim2_5, - can1: &'static stm32f429zi::can::Can, -) { - // USART3 IRQn is 39 - cortexm4::nvic::Nvic::new(stm32f429zi::nvic::USART3).enable(); - - // TIM2 IRQn is 28 - tim2.enable_clock(); - tim2.start(); - cortexm4::nvic::Nvic::new(stm32f429zi::nvic::TIM2).enable(); - - // RNG - trng.enable_clock(); - - tim1.enable_clock(); - tim1.start(); - // tim1.start_pwm(&stm32f4xx::tim1::TimOutputs::OutputCh2, 2000, 800); - tim3.enable_clock(); - tim3.start(); - - // CAN - can1.enable_clock(); -} - -/// Statically initialize the core peripherals for the chip. -/// -/// This is in a separate, inline(never) function so that its stack frame is -/// removed when this function returns. Otherwise, the stack space used for -/// these static_inits is wasted. -#[inline(never)] -unsafe fn get_peripherals() -> ( - &'static mut Stm32f429ziDefaultPeripherals<'static>, - &'static stm32f429zi::syscfg::Syscfg<'static>, - &'static stm32f429zi::dma::Dma1<'static>, - &'static stm32f429zi::rcc::Rcc, -) { - // We use the default HSI 16Mhz clock - let rcc = static_init!(stm32f429zi::rcc::Rcc, stm32f429zi::rcc::Rcc::new()); - let syscfg = static_init!( - stm32f429zi::syscfg::Syscfg, - stm32f429zi::syscfg::Syscfg::new(rcc) - ); - let exti = static_init!( - stm32f429zi::exti::Exti, - stm32f429zi::exti::Exti::new(syscfg) - ); - let dma1 = static_init!(stm32f429zi::dma::Dma1, stm32f429zi::dma::Dma1::new(rcc)); - let dma2 = static_init!(stm32f429zi::dma::Dma2, stm32f429zi::dma::Dma2::new(rcc)); - - let peripherals = static_init!( - Stm32f429ziDefaultPeripherals, - Stm32f429ziDefaultPeripherals::new(rcc, exti, dma1, dma2) - ); - (peripherals, syscfg, dma1, rcc) -} - -/// Initialize clock tree and related peripherals (flash, pwr) -/// -/// In order to start the PLL, the pwr scaling needs to be configured. In order to increase the system clock to 180MHz, the flash latency needs to be increased and pwr overdrive needs to be enabled. -/// see: RM0090 ch. 5.1.4 pg 123 -unsafe fn try_init_clocks(rcc: &Rcc) -> Result<(), ()> { - // only PWR peripheral should be enabled, HSI -> SystemClock - rcc::enable_boot_esential_clocks()?; - pwr::configure_voltage_scaling(1)?; - - // uncomment these lines in order to measure internal clocks - rcc.configure_prescaler(&rcc::RccClockDestination::MClockOutput1, 5); - rcc.configure_prescaler(&rcc::RccClockDestination::MClockOutput2, 5); - - // HSI -> PLL, wait for HSI to be stable - utils::wait_for_condition( - 1_000, - || rcc.is_clock_stable(&rcc::RccClockSource::HsiRc), - || (), - )?; - - // HSI = 16MHz - // PLL output = (16/8)*180/2 = 180 MHz - rcc.configure_pll(8, 180, 2); - rcc.enable(rcc::RccClockSource::Pll); - - pwr::enable_overdrive()?; - flash::set_latency(5); - - let _ = utils::wait_for_condition( - 1_000, - || rcc.is_clock_stable(&rcc::RccClockSource::Pll), - || (), - ); - rcc.configure_prescaler(&rcc::RccClockDestination::Apb1, 4); - rcc.configure_prescaler(&rcc::RccClockDestination::Apb2, 4); - rcc.route( - &rcc::RccClockSource::Pll, - &rcc::RccClockDestination::SystemClock, - )?; - - Ok(()) -} - -/// Initialize clock tree, if it fails it reverts to default configuration (HSI-> SystemClcok) -pub unsafe fn init_clocks(rcc: &Rcc) { - match try_init_clocks(&rcc) { - Ok(_) => {} - Err(_) => { - let _ = rcc.route( - &rcc::RccClockSource::HsiRc, - &rcc::RccClockDestination::SystemClock, - ); - } - } - if rcc.compute_nominal_frequency().is_err() { - breakpoint(); - } -} - -/// Main function. -/// -/// # Safety -/// This function needs to be marked unsafe allows ... -/// -/// This is called after RAM initialization is complete. -#[no_mangle] -pub unsafe fn main() { - stm32f429zi::init(); - - let (peripherals, syscfg, dma1, rcc) = get_peripherals(); - peripherals.init(); - - init_clocks(rcc); - let base_peripherals = &peripherals.stm32f4; - - setup_peripherals( - &base_peripherals.tim2, - &peripherals.trng, - &base_peripherals.tim1, - &base_peripherals.tim3, - &peripherals.can1, - ); - - set_pin_primary_functions( - syscfg, - &base_peripherals.gpio_ports, - &peripherals.stm32f4.i2c1, - ); - - setup_dma( - dma1, - &base_peripherals.dma1_streams, - &base_peripherals.usart3, - ); - - let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); - - let dynamic_deferred_call_clients = - static_init!([DynamicDeferredCallClientState; 3], Default::default()); - let dynamic_deferred_caller = static_init!( - DynamicDeferredCall, - DynamicDeferredCall::new(dynamic_deferred_call_clients) - ); - DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); - - let chip = static_init!( - stm32f429zi::chip::Stm32f4xx, - stm32f429zi::chip::Stm32f4xx::new(peripherals) - ); - CHIP = Some(chip); - - // UART - - // Create a shared UART channel for kernel debug. - base_peripherals.usart3.enable_clock(); - let uart_mux = components::console::UartMuxComponent::new( - &base_peripherals.usart3, - 115200, - dynamic_deferred_caller, - ) - .finalize(components::uart_mux_component_static!()); - - io::WRITER.set_initialized(); - - // Create capabilities that the board needs to call certain protected kernel - // functions. - let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability); - let main_loop_capability = create_capability!(capabilities::MainLoopCapability); - let process_management_capability = - create_capability!(capabilities::ProcessManagementCapability); - - // Setup the console. - let console = components::console::ConsoleComponent::new( - board_kernel, - capsules::console::DRIVER_NUM, - uart_mux, - ) - .finalize(components::console_component_static!()); - // Create the debugger object that handles calls to `debug!()`. - components::debug_writer::DebugWriterComponent::new(uart_mux) - .finalize(components::debug_writer_component_static!()); - - // LEDs - - // Clock to Port A is enabled in `set_pin_primary_functions()` - let gpio_ports = &base_peripherals.gpio_ports; - - let led = components::led::LedsComponent::new().finalize(components::led_component_static!( - LedLow<'static, stm32f429zi::gpio::Pin>, - LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PD15).unwrap()), - LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PD14).unwrap()), - LedLow::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PA05).unwrap()), - )); - - // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB00).unwrap()), - // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB07).unwrap()), - // LedHigh::new(gpio_ports.get_pin(stm32f429zi::gpio::PinId::PB14).unwrap()), - - // BUTTONs - let button = components::button::ButtonComponent::new( - board_kernel, - capsules::button::DRIVER_NUM, - components::button_component_helper!( - stm32f429zi::gpio::Pin, - ( - gpio_ports.get_pin(stm32f429zi::gpio::PinId::PA06).unwrap(), - apis::gpio::ActivationMode::ActiveHigh, - apis::gpio::FloatingState::PullDown - ) - ), - ) - .finalize(components::button_component_static!(stm32f429zi::gpio::Pin)); - - // ALARM - - let tim2 = &base_peripherals.tim2; - let mux_alarm = components::alarm::AlarmMuxComponent::new(tim2).finalize( - components::alarm_mux_component_static!(stm32f429zi::tim2::Tim2), - ); - - let alarm = components::alarm::AlarmDriverComponent::new( - board_kernel, - capsules::alarm::DRIVER_NUM, - mux_alarm, - ) - .finalize(components::alarm_component_static!(stm32f429zi::tim2::Tim2)); - - // GPIO - let gpio = GpioComponent::new( - board_kernel, - capsules::gpio::DRIVER_NUM, - components::gpio_component_helper!( - stm32f429zi::gpio::Pin, - // Arduino like RX/TX - 0 => gpio_ports.get_pin(PinId::PG09).unwrap(), //D0 - 1 => gpio_ports.pins[6][14].as_ref().unwrap(), //D1 - 2 => gpio_ports.pins[5][15].as_ref().unwrap(), //D2 - 3 => gpio_ports.pins[4][13].as_ref().unwrap(), //D3 - 4 => gpio_ports.pins[5][14].as_ref().unwrap(), //D4 - // 5 => gpio_ports.pins[4][11].as_ref().unwrap(), //D5 - // 6 => gpio_ports.pins[4][9].as_ref().unwrap(), //D6 - 7 => gpio_ports.pins[5][13].as_ref().unwrap(), //D7 - 8 => gpio_ports.pins[5][12].as_ref().unwrap(), //D8 - // 9 => gpio_ports.pins[3][15].as_ref().unwrap(), //D9 - // SPI Pins - // 10 => gpio_ports.pins[3][14].as_ref().unwrap(), //D10 - // 11 => gpio_ports.pins[0][7].as_ref().unwrap(), //D11 - // 12 => gpio_ports.pins[0][6].as_ref().unwrap(), //D12 - // 13 => gpio_ports.pins[0][5].as_ref().unwrap(), //D13 - // I2C Pins - 14 => gpio_ports.pins[1][9].as_ref().unwrap(), //D14 - 15 => gpio_ports.pins[1][8].as_ref().unwrap(), //D15 - 16 => gpio_ports.pins[2][6].as_ref().unwrap(), //D16 - 17 => gpio_ports.pins[1][15].as_ref().unwrap(), //D17 - 18 => gpio_ports.pins[1][13].as_ref().unwrap(), //D18 - 19 => gpio_ports.pins[1][12].as_ref().unwrap(), //D19 - 20 => gpio_ports.pins[0][15].as_ref().unwrap(), //D20 - 21 => gpio_ports.pins[2][7].as_ref().unwrap(), //D21 - // SPI B Pins - // 22 => gpio_ports.pins[1][5].as_ref().unwrap(), //D22 - // 23 => gpio_ports.pins[1][3].as_ref().unwrap(), //D23 - // 24 => gpio_ports.pins[0][4].as_ref().unwrap(), //D24 - // 24 => gpio_ports.pins[1][4].as_ref().unwrap(), //D25 - // QSPI - 26 => gpio_ports.pins[1][6].as_ref().unwrap(), //D26 - 27 => gpio_ports.pins[1][2].as_ref().unwrap(), //D27 - 28 => gpio_ports.pins[3][13].as_ref().unwrap(), //D28 - 29 => gpio_ports.pins[3][12].as_ref().unwrap(), //D29 - 30 => gpio_ports.pins[3][11].as_ref().unwrap(), //D30 - 31 => gpio_ports.pins[4][2].as_ref().unwrap(), //D31 - // Timer Pins - 32 => gpio_ports.pins[0][0].as_ref().unwrap(), //D32 - 33 => gpio_ports.pins[1][0].as_ref().unwrap(), //D33 - 34 => gpio_ports.pins[4][0].as_ref().unwrap(), //D34 - 35 => gpio_ports.pins[1][11].as_ref().unwrap(), //D35 - 36 => gpio_ports.pins[1][10].as_ref().unwrap(), //D36 - 37 => gpio_ports.pins[4][15].as_ref().unwrap(), //D37 - 38 => gpio_ports.pins[4][14].as_ref().unwrap(), //D38 - 39 => gpio_ports.pins[4][12].as_ref().unwrap(), //D39 - 40 => gpio_ports.pins[4][10].as_ref().unwrap(), //D40 - 41 => gpio_ports.pins[4][7].as_ref().unwrap(), //D41 - 42 => gpio_ports.pins[4][8].as_ref().unwrap(), //D42 - // SDMMC - 43 => gpio_ports.pins[2][8].as_ref().unwrap(), //D43 - 44 => gpio_ports.pins[2][9].as_ref().unwrap(), //D44 - 45 => gpio_ports.pins[2][10].as_ref().unwrap(), //D45 - 46 => gpio_ports.pins[2][11].as_ref().unwrap(), //D46 - 47 => gpio_ports.pins[2][12].as_ref().unwrap(), //D47 - 48 => gpio_ports.pins[3][2].as_ref().unwrap(), //D48 - 49 => gpio_ports.pins[6][2].as_ref().unwrap(), //D49 - 50 => gpio_ports.pins[6][3].as_ref().unwrap(), //D50 - // USART - 51 => gpio_ports.pins[3][7].as_ref().unwrap(), //D51 - 52 => gpio_ports.pins[3][6].as_ref().unwrap(), //D52 - 53 => gpio_ports.pins[3][5].as_ref().unwrap(), //D53 - 54 => gpio_ports.pins[3][4].as_ref().unwrap(), //D54 - 55 => gpio_ports.pins[3][3].as_ref().unwrap(), //D55 - 56 => gpio_ports.pins[4][2].as_ref().unwrap(), //D56 - 57 => gpio_ports.pins[4][4].as_ref().unwrap(), //D57 - 58 => gpio_ports.pins[4][5].as_ref().unwrap(), //D58 - 59 => gpio_ports.pins[4][6].as_ref().unwrap(), //D59 - 60 => gpio_ports.pins[4][3].as_ref().unwrap(), //D60 - 61 => gpio_ports.pins[5][8].as_ref().unwrap(), //D61 - 62 => gpio_ports.pins[5][7].as_ref().unwrap(), //D62 - 63 => gpio_ports.pins[5][9].as_ref().unwrap(), //D63 - 64 => gpio_ports.pins[6][1].as_ref().unwrap(), //D64 - 65 => gpio_ports.pins[6][0].as_ref().unwrap(), //D65 - // 66 => gpio_ports.pins[3][1].as_ref().unwrap(), //D66 - // 67 => gpio_ports.pins[3][0].as_ref().unwrap(), //D67 - 68 => gpio_ports.pins[5][0].as_ref().unwrap(), //D68 - 69 => gpio_ports.pins[5][1].as_ref().unwrap(), //D69 - 70 => gpio_ports.pins[5][2].as_ref().unwrap(), //D70 - 71 => gpio_ports.pins[0][7].as_ref().unwrap(), //D71 - - // ADC Pins - // Enable the to use the ADC pins as GPIO - // 72 => gpio_ports.pins[0][3].as_ref().unwrap(), //A0 - // 73 => gpio_ports.pins[2][0].as_ref().unwrap(), //A1 - // 74 => gpio_ports.pins[2][3].as_ref().unwrap(), //A2 - // 75 => gpio_ports.pins[5][3].as_ref().unwrap(), //A3 - 76 => gpio_ports.pins[5][5].as_ref().unwrap(), //A4 - 77 => gpio_ports.pins[5][10].as_ref().unwrap(), //A5 - // 78 => gpio_ports.pins[1][1].as_ref().unwrap(), //A6 - // 79 => gpio_ports.pins[2][2].as_ref().unwrap(), //A7 - 80 => gpio_ports.pins[5][4].as_ref().unwrap() //A8 - ), - ) - .finalize(components::gpio_component_static!(stm32f429zi::gpio::Pin)); - - // ADC - let adc_mux = components::adc::AdcMuxComponent::new(&base_peripherals.adc1) - .finalize(components::adc_mux_component_static!(stm32f429zi::adc::Adc)); - - let temp_sensor = components::temperature_stm::TemperatureSTMComponent::new( - adc_mux, - stm32f429zi::adc::Channel::Channel18, - 2.5, - 0.76, - ) - .finalize(components::temperature_stm_adc_component_static!( - stm32f429zi::adc::Adc - )); - let grant_cap = create_capability!(capabilities::MemoryAllocationCapability); - let grant_temperature = - board_kernel.create_grant(capsules_extra::temperature::DRIVER_NUM, &grant_cap); - - let temp = static_init!( - capsules_extra::temperature::TemperatureSensor<'static>, - capsules_extra::temperature::TemperatureSensor::new(temp_sensor, grant_temperature) - ); - kernel::hil::sensors::TemperatureDriver::set_client(temp_sensor, temp); - - let adc_channel_0 = - components::adc::AdcComponent::new(adc_mux, stm32f429zi::adc::Channel::Channel10) - .finalize(components::adc_component_static!(stm32f429zi::adc::Adc)); - - let adc_syscall = - components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM) - .finalize(components::adc_syscall_component_helper!( - adc_channel_0, - )); - - let process_printer = components::process_printer::ProcessPrinterTextComponent::new() - .finalize(components::process_printer_text_component_static!()); - PROCESS_PRINTER = Some(process_printer); - - // RNG - let rng = components::rng::RngComponent::new( - board_kernel, - capsules_core::rng::DRIVER_NUM, - &peripherals.trng, - ) - .finalize(components::rng_component_static!()); - - // PROCESS CONSOLE - let process_console = components::process_console::ProcessConsoleComponent::new( - board_kernel, - uart_mux, - mux_alarm, - process_printer, - None, - ) - .finalize(components::process_console_component_static!( - stm32f429zi::tim2::Tim2 - )); - let _ = process_console.start(); - - let ipc_comm = - driver_setup::ipc::IPCComponent::new(board_kernel, drivers::communication::DRIVER_NUM) - .finalize(driver_setup::ipc_component_static!()); - - let can = driver_setup::can::CanComponent::new( - board_kernel, - capsules_extra::can::DRIVER_NUM, - &peripherals.can1, - ) - .finalize(components::can_component_static!( - stm32f429zi::can::Can<'static> - )); - - // I2C SSD1306 screen - let i2c_mux = static_init!( - MuxI2C<'static>, - MuxI2C::new(&peripherals.stm32f4.i2c1, None, dynamic_deferred_caller) - ); - peripherals.stm32f4.i2c1.set_master_client(i2c_mux); - - let bus = components::bus::I2CMasterBusComponent::new( - i2c_mux, - capsules_extra::ssd1306::SLAVE_ADDRESS_WRITE, - ) - .finalize(components::i2c_master_bus_component_static!(2)); - - let ssd1306_screen = components::ssd1306::SSD1306Component::new(bus, dynamic_deferred_caller) - .finalize(components::ssd1306_component_static!( - capsules_extra::bus::I2CMasterBus<'static, capsules_core::virtualizers::virtual_i2c::I2CDevice<'static>>, - )); - - let _ = ssd1306_screen.init(); - - let display = components::graphic_display::GraphicDisplayComponent::new( - board_kernel, - capsules_extra::graphic_display::DRIVER_NUM, - ssd1306_screen, - Some(ssd1306_screen), - ) - .finalize(components::graphic_display_component_static!(1025)); - - let mux_pwm = components::pwm::PwmMuxComponent::new(&base_peripherals.tim1).finalize( - components::pwm_mux_component_static!(stm32f4xx::tim1::Tim1_8), - ); - - let pwm = components::pwm::PwmVirtualComponent::new(board_kernel, capsules_extra::pwm::DRIVER_NUM) - .finalize(components::pwm_syscall_component_helper!( - components::pwm::PwmPinComponent::new( - &mux_pwm, - stm32f4xx::tim1::TimOutputs::OutputCh2, - //gpio_ports.get_pin(stm32f429zi: gpio::PinId::PE11).unwrap() - ) - .finalize(components::pwm_pin_user_component_static!( - stm32f4xx::tim1::Tim1_8 - )) - )); - - let measurement = components::measurement::MeasurementComponent::new(&base_peripherals.tim3) - .finalize(components::measurement_component_static!(stm32f4xx::tim3::Tim2_5)); - - let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) - .finalize(components::round_robin_component_static!(NUM_PROCS)); - - let nucleo_f429zi = NucleoF429ZI { - console, - ipc: kernel::ipc::IPC::new( - board_kernel, - kernel::ipc::DRIVER_NUM, - &memory_allocation_capability, - ), - adc: adc_syscall, - led, - temperature: temp, - button, - alarm, - gpio, - rng, - - scheduler, - systick: cortexm4::systick::SysTick::new_with_calibration( - rcc.get_nominal_frequency_(&rcc::PeripheralClockType::AHB1(rcc::HCLK1::SysTick)), - ), - - display, - ipc_comm, - pwm, - measurement, - can, - }; - - // // Optional kernel tests - // // - // // See comment in `boards/imix/src/main.rs` - // virtual_uart_rx_test::run_virtual_uart_receive(mux_uart); - debug!("Initialization complete. Entering main loop"); - - // These symbols are defined in the linker script. - extern "C" { - /// Beginning of the ROM region containing app images. - static _sapps: u8; - /// End of the ROM region containing app images. - static _eapps: u8; - /// Beginning of the RAM region for app memory. - static mut _sappmem: u8; - /// End of the RAM region for app memory. - static _eappmem: u8; - } - - kernel::process::load_processes( - board_kernel, - chip, - core::slice::from_raw_parts( - &_sapps as *const u8, - &_eapps as *const u8 as usize - &_sapps as *const u8 as usize, - ), - core::slice::from_raw_parts_mut( - &mut _sappmem as *mut u8, - &_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize, - ), - &mut PROCESSES, - &FAULT_RESPONSE, - &process_management_capability, - ) - .unwrap_or_else(|err| { - debug!("Error loading processes!"); - debug!("{:?}", err); - }); - - //Uncomment to run multi alarm test - /*components::test::multi_alarm_test::MultiAlarmTestComponent::new(mux_alarm) - .finalize(components::multi_alarm_test_component_buf!(stm32f429zi::tim2::Tim2)) - .run();*/ - - board_kernel.kernel_loop( - &nucleo_f429zi, - chip, - Some(&nucleo_f429zi.ipc), - &main_loop_capability, - ); -} From 65f6426a06812f94d2d0ee5802465d59dfb8f937 Mon Sep 17 00:00:00 2001 From: Lazar Cristian-Stefan Date: Fri, 19 Jan 2024 19:07:06 +0200 Subject: [PATCH 6/9] Executed make prepush --- boards/components/src/bus.rs | 6 ++--- boards/components/src/graphic_display.rs | 4 ++-- boards/components/src/lib.rs | 2 +- boards/components/src/ssd1306.rs | 4 ++-- boards/nucleo_f429zi/src/main.rs | 29 +++++++++++++++--------- capsules/extra/src/lib.rs | 2 +- capsules/extra/src/ssd1306.rs | 6 ++--- kernel/src/hil/display.rs | 2 +- 8 files changed, 30 insertions(+), 25 deletions(-) diff --git a/boards/components/src/bus.rs b/boards/components/src/bus.rs index 8f9f39b5ab..f15882ee15 100644 --- a/boards/components/src/bus.rs +++ b/boards/components/src/bus.rs @@ -62,11 +62,11 @@ macro_rules! spi_bus_component_static { #[macro_export] macro_rules! i2c_master_bus_component_static { - () => {{ + ($I:ty $(,)?) => {{ let address_buffer = kernel::static_buf!([u8; 1]); - let bus = kernel::static_buf!(capsules_extra::bus::I2CMasterBus<'static>); + let bus = kernel::static_buf!(capsules_extra::bus::I2CMasterBus<'static, $I>); let i2c_device = - kernel::static_buf!(capsules_core::virtualizers::virtual_i2c::I2CDevice<'static>); + kernel::static_buf!(capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, $I>); (bus, i2c_device, address_buffer) };}; diff --git a/boards/components/src/graphic_display.rs b/boards/components/src/graphic_display.rs index 9861a9bf67..a0d8fe913c 100644 --- a/boards/components/src/graphic_display.rs +++ b/boards/components/src/graphic_display.rs @@ -26,12 +26,12 @@ //! .finalize(components::graphic_display_component_static!(40960)); //! ``` -use core::mem::MaybeUninit; use capsules_extra::graphic_display::GraphicDisplay; -use kernel::hil::display; +use core::mem::MaybeUninit; use kernel::capabilities; use kernel::component::Component; use kernel::create_capability; +use kernel::hil::display; #[macro_export] macro_rules! graphic_display_component_static { diff --git a/boards/components/src/lib.rs b/boards/components/src/lib.rs index 726d78022b..54ba69802e 100644 --- a/boards/components/src/lib.rs +++ b/boards/components/src/lib.rs @@ -78,8 +78,8 @@ pub mod si7021; pub mod siphash; pub mod sound_pressure; pub mod spi; -pub mod st77xx; pub mod ssd1306; +pub mod st77xx; pub mod temperature; pub mod temperature_rp2040; pub mod temperature_stm; diff --git a/boards/components/src/ssd1306.rs b/boards/components/src/ssd1306.rs index dc13068a9a..ec332ae46d 100644 --- a/boards/components/src/ssd1306.rs +++ b/boards/components/src/ssd1306.rs @@ -1,6 +1,6 @@ -use core::mem::MaybeUninit; use capsules_extra::bus; use capsules_extra::ssd1306; +use core::mem::MaybeUninit; use kernel::component::Component; use kernel::deferred_call::DeferredCall; use kernel::deferred_call::DeferredCallClient; @@ -97,7 +97,7 @@ impl> Component for SSD1306Component { )); self.bus.set_client(ssd1306); - // todo remove ssd1306.initialize_callback_handle(self.deferred_caller.register(ssd1306).unwrap()); + // todo remove ssd1306.initialize_callback_handle(self.deferred_caller.register(ssd1306).unwrap()); ssd1306.register(); ssd1306 diff --git a/boards/nucleo_f429zi/src/main.rs b/boards/nucleo_f429zi/src/main.rs index e70bf11757..96476e2c4d 100644 --- a/boards/nucleo_f429zi/src/main.rs +++ b/boards/nucleo_f429zi/src/main.rs @@ -86,6 +86,7 @@ struct NucleoF429ZI { 'static, stm32f429zi::rtc::Rtc<'static>, >, + display: &'static capsules_extra::graphic_display::GraphicDisplay<'static>, } /// Mapping of integer syscalls to objects that implement syscalls. @@ -638,23 +639,28 @@ pub unsafe fn main() { // I2C SSD1306 screen let i2c_mux = components::i2c::I2CMuxComponent::new(&peripherals.stm32f4.i2c1, None).finalize( - components::i2c_mux_component_static!(stm32f4xx::i2c::I2C<'static>)); - // static_init!( - // MuxI2C<'static, stm32f4xx::i2c::I2C>, - // MuxI2C::new(&peripherals.stm32f4.i2c1, None) - // ); + components::i2c_mux_component_static!(stm32f4xx::i2c::I2C<'static>), + ); kernel::deferred_call::DeferredCallClient::register(i2c_mux); + //todo: bus initialization let bus = components::bus::I2CMasterBusComponent::new( i2c_mux, capsules_extra::ssd1306::SLAVE_ADDRESS_WRITE, ) - .finalize(components::i2c_master_bus_component_static!()); //todo - - let ssd1306_screen = components::ssd1306::SSD1306Component::new(bus) - .finalize(components::ssd1306_component_static!( - capsules_extra::bus::I2CMasterBus<'static, capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, stm32f4xx::i2c::I2C>>, - )); + .finalize(components::i2c_master_bus_component_static!()); + + let ssd1306_screen = components::ssd1306::SSD1306Component::new(bus).finalize( + components::ssd1306_component_static!( + capsules_extra::bus::I2CMasterBus< + 'static, + capsules_core::virtualizers::virtual_i2c::I2CDevice< + 'static, + stm32f4xx::i2c::I2C<'static>, + >, + >, + ), + ); let _ = ssd1306_screen.init(); @@ -702,6 +708,7 @@ pub unsafe fn main() { systick: cortexm4::systick::SysTick::new(), can: can, date_time, + display, }; // // Optional kernel tests diff --git a/capsules/extra/src/lib.rs b/capsules/extra/src/lib.rs index 2117bd99ca..1eab0b122b 100644 --- a/capsules/extra/src/lib.rs +++ b/capsules/extra/src/lib.rs @@ -86,8 +86,8 @@ pub mod sht4x; pub mod si7021; pub mod sip_hash; pub mod sound_pressure; -pub mod st77xx; pub mod ssd1306; +pub mod st77xx; pub mod symmetric_encryption; pub mod temperature; pub mod temperature_rp2040; diff --git a/capsules/extra/src/ssd1306.rs b/capsules/extra/src/ssd1306.rs index 79b588a07b..e5e575b6c2 100644 --- a/capsules/extra/src/ssd1306.rs +++ b/capsules/extra/src/ssd1306.rs @@ -3,16 +3,14 @@ use kernel::{ ErrorCode, }; -use kernel::deferred_call::{ - DeferredCall, DeferredCallClient -}; +use kernel::deferred_call::{DeferredCall, DeferredCallClient}; use crate::bus::{self, Bus, BusWidth}; +use core::cell::Cell; use kernel::hil::display::{ Align, FrameBuffer, FrameBufferClient, FrameBufferSetup, GraphicsFrame, GraphicsMode, PixelFormat, Point, Rotation, Screen, ScreenClient, Tile, }; -use core::cell::Cell; pub const SLAVE_ADDRESS_WRITE: u8 = 0b0111100; pub const SLAVE_ADDRESS_READ: u8 = 0b0111101; diff --git a/kernel/src/hil/display.rs b/kernel/src/hil/display.rs index e803994b0a..e776f7d27f 100644 --- a/kernel/src/hil/display.rs +++ b/kernel/src/hil/display.rs @@ -1,7 +1,7 @@ //! Interface for screens and displays. +use crate::ErrorCode; use core::ops::Add; use core::ops::Sub; -use crate::ErrorCode; pub const MAX_BRIGHTNESS: u16 = 65535; From b1ecf34dce588719e6a119c54a620619f9135084 Mon Sep 17 00:00:00 2001 From: Lazar Cristian-Stefan Date: Mon, 22 Jan 2024 23:52:49 +0200 Subject: [PATCH 7/9] Removed changes to boards/components/bus.rs --- boards/components/src/bus.rs | 6 +-- boards/components/src/graphic_display.rs | 4 ++ boards/components/src/ssd1306.rs | 4 ++ boards/nucleo_f429zi/src/main.rs | 60 ++++++++++++------------ capsules/extra/src/bus.rs | 1 - capsules/extra/src/graphic_display.rs | 4 ++ capsules/extra/src/ssd1306.rs | 4 ++ kernel/src/hil/display.rs | 4 ++ 8 files changed, 53 insertions(+), 34 deletions(-) diff --git a/boards/components/src/bus.rs b/boards/components/src/bus.rs index f15882ee15..8f9f39b5ab 100644 --- a/boards/components/src/bus.rs +++ b/boards/components/src/bus.rs @@ -62,11 +62,11 @@ macro_rules! spi_bus_component_static { #[macro_export] macro_rules! i2c_master_bus_component_static { - ($I:ty $(,)?) => {{ + () => {{ let address_buffer = kernel::static_buf!([u8; 1]); - let bus = kernel::static_buf!(capsules_extra::bus::I2CMasterBus<'static, $I>); + let bus = kernel::static_buf!(capsules_extra::bus::I2CMasterBus<'static>); let i2c_device = - kernel::static_buf!(capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, $I>); + kernel::static_buf!(capsules_core::virtualizers::virtual_i2c::I2CDevice<'static>); (bus, i2c_device, address_buffer) };}; diff --git a/boards/components/src/graphic_display.rs b/boards/components/src/graphic_display.rs index a0d8fe913c..28f6e23f5e 100644 --- a/boards/components/src/graphic_display.rs +++ b/boards/components/src/graphic_display.rs @@ -1,3 +1,7 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2022. + //! Components for the Screen. //! //! Buffer Size diff --git a/boards/components/src/ssd1306.rs b/boards/components/src/ssd1306.rs index ec332ae46d..810abb84cb 100644 --- a/boards/components/src/ssd1306.rs +++ b/boards/components/src/ssd1306.rs @@ -1,3 +1,7 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2022. + use capsules_extra::bus; use capsules_extra::ssd1306; use core::mem::MaybeUninit; diff --git a/boards/nucleo_f429zi/src/main.rs b/boards/nucleo_f429zi/src/main.rs index 96476e2c4d..8afa7c6b1a 100644 --- a/boards/nucleo_f429zi/src/main.rs +++ b/boards/nucleo_f429zi/src/main.rs @@ -86,7 +86,7 @@ struct NucleoF429ZI { 'static, stm32f429zi::rtc::Rtc<'static>, >, - display: &'static capsules_extra::graphic_display::GraphicDisplay<'static>, + //todo uncomment: display: &'static capsules_extra::graphic_display::GraphicDisplay<'static>, } /// Mapping of integer syscalls to objects that implement syscalls. @@ -643,34 +643,34 @@ pub unsafe fn main() { ); kernel::deferred_call::DeferredCallClient::register(i2c_mux); - //todo: bus initialization - let bus = components::bus::I2CMasterBusComponent::new( - i2c_mux, - capsules_extra::ssd1306::SLAVE_ADDRESS_WRITE, - ) - .finalize(components::i2c_master_bus_component_static!()); - - let ssd1306_screen = components::ssd1306::SSD1306Component::new(bus).finalize( - components::ssd1306_component_static!( - capsules_extra::bus::I2CMasterBus< - 'static, - capsules_core::virtualizers::virtual_i2c::I2CDevice< - 'static, - stm32f4xx::i2c::I2C<'static>, - >, - >, - ), - ); - - let _ = ssd1306_screen.init(); - - let display = components::graphic_display::GraphicDisplayComponent::new( - board_kernel, - capsules_extra::graphic_display::DRIVER_NUM, - ssd1306_screen, - Some(ssd1306_screen), - ) - .finalize(components::graphic_display_component_static!(1025)); + //todo: bus initialization + uncomment + // let bus = components::bus::I2CMasterBusComponent::new( + // i2c_mux, + // capsules_extra::ssd1306::SLAVE_ADDRESS_WRITE, + // ) + // .finalize(components::i2c_master_bus_component_static!()); + + // let ssd1306_screen = components::ssd1306::SSD1306Component::new(bus).finalize( + // components::ssd1306_component_static!( + // capsules_extra::bus::I2CMasterBus< + // 'static, + // capsules_core::virtualizers::virtual_i2c::I2CDevice< + // 'static, + // stm32f4xx::i2c::I2C<'static>, + // >, + // >, + // ), + // ); + + // let _ = ssd1306_screen.init(); + + // let display = components::graphic_display::GraphicDisplayComponent::new( + // board_kernel, + // capsules_extra::graphic_display::DRIVER_NUM, + // ssd1306_screen, + // Some(ssd1306_screen), + // ) + // .finalize(components::graphic_display_component_static!(1025)); // PROCESS CONSOLE let process_console = components::process_console::ProcessConsoleComponent::new( @@ -708,7 +708,7 @@ pub unsafe fn main() { systick: cortexm4::systick::SysTick::new(), can: can, date_time, - display, + //todo uncomment: display, }; // // Optional kernel tests diff --git a/capsules/extra/src/bus.rs b/capsules/extra/src/bus.rs index 126cc3b942..9576ee939d 100644 --- a/capsules/extra/src/bus.rs +++ b/capsules/extra/src/bus.rs @@ -330,7 +330,6 @@ impl<'a, I: I2CDevice> Bus<'a> for I2CMasterBus<'a, I> { let bytes = data_width.width_in_bytes(); self.len.set(len * bytes); - //TODO: might crash if len * bytes < 255 && buffer.len() >= len * bytes { debug!("write len {}", len); self.len.set(len); diff --git a/capsules/extra/src/graphic_display.rs b/capsules/extra/src/graphic_display.rs index 40a965245b..deef606aa0 100644 --- a/capsules/extra/src/graphic_display.rs +++ b/capsules/extra/src/graphic_display.rs @@ -1,3 +1,7 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2022. + //! Provides userspace with access to the screen. //! //! Usage diff --git a/capsules/extra/src/ssd1306.rs b/capsules/extra/src/ssd1306.rs index e5e575b6c2..2578e5d2d1 100644 --- a/capsules/extra/src/ssd1306.rs +++ b/capsules/extra/src/ssd1306.rs @@ -1,3 +1,7 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2022. + use kernel::{ utilities::cells::{OptionalCell, TakeCell}, ErrorCode, diff --git a/kernel/src/hil/display.rs b/kernel/src/hil/display.rs index e776f7d27f..62b218ed8d 100644 --- a/kernel/src/hil/display.rs +++ b/kernel/src/hil/display.rs @@ -1,3 +1,7 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2022. + //! Interface for screens and displays. use crate::ErrorCode; use core::ops::Add; From 3dc9ca3da92bfeee1c90a20f1dd994463516d986 Mon Sep 17 00:00:00 2001 From: Cristian L <117449010+Cristian243342@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:42:48 +0200 Subject: [PATCH 8/9] Split changes to bus.rs library into a separate pull request --- capsules/extra/src/bus.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/capsules/extra/src/bus.rs b/capsules/extra/src/bus.rs index 9576ee939d..5cc22479dc 100644 --- a/capsules/extra/src/bus.rs +++ b/capsules/extra/src/bus.rs @@ -301,21 +301,7 @@ impl<'a, I: I2CDevice> Bus<'a> for I2CMasterBus<'a, I> { } } }), - BusWidth::Bits16LE => self - .addr_buffer - .take() - .map_or(Err(ErrorCode::NOMEM), |buffer| { - buffer[0] = 0x00; - buffer[1] = addr as u8; - self.status.set(BusStatus::SetAddress); - match self.i2c.write(buffer, 2) { - Ok(()) => Ok(()), - Err((error, buffer)) => { - self.addr_buffer.replace(buffer); - Err(error.into()) - } - } - }), + _ => Err(ErrorCode::NOSUPPORT), } } From 561138ef286c5dc401cb01b42ba2e9208bfcf1c8 Mon Sep 17 00:00:00 2001 From: Cristian L <117449010+Cristian243342@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:43:42 +0200 Subject: [PATCH 9/9] Removed a new line --- capsules/extra/src/bus.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/capsules/extra/src/bus.rs b/capsules/extra/src/bus.rs index 5cc22479dc..77326f83d2 100644 --- a/capsules/extra/src/bus.rs +++ b/capsules/extra/src/bus.rs @@ -315,7 +315,6 @@ impl<'a, I: I2CDevice> Bus<'a> for I2CMasterBus<'a, I> { // endianess does not matter as the buffer is sent as is let bytes = data_width.width_in_bytes(); self.len.set(len * bytes); - if len * bytes < 255 && buffer.len() >= len * bytes { debug!("write len {}", len); self.len.set(len);