Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

need to know the buffer configuration to slint ui #5264

Closed
MohaBeacon opened this issue May 17, 2024 · 6 comments
Closed

need to know the buffer configuration to slint ui #5264

MohaBeacon opened this issue May 17, 2024 · 6 comments

Comments

@MohaBeacon
Copy link

#![no_std]
#![no_main]

extern crate alloc;
use alloc::{rc::Rc, boxed::Box};
slint::include_modules!();

fn create_slint_app() -> AppWindow {
let ui = AppWindow::new().expect("Failed to load UI");

let ui_handle = ui.as_weak();
ui.on_request_increase_value(move || {
    let ui = ui_handle.unwrap();
    ui.set_counter(ui.get_counter() + 1);
});
ui

}

use rp_pico as bsp;

use bsp::entry;
use fugit::RateExtU32;

use display_interface_spi::SPIInterface;
use embedded_graphics::prelude::*;
use embedded_graphics::{
pixelcolor::Rgb565,
primitives::{Circle, PrimitiveStyleBuilder, Rectangle, Triangle},
};

use bsp::hal::{
clocks::{init_clocks_and_plls, Clock},
gpio, pac, pwm,
sio::Sio,
spi,
watchdog::Watchdog,
};

use bsp::hal::prelude::*;
use gc9a01a;
use panic_halt as _;
use slint::platform::{Platform, software_renderer::MinimalSoftwareWindow};
use slint::platform::software_renderer::Rgb565Pixel;

#[entry]
fn main() -> ! {
use bsp::hal;
use embedded_hal::timer;
// Pull in any important traits
use fugit::RateExtU32;
use slint::platform::WindowEvent;

let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(
    slint::platform::software_renderer::RepaintBufferType::SwappedBuffers
);

const DISPLAY_WIDTH: usize = 240;
const DISPLAY_HEIGHT: usize = 240;
let mut buffer1 = [Rgb565Pixel(0); DISPLAY_WIDTH * DISPLAY_HEIGHT];
let mut buffer2 = [Rgb565Pixel(0); DISPLAY_WIDTH * DISPLAY_HEIGHT];


// -------- Setup Allocator --------
const HEAP_SIZE: usize = 200 * 1024;
static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];
#[global_allocator]
static ALLOCATOR: embedded_alloc::Heap = embedded_alloc::Heap::empty();
unsafe { ALLOCATOR.init(&mut HEAP as *const u8 as usize, core::mem::size_of_val(&HEAP)) };


// -------- Setup peripherials --------
let mut pac = pac::Peripherals::take().unwrap();
let core = pac::CorePeripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let sio = Sio::new(pac.SIO);

// External high-speed crystal on the pico board is 12Mhz
let external_xtal_freq_hz = 12_000_000u32;
let clocks = init_clocks_and_plls(
    external_xtal_freq_hz,
    pac.XOSC,
    pac.CLOCKS,
    pac.PLL_SYS,
    pac.PLL_USB,
    &mut pac.RESETS,
    &mut watchdog,
)
.ok()
.unwrap();

let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());

let pins = bsp::Pins::new(
    pac.IO_BANK0,
    pac.PADS_BANK0,
    sio.gpio_bank0,
    &mut pac.RESETS,
);
let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);

// These are implicitly used by the spi driver if they are in the correct mode
let _spi_sclk = pins.gpio10.into_mode::<gpio::FunctionSpi>();
let _spi_mosi = pins.gpio11.into_mode::<gpio::FunctionSpi>();
let spi_cs = pins.gpio9.into_push_pull_output();

// Create an SPI driver instance for the SPI1 device
let spi = spi::Spi::<_, _, 8>::new(pac.SPI1);

// Exchange the uninitialised SPI driver for an initialised one
let spi = spi.init(
    &mut pac.RESETS,
    clocks.peripheral_clock.freq(),
    8_000_000u32.Hz(),
    &embedded_hal::spi::MODE_0,
);

let dc_pin = pins.gpio8.into_push_pull_output();
let rst_pin = pins.gpio12.into_push_pull_output();

let spi_interface = SPIInterface::new(spi, dc_pin, spi_cs);

// initialize PWM for backlight
let pwm_slices = pwm::Slices::new(pac.PWM, &mut pac.RESETS);

// Configure PWM6
let mut pwm = pwm_slices.pwm4;
pwm.set_ph_correct();
pwm.enable();

// Output channel B on PWM6 to GPIO 13
let mut channel = pwm.channel_b;
channel.output_to(pins.led);

// Create display driver
let mut display = gc9a01a::GC9A01A::new(spi_interface, rst_pin, channel);
// Bring out of reset
display.reset(&mut delay).unwrap();
// Turn on backlight
display.set_backlight(55000);
// Initialize registers
display.initialize(&mut delay).unwrap();


let mut currently_displayed_buffer : &mut [_] = &mut buffer1;
let mut work_buffer : &mut [_] = &mut buffer2;


// -------- Setup the Slint backend --------
let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(Default::default());
slint::platform::set_platform(alloc::boxed::Box::new(MyPlatform {
    window: window.clone(),
    timer,
}))
.unwrap();

struct MyPlatform {
    window: alloc::rc::Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,
    timer: hal::Timer,
}

impl slint::platform::Platform for MyPlatform {
    fn create_window_adapter(&self) -> Result<alloc::rc::Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
        Ok(self.window.clone())
    }
    fn duration_since_start(&self) -> core::time::Duration {
        core::time::Duration::from_micros(self.timer.get_counter_low().into())
    }
   
}

// -------- Configure the UI --------
// (need to be done after the call to slint::platform::set_platform)
let _ui = create_slint_app();

// -------- Event loop --------
let mut line = [slint::platform::software_renderer::Rgb565Pixel(0); 240];

loop {
    slint::platform::update_timers_and_animations();
    window.draw_if_needed(|renderer| {
        use embedded_graphics_core::prelude::*;
        struct DisplayWrapper<'a, T>(
            &'a mut T,
            &'a mut [slint::platform::software_renderer::Rgb565Pixel],
        );
        impl<T: DrawTarget<Color = embedded_graphics_core::pixelcolor::Rgb565>>
            slint::platform::software_renderer::LineBufferProvider for DisplayWrapper<'_, T>
        {
            type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;
            fn process_line(
                &mut self,
                line: usize,
                range: core::ops::Range<usize>,
                render_fn: impl FnOnce(&mut [Self::TargetPixel]),
            ) {
                let rect = embedded_graphics_core::primitives::Rectangle::new(
                    Point::new(range.start as _, line as _),
                    Size::new(range.len() as _, 1),
                );
                render_fn(&mut self.1[range.clone()]);
                // NOTE! this is not an efficient way to send pixel to the screen, but it is kept simple on this template.
                // It would be much faster to use the DMA to send pixel in parallel.
                // See the example in https://github.com/slint-ui/slint/blob/master/examples/mcu-board-support/pico_st7789.rs 
                self.0
                    .fill_contiguous(
                        &rect,
                        self.1[range.clone()].iter().map(|p| {
                            embedded_graphics_core::pixelcolor::raw::RawU16::new(p.0).into()
                        }),
                    )
                    .map_err(drop)
                    .unwrap();
            }
        }
        renderer.render_by_line(DisplayWrapper(&mut display, &mut line));
    });

   

    if window.has_active_animations() {
        continue;
    }

    // TODO: we could save battery here by going to sleep up to
    //   slint::platform::duration_until_next_timer_update()
    // or until the next touch interrupt, whatever comes first
    // cortex_m::asm::wfe();
}
exit()

}

pub fn exit() -> ! {
loop {
cortex_m::asm::bkpt();
}
}

[dependencies]
embedded-hal = { version = "0.2.7", features = ["unproven"]}
embedded-alloc = "0.5"
embedded-graphics-core ="0.4.0"
display-interface ="0.4.1"
display-interface-spi = "0.4.1"
gc9a01a = "0.1.1"
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "0.2"
tinybmp = "0.5"
embedded-graphics = "0.8.0"
rp-pico = "0.7"
fugit = "0.3"

[dev-dependencies]
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "0.2"
tinybmp = "0.5"
embedded-graphics = "0.8.0"
rp-pico = "0.7"
fugit = "0.3"

[dependencies.slint]
version = "1.6.0"
default-features = false
features = ["compat-1-2", "unsafe-single-threaded", "libm", "renderer-software"]

[build-dependencies]
slint-build = "1.6.0"

@MohaBeacon
Copy link
Author

#![no_std]
#![no_main]

extern crate alloc;
use core::ptr::addr_of_mut;

use alloc::{rc::Rc, boxed::Box};
slint::include_modules!();

fn create_slint_app() -> AppWindow {
let ui = AppWindow::new().expect("Failed to load UI");

let ui_handle = ui.as_weak();
ui.on_request_increase_value(move || {
    let ui = ui_handle.unwrap();
    ui.set_counter(ui.get_counter() + 1);
});
ui

}

use rp_pico as bsp;

use bsp::entry;
use fugit::RateExtU32;

use display_interface_spi::SPIInterface;
use embedded_graphics::prelude::*;
use embedded_graphics::{
pixelcolor::Rgb565,
primitives::{Circle, PrimitiveStyleBuilder, Rectangle, Triangle},
};

use bsp::hal::{
clocks::{init_clocks_and_plls, Clock},
gpio, pac, pwm,
sio::Sio,
spi,
watchdog::Watchdog,
};

use bsp::hal::prelude::*;
use gc9a01a;
use panic_halt as _;
use slint::platform::{Platform, software_renderer::MinimalSoftwareWindow};
use slint::platform::software_renderer::Rgb565Pixel;

#[entry]
fn main() -> ! {
use bsp::hal;
use embedded_hal::timer;
// Pull in any important traits
use fugit::RateExtU32;
use slint::platform::WindowEvent;

// -------- Setup Allocator --------
const HEAP_SIZE: usize = 200 * 1024;
static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];
#[global_allocator]
static ALLOCATOR: embedded_alloc::Heap = embedded_alloc::Heap::empty();
unsafe { ALLOCATOR.init(addr_of_mut!(HEAP) as *const u8 as usize, core::mem::size_of_val(&HEAP)) };


// -------- Setup peripherials --------
let mut pac = pac::Peripherals::take().unwrap();
let core = pac::CorePeripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let sio = Sio::new(pac.SIO);

// External high-speed crystal on the pico board is 12Mhz
let external_xtal_freq_hz = 12_000_000u32;
let clocks = init_clocks_and_plls(
    external_xtal_freq_hz,
    pac.XOSC,
    pac.CLOCKS,
    pac.PLL_SYS,
    pac.PLL_USB,
    &mut pac.RESETS,
    &mut watchdog,
)
.ok()
.unwrap();

let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());

let pins = bsp::Pins::new(
    pac.IO_BANK0,
    pac.PADS_BANK0,
    sio.gpio_bank0,
    &mut pac.RESETS,
);
let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);

// These are implicitly used by the spi driver if they are in the correct mode
let _spi_sclk = pins.gpio10.into_mode::<gpio::FunctionSpi>();
let _spi_mosi = pins.gpio11.into_mode::<gpio::FunctionSpi>();
let spi_cs = pins.gpio9.into_push_pull_output();

// Create an SPI driver instance for the SPI1 device
let spi = spi::Spi::<_, _, 8>::new(pac.SPI1);

// Exchange the uninitialised SPI driver for an initialised one
let spi = spi.init(
    &mut pac.RESETS,
    clocks.peripheral_clock.freq(),
    8_000_000u32.Hz(),
    &embedded_hal::spi::MODE_0,
);

let dc_pin = pins.gpio8.into_push_pull_output();
let rst_pin = pins.gpio12.into_push_pull_output();

let spi_interface = SPIInterface::new(spi, dc_pin, spi_cs);

// initialize PWM for backlight
let pwm_slices = pwm::Slices::new(pac.PWM, &mut pac.RESETS);

// Configure PWM6
let mut pwm = pwm_slices.pwm4;
pwm.set_ph_correct();
pwm.enable();

// Output channel B on PWM6 to GPIO 13
let mut channel = pwm.channel_b;
channel.output_to(pins.led);

// Create display driver
let mut display = gc9a01a::GC9A01A::new(spi_interface, rst_pin, channel);
// Bring out of reset
display.reset(&mut delay).unwrap();
// Turn on backlight
display.set_backlight(55000);
// Initialize registers
display.initialize(&mut delay).unwrap();


// -------- Setup the Slint backend --------
let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(Default::default());
slint::platform::set_platform(alloc::boxed::Box::new(MyPlatform {
    window: window.clone(),
    timer,
}))
.unwrap();

struct MyPlatform {
    window: alloc::rc::Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,
    timer: hal::Timer,
}

impl slint::platform::Platform for MyPlatform {
    fn create_window_adapter(&self) -> Result<alloc::rc::Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
        Ok(self.window.clone())
    }
    fn duration_since_start(&self) -> core::time::Duration {
        core::time::Duration::from_micros(self.timer.get_counter_low().into())
    }
   
}

// -------- Configure the UI --------
// (need to be done after the call to slint::platform::set_platform)
let _ui = create_slint_app();

// -------- Event loop --------
let mut line = [slint::platform::software_renderer::Rgb565Pixel(0); 240];

loop {
    slint::platform::update_timers_and_animations();
    window.draw_if_needed(|renderer| {
        use embedded_graphics_core::prelude::*;
        struct DisplayWrapper<'a, T>(
            &'a mut T,
            &'a mut [slint::platform::software_renderer::Rgb565Pixel],
        );
        impl<T: DrawTarget<Color = embedded_graphics_core::pixelcolor::Rgb565>>
            slint::platform::software_renderer::LineBufferProvider for DisplayWrapper<'_, T>
        {
            type TargetPixel = slint::platform::software_renderer::Rgb565Pixel;
            fn process_line(
                &mut self,
                line: usize,
                range: core::ops::Range<usize>,
                render_fn: impl FnOnce(&mut [Self::TargetPixel]),
            ) {
                let rect = embedded_graphics_core::primitives::Rectangle::new(
                    Point::new(range.start as _, line as _),
                    Size::new(range.len() as _, 1),
                );
                render_fn(&mut self.1[range.clone()]);
                // NOTE! this is not an efficient way to send pixel to the screen, but it is kept simple on this template.
                // It would be much faster to use the DMA to send pixel in parallel.
                // See the example in https://github.com/slint-ui/slint/blob/master/examples/mcu-board-support/pico_st7789.rs 
                self.0
                    .fill_contiguous(
                        &rect,
                        self.1[range.clone()].iter().map(|p| {
                            embedded_graphics_core::pixelcolor::raw::RawU16::new(p.0).into()
                        }),
                    )
                    .map_err(drop)
                    .unwrap();
            }
        }
        renderer.render_by_line(DisplayWrapper(&mut display, &mut line));
    });

   

    if window.has_active_animations() {
        continue;
    }

    // TODO: we could save battery here by going to sleep up to
    //   slint::platform::duration_until_next_timer_update()
    // or until the next touch interrupt, whatever comes first
    // cortex_m::asm::wfe();
}
exit()

}

pub fn exit() -> ! {
loop {
cortex_m::asm::bkpt();
}
}

@hunger
Copy link
Member

hunger commented May 22, 2024

Thank you for taking the time to report your issue with Slint!

What is the problem here?

Maybe you could put the code into a repo on Github or elsewhere and put a link to that repo here? It is way easier to just check out something than to copy/paste things into possibly multiple files. The missing Cargo.toml makes it even harder to just try this out.

A short description of what you actually observe and what you expect to happen instead would also help.

@MohaBeacon
Copy link
Author

i have tried to use https://docs.rs/gc9a01a/latest/gc9a01a/ it is working fine with draw line by line - but when trying to use buffer - embedded hal - not able to know how to // ... configure the screen driver to use buffer1 or buffer2 ... in the docs of mcu

@MohaBeacon
Copy link
Author

[dependencies]
embedded-hal = { version = "0.2.7", features = ["unproven"]}
embedded-alloc = "0.5"
embedded-graphics-core ="0.4.0"
display-interface ="0.4.1"
display-interface-spi = "0.4.1"
shared-bus = "0.2.4"
gc9a01a = "0.1.1"
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "0.2"
tinybmp = "0.5"
embedded-graphics = "0.8.0"
rp-pico = "0.7"
fugit = "0.3"

@hunger
Copy link
Member

hunger commented May 22, 2024

Do you have enough memory to drive a buffer on the rp-pico?

@MohaBeacon
Copy link
Author

Do you have enough memory to drive a buffer on the rp-pico?

yes i have, i feel my configuration to make it work is having a trouble. let me update and let you know on this.

@slint-ui slint-ui locked and limited conversation to collaborators May 24, 2024
@ogoffart ogoffart converted this issue into discussion #5294 May 24, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants