Compare commits
No commits in common. "e9298384c278886e1c216da74be8cb2bce48fd29" and "3d7e506dd5fb257aeffc49b360327fedb2465c60" have entirely different histories.
e9298384c2
...
3d7e506dd5
41
Cargo.lock
generated
41
Cargo.lock
generated
@ -725,12 +725,6 @@ version = "1.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "format_no_std"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9ae45e32b0bfe2c62c805f8e87027b5aa08562000326edbc5b421ab6d92873a7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fugit"
|
name = "fugit"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@ -867,20 +861,17 @@ dependencies = [
|
|||||||
"esp-hal",
|
"esp-hal",
|
||||||
"esp-hal-embassy",
|
"esp-hal-embassy",
|
||||||
"esp-println",
|
"esp-println",
|
||||||
"format_no_std",
|
|
||||||
"heapless 0.8.0",
|
"heapless 0.8.0",
|
||||||
"kolibri-embedded-gui",
|
"kolibri-embedded-gui",
|
||||||
"mipidsi",
|
"mipidsi",
|
||||||
"profont",
|
|
||||||
"static_cell",
|
"static_cell",
|
||||||
"ufmt",
|
|
||||||
"xpt2046",
|
"xpt2046",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kolibri-embedded-gui"
|
name = "kolibri-embedded-gui"
|
||||||
version = "0.0.0-alpha.1"
|
version = "0.0.0-alpha.1"
|
||||||
source = "git+https://github.com/Yandrik/kolibri.git?branch=optimizations#f3e92212ac29431561748e6c37427651b3151bc4"
|
source = "git+https://github.com/Yandrik/kolibri.git?branch=optimizations#1bd7d733a6772f208a8a08f05cf33f5467c02d34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-graphics",
|
"embedded-graphics",
|
||||||
"embedded-iconoir",
|
"embedded-iconoir",
|
||||||
@ -1048,15 +1039,6 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "profont"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "016681370a9dd6e7ddb4c1a959922fd59dc45e5ebaa5ff5b13090267898ced34"
|
|
||||||
dependencies = [
|
|
||||||
"embedded-graphics",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.37"
|
version = "1.0.37"
|
||||||
@ -1284,27 +1266,6 @@ dependencies = [
|
|||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ufmt"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a64846ec02b57e9108d6469d98d1648782ad6bb150a95a9baac26900bbeab9d"
|
|
||||||
dependencies = [
|
|
||||||
"ufmt-macros",
|
|
||||||
"ufmt-write",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ufmt-macros"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d337d3be617449165cb4633c8dece429afd83f84051024079f97ad32a9663716"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ufmt-write"
|
name = "ufmt-write"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -8,9 +8,6 @@ rust-version = "1.76.0"
|
|||||||
name = "firmware"
|
name = "firmware"
|
||||||
path = "src/bin/firmware.rs"
|
path = "src/bin/firmware.rs"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "kolibri-timer"
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "xpt"
|
name = "xpt"
|
||||||
path = "src/bin/xpt.rs"
|
path = "src/bin/xpt.rs"
|
||||||
@ -39,12 +36,9 @@ esp-backtrace = { version = "0.14.1", features = ["esp32", "println", "except
|
|||||||
esp-hal = { version = "0.20.1", features = ["esp32", "log", "async"] }
|
esp-hal = { version = "0.20.1", features = ["esp32", "log", "async"] }
|
||||||
esp-hal-embassy = { version = "0.3.0", features = ["esp32", "log"] }
|
esp-hal-embassy = { version = "0.3.0", features = ["esp32", "log"] }
|
||||||
esp-println = { version = "0.11.0", features = ["esp32", "log"] }
|
esp-println = { version = "0.11.0", features = ["esp32", "log"] }
|
||||||
format_no_std = "1.2.0"
|
|
||||||
heapless = { version = "0.8.0", features = ["serde"] }
|
heapless = { version = "0.8.0", features = ["serde"] }
|
||||||
kolibri-embedded-gui = { git = "https://github.com/Yandrik/kolibri.git", version = "0.0.0-alpha.1", branch = "optimizations" }
|
kolibri-embedded-gui = { git = "https://github.com/Yandrik/kolibri.git", version = "0.0.0-alpha.1", branch = "optimizations" }
|
||||||
mipidsi = "0.8.0"
|
mipidsi = "0.8.0"
|
||||||
profont = "0.7.0"
|
|
||||||
static_cell = { version = "2.1.0", features = ["nightly"] }
|
static_cell = { version = "2.1.0", features = ["nightly"] }
|
||||||
ufmt = "0.2.0"
|
|
||||||
xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
|
xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
|
||||||
|
|
||||||
|
@ -1,244 +0,0 @@
|
|||||||
#![no_std]
|
|
||||||
#![no_main]
|
|
||||||
|
|
||||||
use core::cell::RefCell;
|
|
||||||
use core::cmp::min;
|
|
||||||
use display_interface_spi::SPIInterface;
|
|
||||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
|
||||||
use embassy_executor::Spawner;
|
|
||||||
use embassy_sync::{
|
|
||||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
|
||||||
signal::Signal,
|
|
||||||
};
|
|
||||||
use embassy_time::{Duration, Timer};
|
|
||||||
use embedded_graphics::{
|
|
||||||
mono_font::ascii,
|
|
||||||
pixelcolor::Rgb565,
|
|
||||||
prelude::{DrawTarget, Point, RgbColor},
|
|
||||||
};
|
|
||||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
|
||||||
use esp_backtrace as _;
|
|
||||||
use esp_hal::{
|
|
||||||
clock::ClockControl,
|
|
||||||
gpio,
|
|
||||||
gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
|
|
||||||
peripherals::{Peripherals, SPI2, SPI3},
|
|
||||||
prelude::*,
|
|
||||||
rtc_cntl::Rtc,
|
|
||||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
|
||||||
system::SystemControl,
|
|
||||||
timer::{timg::TimerGroup, OneShotTimer},
|
|
||||||
};
|
|
||||||
use esp_println::println;
|
|
||||||
use kolibri_cyd_tester_app_embassy::Debouncer;
|
|
||||||
use kolibri_embedded_gui::{
|
|
||||||
button::Button,
|
|
||||||
label::Label,
|
|
||||||
smartstate::SmartstateProvider,
|
|
||||||
style::medsize_rgb565_style,
|
|
||||||
ui::{Interaction, Ui},
|
|
||||||
};
|
|
||||||
use kolibri_embedded_gui::helpers::keyboard::draw_keyboard;
|
|
||||||
use mipidsi::{
|
|
||||||
models::{ILI9486Rgb565, ILI9486Rgb666},
|
|
||||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
|
||||||
Builder,
|
|
||||||
};
|
|
||||||
use static_cell::{make_static, StaticCell};
|
|
||||||
use xpt2046::Xpt2046;
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn touch_task(
|
|
||||||
touch_irq: GpioPin<36>,
|
|
||||||
spi: &'static mut NoopMutex<RefCell<Spi<'static, SPI3, FullDuplexMode>>>,
|
|
||||||
touch_cs: GpioPin<33>,
|
|
||||||
touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
|
|
||||||
) -> ! {
|
|
||||||
let mut touch_driver = Xpt2046::new(
|
|
||||||
SpiDevice::new(spi, Output::new(touch_cs, Level::Low)),
|
|
||||||
Input::new(touch_irq, Pull::Up),
|
|
||||||
xpt2046::Orientation::LandscapeFlipped,
|
|
||||||
);
|
|
||||||
touch_driver.set_num_samples(16);
|
|
||||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
|
||||||
|
|
||||||
let mut debounce = Debouncer::new();
|
|
||||||
println!("touch task");
|
|
||||||
|
|
||||||
loop {
|
|
||||||
touch_driver.run().expect("Running Touch driver failed");
|
|
||||||
if touch_driver.is_touched() {
|
|
||||||
let point = touch_driver.get_touch_point();
|
|
||||||
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
|
|
||||||
} else {
|
|
||||||
touch_signal.signal(None);
|
|
||||||
}
|
|
||||||
Timer::after(Duration::from_millis(1)).await; // 100 a second
|
|
||||||
|
|
||||||
// Your touch handling logic here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[main]
|
|
||||||
async fn main(spawner: Spawner) {
|
|
||||||
let peripherals = Peripherals::take();
|
|
||||||
let system = SystemControl::new(peripherals.SYSTEM);
|
|
||||||
let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
|
||||||
|
|
||||||
// Enable the RWDT watchdog timer:
|
|
||||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
|
||||||
rtc.rwdt.set_timeout(2.secs());
|
|
||||||
rtc.rwdt.enable();
|
|
||||||
println!("RWDT watchdog enabled!");
|
|
||||||
|
|
||||||
// Initialize the SYSTIMER peripheral, and then Embassy:
|
|
||||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
|
||||||
esp_hal_embassy::init(&clocks, timg0.timer0);
|
|
||||||
println!("Embassy initialized!");
|
|
||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
|
||||||
// let mut led = Output::new(io.pins.gpio5, Level::High);
|
|
||||||
// Initialize SPI
|
|
||||||
let sclk = io.pins.gpio14;
|
|
||||||
let miso = io.pins.gpio12;
|
|
||||||
let mosi = io.pins.gpio13;
|
|
||||||
let cs = io.pins.gpio15;
|
|
||||||
let dc = io.pins.gpio2;
|
|
||||||
let mut backlight = Output::new(io.pins.gpio21, Level::Low);
|
|
||||||
|
|
||||||
// Note: RST is not initialized as it's set to -1 in the instructions
|
|
||||||
|
|
||||||
// up to 80MHz is possible (even tho the display driver isn't supposed to be
|
|
||||||
// that fast) Dataseheet sais 10MHz, so we're gonna go with that
|
|
||||||
let mut spi = Spi::new(peripherals.SPI2, 10.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(sclk),
|
|
||||||
Some(mosi),
|
|
||||||
Some(miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
|
|
||||||
static DISP_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let spi_bus = NoopMutex::new(RefCell::new(spi));
|
|
||||||
let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
|
||||||
|
|
||||||
let di = SPIInterface::new(
|
|
||||||
SpiDevice::new(spi_bus, Output::new(cs, Level::Low)),
|
|
||||||
Output::new(dc, Level::Low),
|
|
||||||
);
|
|
||||||
let display = Builder::new(ILI9486Rgb565, di)
|
|
||||||
.orientation(Orientation {
|
|
||||||
rotation: Rotation::Deg90,
|
|
||||||
mirrored: true,
|
|
||||||
})
|
|
||||||
.color_order(ColorOrder::Bgr)
|
|
||||||
.invert_colors(ColorInversion::Inverted)
|
|
||||||
.init(&mut embassy_time::Delay)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut display = ProfilerDisplay::new(display);
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
ui.clear_background().ok();
|
|
||||||
}
|
|
||||||
backlight.set_high();
|
|
||||||
|
|
||||||
// init touchscreen pins
|
|
||||||
let touch_irq = io.pins.gpio36;
|
|
||||||
let touch_mosi = io.pins.gpio32;
|
|
||||||
let touch_miso = io.pins.gpio39;
|
|
||||||
let touch_clk = io.pins.gpio25;
|
|
||||||
let touch_cs = io.pins.gpio33;
|
|
||||||
|
|
||||||
// 2MHz is the MAX! DO NOT DECREASE! This is really important.
|
|
||||||
let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(touch_clk),
|
|
||||||
Some(touch_mosi),
|
|
||||||
Some(touch_miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
static TOUCH_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI3, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let touch_spi_bus = NoopMutex::new(RefCell::new(touch_spi));
|
|
||||||
let touch_spi_bus = TOUCH_SPI_BUS.init(touch_spi_bus);
|
|
||||||
|
|
||||||
let touch_signal = Signal::new();
|
|
||||||
static TOUCH_SIGNAL: StaticCell<Signal<NoopRawMutex, Option<Point>>> = StaticCell::new();
|
|
||||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
|
||||||
|
|
||||||
spawner
|
|
||||||
.spawn(touch_task(touch_irq, touch_spi_bus, touch_cs, touch_signal))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// init RGB LED pins
|
|
||||||
|
|
||||||
let mut red_led = Output::new(io.pins.gpio4, Level::High);
|
|
||||||
let mut green_led = Output::new(io.pins.gpio16, Level::High);
|
|
||||||
let mut blue_led = Output::new(io.pins.gpio17, Level::High);
|
|
||||||
|
|
||||||
// init SD card pins
|
|
||||||
let sd_miso = io.pins.gpio19;
|
|
||||||
let sd_mosi = io.pins.gpio23;
|
|
||||||
let sd_sck = io.pins.gpio18;
|
|
||||||
let sd_cs = io.pins.gpio5;
|
|
||||||
|
|
||||||
// TODO: Spawn some tasks
|
|
||||||
let _ = spawner;
|
|
||||||
|
|
||||||
let mut last_touch = None;
|
|
||||||
|
|
||||||
static BUF_CELL: StaticCell<[Rgb565; 100 * 100]> = StaticCell::new();
|
|
||||||
let buf = BUF_CELL.init([Rgb565::BLACK; 100 * 100]);
|
|
||||||
|
|
||||||
// Periodically feed the RWDT watchdog timer when our tasks are not running:
|
|
||||||
let mut sm = SmartstateProvider::<20>::new();
|
|
||||||
loop {
|
|
||||||
let start_time = embassy_time::Instant::now();
|
|
||||||
sm.restart_counter();
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
ui.set_buffer(buf);
|
|
||||||
if let Some(touch) = touch_signal.try_take() {
|
|
||||||
let interact = match (touch, last_touch) {
|
|
||||||
(Some(point), Some(_)) => Interaction::Drag(point),
|
|
||||||
(Some(point), None) => Interaction::Click(point),
|
|
||||||
(None, Some(point)) => Interaction::Release(point),
|
|
||||||
(None, None) => Interaction::None,
|
|
||||||
};
|
|
||||||
ui.interact(interact);
|
|
||||||
// println!("{:?}, {:?}, {:?}", last_touch, touch, interact);
|
|
||||||
|
|
||||||
last_touch = touch;
|
|
||||||
}
|
|
||||||
let start_draw_time = embassy_time::Instant::now();
|
|
||||||
ui.sub_ui(|ui| {
|
|
||||||
ui.style_mut().default_font = ascii::FONT_9X18_BOLD;
|
|
||||||
ui.add(Label::new("Kolibri Tester").smartstate(sm.next()));
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
ui.add_horizontal(Button::new("Works!").smartstate(sm.next()));
|
|
||||||
ui.add(Button::new("And pretty nicely!").smartstate(sm.next()));
|
|
||||||
let end_time = embassy_time::Instant::now();
|
|
||||||
let draw_time = display.get_time();
|
|
||||||
let prep_time = start_draw_time - start_time;
|
|
||||||
let proc_time = end_time - start_draw_time;
|
|
||||||
let proc_time = proc_time - min(draw_time, proc_time);
|
|
||||||
rtc.rwdt.feed();
|
|
||||||
|
|
||||||
if draw_time.as_micros() > 0 {
|
|
||||||
println!(
|
|
||||||
"draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms ",
|
|
||||||
draw_time.as_millis(),
|
|
||||||
draw_time.as_micros() % 100,
|
|
||||||
prep_time.as_millis(),
|
|
||||||
prep_time.as_micros() % 100,
|
|
||||||
proc_time.as_millis(),
|
|
||||||
proc_time.as_micros() % 100,
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
display.reset_time();
|
|
||||||
Timer::after(Duration::from_millis(17)).await; // 60 a second
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,250 +0,0 @@
|
|||||||
#![no_std]
|
|
||||||
#![no_main]
|
|
||||||
|
|
||||||
use core::cell::RefCell;
|
|
||||||
use core::cmp::min;
|
|
||||||
use display_interface_spi::SPIInterface;
|
|
||||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
|
||||||
use embassy_executor::Spawner;
|
|
||||||
use embassy_sync::{
|
|
||||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
|
||||||
signal::Signal,
|
|
||||||
};
|
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
|
||||||
use embedded_graphics::{mono_font::ascii, pixelcolor::Rgb565, prelude::{DrawTarget, Point, RgbColor}, Drawable};
|
|
||||||
use embedded_graphics::prelude::Size;
|
|
||||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
|
||||||
use esp_backtrace as _;
|
|
||||||
use esp_hal::{
|
|
||||||
clock::ClockControl,
|
|
||||||
gpio,
|
|
||||||
gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
|
|
||||||
peripherals::{Peripherals, SPI2, SPI3},
|
|
||||||
prelude::*,
|
|
||||||
rtc_cntl::Rtc,
|
|
||||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
|
||||||
system::SystemControl,
|
|
||||||
timer::{timg::TimerGroup, OneShotTimer},
|
|
||||||
};
|
|
||||||
use esp_println::println;
|
|
||||||
use kolibri_cyd_tester_app_embassy::Debouncer;
|
|
||||||
use kolibri_embedded_gui::{button::Button, icons, label::Label, smartstate::SmartstateProvider, style::medsize_rgb565_style, ui::{Interaction, Ui}};
|
|
||||||
use kolibri_embedded_gui::helpers::keyboard::draw_keyboard;
|
|
||||||
use kolibri_embedded_gui::iconbutton::IconButton;
|
|
||||||
use kolibri_embedded_gui::spacer::Spacer;
|
|
||||||
use mipidsi::{models::{ILI9486Rgb565, ILI9486Rgb666}, options::{ColorInversion, ColorOrder, Orientation, Rotation}, Builder, Display, NoResetPin};
|
|
||||||
use static_cell::{make_static, StaticCell};
|
|
||||||
use xpt2046::Xpt2046;
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn touch_task(
|
|
||||||
touch_irq: GpioPin<36>,
|
|
||||||
spi: &'static mut NoopMutex<RefCell<Spi<'static, SPI3, FullDuplexMode>>>,
|
|
||||||
touch_cs: GpioPin<33>,
|
|
||||||
touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
|
|
||||||
) -> ! {
|
|
||||||
let mut touch_driver = Xpt2046::new(
|
|
||||||
SpiDevice::new(spi, Output::new(touch_cs, Level::Low)),
|
|
||||||
Input::new(touch_irq, Pull::Up),
|
|
||||||
xpt2046::Orientation::LandscapeFlipped,
|
|
||||||
);
|
|
||||||
touch_driver.set_num_samples(16);
|
|
||||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
|
||||||
|
|
||||||
let mut debounce = Debouncer::new();
|
|
||||||
println!("touch task");
|
|
||||||
|
|
||||||
loop {
|
|
||||||
touch_driver.run().expect("Running Touch driver failed");
|
|
||||||
if touch_driver.is_touched() {
|
|
||||||
let point = touch_driver.get_touch_point();
|
|
||||||
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
|
|
||||||
} else {
|
|
||||||
touch_signal.signal(None);
|
|
||||||
}
|
|
||||||
Timer::after(Duration::from_millis(1)).await; // 100 a second
|
|
||||||
|
|
||||||
// Your touch handling logic here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[main]
|
|
||||||
async fn main(spawner: Spawner) {
|
|
||||||
let peripherals = Peripherals::take();
|
|
||||||
let system = SystemControl::new(peripherals.SYSTEM);
|
|
||||||
let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
|
||||||
|
|
||||||
// Enable the RWDT watchdog timer:
|
|
||||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
|
||||||
rtc.rwdt.set_timeout(2.secs());
|
|
||||||
rtc.rwdt.enable();
|
|
||||||
println!("RWDT watchdog enabled!");
|
|
||||||
|
|
||||||
// Initialize the SYSTIMER peripheral, and then Embassy:
|
|
||||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
|
||||||
esp_hal_embassy::init(&clocks, timg0.timer0);
|
|
||||||
println!("Embassy initialized!");
|
|
||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
|
||||||
// let mut led = Output::new(io.pins.gpio5, Level::High);
|
|
||||||
// Initialize SPI
|
|
||||||
let sclk = io.pins.gpio14;
|
|
||||||
let miso = io.pins.gpio12;
|
|
||||||
let mosi = io.pins.gpio13;
|
|
||||||
let cs = io.pins.gpio15;
|
|
||||||
let dc = io.pins.gpio2;
|
|
||||||
let mut backlight = Output::new(io.pins.gpio21, Level::Low);
|
|
||||||
|
|
||||||
// Note: RST is not initialized as it's set to -1 in the instructions
|
|
||||||
|
|
||||||
// up to 80MHz is possible (even tho the display driver isn't supposed to be
|
|
||||||
// that fast) Dataseheet sais 10MHz, so we're gonna go with that
|
|
||||||
let mut spi = Spi::new(peripherals.SPI2, 10.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(sclk),
|
|
||||||
Some(mosi),
|
|
||||||
Some(miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
|
|
||||||
static DISP_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let spi_bus = NoopMutex::new(RefCell::new(spi));
|
|
||||||
let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
|
||||||
|
|
||||||
let di = SPIInterface::new(
|
|
||||||
SpiDevice::new(spi_bus, Output::new(cs, Level::Low)),
|
|
||||||
Output::new(dc, Level::Low),
|
|
||||||
);
|
|
||||||
let display = Builder::new(ILI9486Rgb565, di)
|
|
||||||
.orientation(Orientation {
|
|
||||||
rotation: Rotation::Deg90,
|
|
||||||
mirrored: true,
|
|
||||||
})
|
|
||||||
.color_order(ColorOrder::Bgr)
|
|
||||||
.invert_colors(ColorInversion::Inverted)
|
|
||||||
.init(&mut embassy_time::Delay)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut display = ProfilerDisplay::new(display);
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
ui.clear_background().ok();
|
|
||||||
}
|
|
||||||
backlight.set_high();
|
|
||||||
|
|
||||||
// init touchscreen pins
|
|
||||||
let touch_irq = io.pins.gpio36;
|
|
||||||
let touch_mosi = io.pins.gpio32;
|
|
||||||
let touch_miso = io.pins.gpio39;
|
|
||||||
let touch_clk = io.pins.gpio25;
|
|
||||||
let touch_cs = io.pins.gpio33;
|
|
||||||
|
|
||||||
// 2MHz is the MAX! DO NOT DECREASE! This is really important.
|
|
||||||
let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(touch_clk),
|
|
||||||
Some(touch_mosi),
|
|
||||||
Some(touch_miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
static TOUCH_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI3, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let touch_spi_bus = NoopMutex::new(RefCell::new(touch_spi));
|
|
||||||
let touch_spi_bus = TOUCH_SPI_BUS.init(touch_spi_bus);
|
|
||||||
|
|
||||||
let touch_signal = Signal::new();
|
|
||||||
static TOUCH_SIGNAL: StaticCell<Signal<NoopRawMutex, Option<Point>>> = StaticCell::new();
|
|
||||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
|
||||||
|
|
||||||
spawner
|
|
||||||
.spawn(touch_task(touch_irq, touch_spi_bus, touch_cs, touch_signal))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// init RGB LED pins
|
|
||||||
|
|
||||||
let mut red_led = Output::new(io.pins.gpio4, Level::High);
|
|
||||||
let mut green_led = Output::new(io.pins.gpio16, Level::High);
|
|
||||||
let mut blue_led = Output::new(io.pins.gpio17, Level::High);
|
|
||||||
|
|
||||||
// init SD card pins
|
|
||||||
let sd_miso = io.pins.gpio19;
|
|
||||||
let sd_mosi = io.pins.gpio23;
|
|
||||||
let sd_sck = io.pins.gpio18;
|
|
||||||
let sd_cs = io.pins.gpio5;
|
|
||||||
|
|
||||||
// TODO: Spawn some tasks
|
|
||||||
let _ = spawner;
|
|
||||||
|
|
||||||
let mut last_touch = None;
|
|
||||||
|
|
||||||
static BUF_CELL: StaticCell<[Rgb565; 100 * 100]> = StaticCell::new();
|
|
||||||
let buf = BUF_CELL.init([Rgb565::BLACK; 100 * 100]);
|
|
||||||
|
|
||||||
// Periodically feed the RWDT watchdog timer when our tasks are not running:
|
|
||||||
let mut sm = SmartstateProvider::<20>::new();
|
|
||||||
let mut ui_data = UiData {
|
|
||||||
timer_started: false,
|
|
||||||
timer_duration: Duration::from_secs(30),
|
|
||||||
timer_start_time: Instant::now(),
|
|
||||||
};
|
|
||||||
loop {
|
|
||||||
let start_time = embassy_time::Instant::now();
|
|
||||||
sm.restart_counter();
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
ui.set_buffer(buf);
|
|
||||||
if let Some(touch) = touch_signal.try_take() {
|
|
||||||
let interact = match (touch, last_touch) {
|
|
||||||
(Some(point), Some(_)) => Interaction::Drag(point),
|
|
||||||
(Some(point), None) => Interaction::Click(point),
|
|
||||||
(None, Some(point)) => Interaction::Release(point),
|
|
||||||
(None, None) => Interaction::None,
|
|
||||||
};
|
|
||||||
ui.interact(interact);
|
|
||||||
// println!("{:?}, {:?}, {:?}", last_touch, touch, interact);
|
|
||||||
|
|
||||||
last_touch = touch;
|
|
||||||
}
|
|
||||||
let start_draw_time = embassy_time::Instant::now();
|
|
||||||
do_ui(&mut sm, &mut ui, &mut ui_data);
|
|
||||||
let end_time = embassy_time::Instant::now();
|
|
||||||
let draw_time = display.get_time();
|
|
||||||
let prep_time = start_draw_time - start_time;
|
|
||||||
let proc_time = end_time - start_draw_time;
|
|
||||||
let proc_time = proc_time - min(draw_time, proc_time);
|
|
||||||
rtc.rwdt.feed();
|
|
||||||
|
|
||||||
if draw_time.as_micros() > 0 {
|
|
||||||
println!(
|
|
||||||
"draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms ",
|
|
||||||
draw_time.as_millis(),
|
|
||||||
draw_time.as_micros() % 100,
|
|
||||||
prep_time.as_millis(),
|
|
||||||
prep_time.as_micros() % 100,
|
|
||||||
proc_time.as_millis(),
|
|
||||||
proc_time.as_micros() % 100,
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
display.reset_time();
|
|
||||||
Timer::after(Duration::from_millis(17)).await; // 60 a second
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UiData {
|
|
||||||
timer_started: bool,
|
|
||||||
timer_duration: Duration,
|
|
||||||
timer_start_time: Instant,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_ui<DISP: DrawTarget<Color=Rgb565>>(sm: &mut SmartstateProvider<20>, ui: &mut Ui<DISP, Rgb565>, &mut UiData) {
|
|
||||||
ui.sub_ui(|ui| {
|
|
||||||
ui.style_mut().default_font = ascii::FONT_9X18_BOLD;
|
|
||||||
ui.add(Label::new("Timer").smartstate(sm.next()));
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
ui.add(Spacer::new(Size::new(0, 16)));
|
|
||||||
ui.add(Spacer::new(Size::new(0, 32)));
|
|
||||||
ui.add_horizontal(IconButton::new(icons::size32px::music::Play).smartstate(sm.next()));
|
|
||||||
ui.add(Button::new("And pretty nicely!").smartstate(sm.next()));
|
|
||||||
}
|
|
@ -1,468 +0,0 @@
|
|||||||
#![no_std]
|
|
||||||
#![no_main]
|
|
||||||
|
|
||||||
use core::{cell::RefCell, cmp::min, fmt};
|
|
||||||
|
|
||||||
use display_interface_spi::SPIInterface;
|
|
||||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
|
||||||
use embassy_executor::Spawner;
|
|
||||||
use embassy_sync::{
|
|
||||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
|
||||||
signal::Signal,
|
|
||||||
};
|
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
|
||||||
use embedded_graphics::{
|
|
||||||
mono_font::ascii,
|
|
||||||
pixelcolor::Rgb565,
|
|
||||||
prelude::{DrawTarget, Point, RgbColor, Size, WebColors},
|
|
||||||
};
|
|
||||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
|
||||||
use esp_backtrace as _;
|
|
||||||
use esp_hal::{
|
|
||||||
clock::ClockControl,
|
|
||||||
gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
|
|
||||||
peripherals::{Peripherals, SPI2, SPI3},
|
|
||||||
prelude::*,
|
|
||||||
rtc_cntl::Rtc,
|
|
||||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
|
||||||
system::SystemControl,
|
|
||||||
timer::timg::TimerGroup,
|
|
||||||
};
|
|
||||||
use esp_println::println;
|
|
||||||
use kolibri_cyd_tester_app_embassy::Debouncer;
|
|
||||||
use kolibri_embedded_gui::{
|
|
||||||
button::Button,
|
|
||||||
checkbox::Checkbox,
|
|
||||||
icon::IconWidget,
|
|
||||||
iconbutton::IconButton,
|
|
||||||
icons::{size12px, size24px, size32px, size48px, size96px},
|
|
||||||
label::Label,
|
|
||||||
smartstate::SmartstateProvider,
|
|
||||||
spacer::Spacer,
|
|
||||||
style::medsize_rgb565_style,
|
|
||||||
ui::{Interaction, Ui},
|
|
||||||
};
|
|
||||||
use mipidsi::{
|
|
||||||
models::ILI9486Rgb565,
|
|
||||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
|
||||||
Builder,
|
|
||||||
};
|
|
||||||
use static_cell::StaticCell;
|
|
||||||
use xpt2046::Xpt2046;
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn touch_task(
|
|
||||||
touch_irq: GpioPin<36>,
|
|
||||||
spi: &'static mut NoopMutex<RefCell<Spi<'static, SPI3, FullDuplexMode>>>,
|
|
||||||
touch_cs: GpioPin<33>,
|
|
||||||
touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
|
|
||||||
) -> ! {
|
|
||||||
let mut touch_driver = Xpt2046::new(
|
|
||||||
SpiDevice::new(spi, Output::new(touch_cs, Level::Low)),
|
|
||||||
Input::new(touch_irq, Pull::Up),
|
|
||||||
xpt2046::Orientation::LandscapeFlipped,
|
|
||||||
);
|
|
||||||
touch_driver.set_num_samples(16);
|
|
||||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
|
||||||
|
|
||||||
println!("touch task");
|
|
||||||
|
|
||||||
loop {
|
|
||||||
touch_driver.run().expect("Running Touch driver failed");
|
|
||||||
if touch_driver.is_touched() {
|
|
||||||
let point = touch_driver.get_touch_point();
|
|
||||||
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
|
|
||||||
} else {
|
|
||||||
touch_signal.signal(None);
|
|
||||||
}
|
|
||||||
Timer::after(Duration::from_millis(1)).await; // 100 a second
|
|
||||||
|
|
||||||
// Your touch handling logic here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AppData {
|
|
||||||
timer_start: Instant,
|
|
||||||
timer_set_duration: Duration,
|
|
||||||
timer_remaining_duration: Duration,
|
|
||||||
timer_running: bool,
|
|
||||||
timer_paused: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppData {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
timer_start: Instant::now(),
|
|
||||||
timer_set_duration: Duration::from_secs(10),
|
|
||||||
timer_remaining_duration: Duration::from_secs(10),
|
|
||||||
timer_running: false,
|
|
||||||
timer_paused: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_timer_duration(&mut self, duration: Duration) {
|
|
||||||
self.timer_set_duration = duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_secs(&mut self, secs: u64) {
|
|
||||||
self.set_timer_duration(
|
|
||||||
self.timer_set_duration
|
|
||||||
.checked_add(Duration::from_secs(secs))
|
|
||||||
.unwrap_or(Duration::from_secs(5999))
|
|
||||||
.min(Duration::from_secs(5999)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sub_secs(&mut self, secs: u64) {
|
|
||||||
self.set_timer_duration(
|
|
||||||
self.timer_set_duration
|
|
||||||
.checked_sub(Duration::from_secs(secs))
|
|
||||||
.unwrap_or(Duration::from_secs(10))
|
|
||||||
.max(Duration::from_secs(10)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_timer(&mut self) {
|
|
||||||
if !self.timer_paused {
|
|
||||||
self.timer_remaining_duration = self.timer_set_duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.timer_start = Instant::now();
|
|
||||||
self.timer_running = true;
|
|
||||||
self.timer_paused = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pause_timer(&mut self) {
|
|
||||||
self.timer_paused = true;
|
|
||||||
self.timer_remaining_duration = self
|
|
||||||
.timer_remaining_duration
|
|
||||||
.checked_sub(self.timer_start.elapsed())
|
|
||||||
.unwrap_or(Duration::from_secs(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_timer(&mut self) {
|
|
||||||
self.timer_start = Instant::now();
|
|
||||||
self.timer_paused = false;
|
|
||||||
self.timer_running = false;
|
|
||||||
self.timer_remaining_duration = self.timer_set_duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remaining(&self) -> Duration {
|
|
||||||
if self.timer_stopped() {
|
|
||||||
self.timer_set_duration
|
|
||||||
} else if self.timer_paused() {
|
|
||||||
self.timer_remaining_duration
|
|
||||||
} else {
|
|
||||||
self.timer_remaining_duration
|
|
||||||
.checked_sub(self.timer_start.elapsed())
|
|
||||||
.unwrap_or(Duration::from_secs(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn timer_stopped(&self) -> bool {
|
|
||||||
!self.timer_running
|
|
||||||
}
|
|
||||||
|
|
||||||
fn timer_paused(&self) -> bool {
|
|
||||||
self.timer_running && self.timer_paused
|
|
||||||
}
|
|
||||||
|
|
||||||
fn timer_running(&self) -> bool {
|
|
||||||
self.timer_running && !self.timer_paused
|
|
||||||
}
|
|
||||||
|
|
||||||
fn timer_finished(&self) -> bool {
|
|
||||||
self.timer_running && self.remaining() == Duration::from_secs(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[main]
|
|
||||||
async fn main(spawner: Spawner) {
|
|
||||||
let peripherals = Peripherals::take();
|
|
||||||
let system = SystemControl::new(peripherals.SYSTEM);
|
|
||||||
let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
|
||||||
|
|
||||||
// Enable the RWDT watchdog timer:
|
|
||||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
|
||||||
rtc.rwdt.set_timeout(2.secs());
|
|
||||||
rtc.rwdt.enable();
|
|
||||||
println!("RWDT watchdog enabled!");
|
|
||||||
|
|
||||||
// Initialize the SYSTIMER peripheral, and then Embassy:
|
|
||||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
|
||||||
esp_hal_embassy::init(&clocks, timg0.timer0);
|
|
||||||
println!("Embassy initialized!");
|
|
||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
|
||||||
// let mut led = Output::new(io.pins.gpio5, Level::High);
|
|
||||||
// Initialize SPI
|
|
||||||
let sclk = io.pins.gpio14;
|
|
||||||
let miso = io.pins.gpio12;
|
|
||||||
let mosi = io.pins.gpio13;
|
|
||||||
let cs = io.pins.gpio15;
|
|
||||||
let dc = io.pins.gpio2;
|
|
||||||
let mut backlight = Output::new(io.pins.gpio21, Level::Low);
|
|
||||||
|
|
||||||
// Note: RST is not initialized as it's set to -1 in the instructions
|
|
||||||
|
|
||||||
// up to 80MHz is possible (even tho the display driver isn't supposed to be
|
|
||||||
// that fast) Dataseheet sais 10MHz, so we're gonna go with that
|
|
||||||
let mut spi = Spi::new(peripherals.SPI2, 10.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(sclk),
|
|
||||||
Some(mosi),
|
|
||||||
Some(miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
|
|
||||||
static DISP_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let spi_bus = NoopMutex::new(RefCell::new(spi));
|
|
||||||
let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
|
||||||
|
|
||||||
let di = SPIInterface::new(
|
|
||||||
SpiDevice::new(spi_bus, Output::new(cs, Level::Low)),
|
|
||||||
Output::new(dc, Level::Low),
|
|
||||||
);
|
|
||||||
let display = Builder::new(ILI9486Rgb565, di)
|
|
||||||
.orientation(Orientation {
|
|
||||||
rotation: Rotation::Deg90,
|
|
||||||
mirrored: true,
|
|
||||||
})
|
|
||||||
.color_order(ColorOrder::Bgr)
|
|
||||||
.invert_colors(ColorInversion::Inverted)
|
|
||||||
.init(&mut embassy_time::Delay)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut display = ProfilerDisplay::new(display);
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
ui.clear_background().ok();
|
|
||||||
}
|
|
||||||
backlight.set_high();
|
|
||||||
|
|
||||||
// init touchscreen pins
|
|
||||||
let touch_irq = io.pins.gpio36;
|
|
||||||
let touch_mosi = io.pins.gpio32;
|
|
||||||
let touch_miso = io.pins.gpio39;
|
|
||||||
let touch_clk = io.pins.gpio25;
|
|
||||||
let touch_cs = io.pins.gpio33;
|
|
||||||
|
|
||||||
// 2MHz is the MAX! DO NOT DECREASE! This is really important.
|
|
||||||
let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(touch_clk),
|
|
||||||
Some(touch_mosi),
|
|
||||||
Some(touch_miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
static TOUCH_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI3, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let touch_spi_bus = NoopMutex::new(RefCell::new(touch_spi));
|
|
||||||
let touch_spi_bus = TOUCH_SPI_BUS.init(touch_spi_bus);
|
|
||||||
|
|
||||||
let touch_signal = Signal::new();
|
|
||||||
static TOUCH_SIGNAL: StaticCell<Signal<NoopRawMutex, Option<Point>>> = StaticCell::new();
|
|
||||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
|
||||||
|
|
||||||
spawner
|
|
||||||
.spawn(touch_task(touch_irq, touch_spi_bus, touch_cs, touch_signal))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// TODO: Spawn some tasks
|
|
||||||
let _ = spawner;
|
|
||||||
|
|
||||||
// variables
|
|
||||||
let mut appdata = AppData::new();
|
|
||||||
let (mut prev_mins, mut prev_secs, mut prev_millis) = (0, 0, 0);
|
|
||||||
let mut finished = false;
|
|
||||||
|
|
||||||
// touchpoints
|
|
||||||
|
|
||||||
let mut last_touch = None;
|
|
||||||
|
|
||||||
static BUF_CELL: StaticCell<[Rgb565; 100 * 100]> = StaticCell::new();
|
|
||||||
let buf = BUF_CELL.init([Rgb565::BLACK; 100 * 100]);
|
|
||||||
|
|
||||||
let mut textbuf = [0u8; 64];
|
|
||||||
|
|
||||||
// Periodically feed the RWDT watchdog timer when our tasks are not running:
|
|
||||||
let mut sm = SmartstateProvider::<20>::new();
|
|
||||||
loop {
|
|
||||||
// SMART REDRAWING ENABLE / DISABLE
|
|
||||||
// sm.force_redraw_all();
|
|
||||||
|
|
||||||
let start_time = embassy_time::Instant::now();
|
|
||||||
sm.restart_counter();
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
if let Some(touch) = touch_signal.try_take() {
|
|
||||||
let interact = match (touch, last_touch) {
|
|
||||||
(Some(point), Some(_)) => Interaction::Drag(point),
|
|
||||||
(Some(point), None) => Interaction::Click(point),
|
|
||||||
(None, Some(point)) => Interaction::Release(point),
|
|
||||||
(None, None) => Interaction::None,
|
|
||||||
};
|
|
||||||
ui.interact(interact);
|
|
||||||
// println!("{:?}, {:?}, {:?}", last_touch, touch, interact);
|
|
||||||
|
|
||||||
last_touch = touch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BUFFER ENABLE/DISABLE
|
|
||||||
ui.set_buffer(buf);
|
|
||||||
|
|
||||||
let start_draw_time = embassy_time::Instant::now();
|
|
||||||
ui.sub_ui(|ui| {
|
|
||||||
ui.style_mut().default_font = ascii::FONT_9X18_BOLD;
|
|
||||||
ui.add(Label::new("Kolibri Timer App").smartstate(sm.next()));
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
let remaining = appdata.remaining();
|
|
||||||
|
|
||||||
ui.add(Spacer::new(Size::new(0, 60)));
|
|
||||||
ui.add_horizontal(Spacer::new(Size::new(80, 0)));
|
|
||||||
ui.sub_ui(|ui| {
|
|
||||||
ui.style_mut().default_font = ascii::FONT_10X20;
|
|
||||||
if remaining.as_secs() / 60 != prev_mins {
|
|
||||||
sm.peek().force_redraw();
|
|
||||||
prev_mins = remaining.as_secs() / 60;
|
|
||||||
}
|
|
||||||
ui.add_horizontal(
|
|
||||||
Label::new(
|
|
||||||
&format_no_std::show(
|
|
||||||
&mut textbuf,
|
|
||||||
format_args!("{:02}", remaining.as_secs() / 60),
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.smartstate(sm.next()),
|
|
||||||
);
|
|
||||||
ui.add_horizontal(Label::new(":").smartstate(sm.next()));
|
|
||||||
|
|
||||||
if remaining.as_secs() % 60 != prev_secs {
|
|
||||||
sm.peek().force_redraw();
|
|
||||||
prev_secs = remaining.as_secs() % 60;
|
|
||||||
}
|
|
||||||
ui.add_horizontal(
|
|
||||||
Label::new(
|
|
||||||
&format_no_std::show(
|
|
||||||
&mut textbuf,
|
|
||||||
format_args!("{:02}", remaining.as_secs() % 60),
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.smartstate(sm.next()),
|
|
||||||
);
|
|
||||||
ui.add_horizontal(Label::new(":").smartstate(sm.next()));
|
|
||||||
|
|
||||||
if remaining.as_millis() % 1000 != prev_millis {
|
|
||||||
sm.peek().force_redraw();
|
|
||||||
prev_millis = remaining.as_millis() % 1000;
|
|
||||||
}
|
|
||||||
ui.add(
|
|
||||||
Label::new(
|
|
||||||
&format_no_std::show(
|
|
||||||
&mut textbuf,
|
|
||||||
format_args!("{:03}", remaining.as_millis() % 1000),
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.smartstate(sm.next()),
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
ui.add_horizontal(Spacer::new(Size::new(65, 0)));
|
|
||||||
ui.sub_ui(|ui| {
|
|
||||||
if appdata.timer_running() {
|
|
||||||
ui.style_mut().icon_color = Rgb565::CSS_LIGHT_GRAY;
|
|
||||||
}
|
|
||||||
if ui
|
|
||||||
.add_horizontal(IconButton::new(size32px::actions::AddCircle).smartstate(sm.next()))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
if !appdata.timer_running() {
|
|
||||||
appdata.add_secs(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ui.add_horizontal(Label::new("+/- 10s").smartstate(sm.next()));
|
|
||||||
if ui
|
|
||||||
.add(IconButton::new(size32px::actions::MinusCircle).smartstate(sm.next()))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
if !appdata.timer_running() {
|
|
||||||
appdata.sub_secs(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
ui.add_horizontal(Spacer::new(Size::new(80, 0)));
|
|
||||||
if ui
|
|
||||||
.add_horizontal(IconButton::new(size48px::actions::Undo).smartstate(sm.next()))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
appdata.reset_timer();
|
|
||||||
sm.force_redraw_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
if !finished && appdata.timer_finished() {
|
|
||||||
sm.peek().force_redraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
if appdata.timer_finished() {
|
|
||||||
if ui
|
|
||||||
.add_horizontal(
|
|
||||||
IconButton::new(size48px::actions::RemoveSquare).smartstate(sm.next()),
|
|
||||||
)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
appdata.reset_timer();
|
|
||||||
sm.force_redraw_all();
|
|
||||||
}
|
|
||||||
} else if appdata.timer_running() {
|
|
||||||
if ui
|
|
||||||
.add_horizontal(IconButton::new(size48px::music::Pause).smartstate(sm.next()))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
appdata.pause_timer();
|
|
||||||
sm.force_redraw_all();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ui
|
|
||||||
.add_horizontal(IconButton::new(size48px::music::Play).smartstate(sm.next()))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
appdata.start_timer();
|
|
||||||
sm.force_redraw_all();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finished = appdata.timer_finished();
|
|
||||||
|
|
||||||
let end_time = embassy_time::Instant::now();
|
|
||||||
let draw_time = display.get_time();
|
|
||||||
let prep_time = start_draw_time - start_time;
|
|
||||||
let proc_time = end_time - start_draw_time;
|
|
||||||
let proc_time = proc_time - min(draw_time, proc_time);
|
|
||||||
rtc.rwdt.feed();
|
|
||||||
|
|
||||||
if draw_time.as_micros() > 0 {
|
|
||||||
println!(
|
|
||||||
"draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms | total time: {}.{:03}ms",
|
|
||||||
draw_time.as_millis(),
|
|
||||||
draw_time.as_micros() % 100,
|
|
||||||
prep_time.as_millis(),
|
|
||||||
prep_time.as_micros() % 100,
|
|
||||||
proc_time.as_millis(),
|
|
||||||
proc_time.as_micros() % 100,
|
|
||||||
(draw_time + prep_time + proc_time).as_millis(),
|
|
||||||
(draw_time + prep_time + proc_time).as_micros() % 100, );
|
|
||||||
}
|
|
||||||
display.reset_time();
|
|
||||||
Timer::after(Duration::from_millis(17)).await; // 60 a second
|
|
||||||
}
|
|
||||||
}
|
|
@ -219,12 +219,11 @@ async fn main(spawner: Spawner) {
|
|||||||
.ok();
|
.ok();
|
||||||
ui.add_horizontal(Button::new("Works!").smartstate(sm.next()));
|
ui.add_horizontal(Button::new("Works!").smartstate(sm.next()));
|
||||||
ui.add(Button::new("And pretty nicely!").smartstate(sm.next()));
|
ui.add(Button::new("And pretty nicely!").smartstate(sm.next()));
|
||||||
let end_time = embassy_time::Instant::now();
|
rtc.rwdt.feed();
|
||||||
let draw_time = display.get_time();
|
let draw_time = display.get_time();
|
||||||
let prep_time = start_draw_time - start_time;
|
let prep_time = start_draw_time - start_time;
|
||||||
let proc_time = end_time - start_draw_time;
|
let proc_time = embassy_time::Instant::now() - start_draw_time;
|
||||||
let proc_time = proc_time - min(draw_time, proc_time);
|
let proc_time = proc_time - min(draw_time, proc_time);
|
||||||
rtc.rwdt.feed();
|
|
||||||
|
|
||||||
if draw_time.as_micros() > 0 {
|
if draw_time.as_micros() > 0 {
|
||||||
println!(
|
println!(
|
||||||
|
@ -1,261 +0,0 @@
|
|||||||
#![no_std]
|
|
||||||
#![no_main]
|
|
||||||
|
|
||||||
use core::{cell::RefCell, cmp::min};
|
|
||||||
|
|
||||||
use display_interface_spi::SPIInterface;
|
|
||||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
|
||||||
use embassy_executor::Spawner;
|
|
||||||
use embassy_sync::{
|
|
||||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
|
||||||
signal::Signal,
|
|
||||||
};
|
|
||||||
use embassy_time::{Duration, Timer};
|
|
||||||
use embedded_graphics::{
|
|
||||||
mono_font::ascii,
|
|
||||||
pixelcolor::Rgb565,
|
|
||||||
prelude::{DrawTarget, Point, RgbColor},
|
|
||||||
};
|
|
||||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
|
||||||
use esp_backtrace as _;
|
|
||||||
use esp_hal::{
|
|
||||||
clock::ClockControl,
|
|
||||||
gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
|
|
||||||
peripherals::{Peripherals, SPI2, SPI3},
|
|
||||||
prelude::*,
|
|
||||||
rtc_cntl::Rtc,
|
|
||||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
|
||||||
system::SystemControl,
|
|
||||||
timer::timg::TimerGroup,
|
|
||||||
};
|
|
||||||
use esp_println::println;
|
|
||||||
use kolibri_cyd_tester_app_embassy::Debouncer;
|
|
||||||
use kolibri_embedded_gui::{
|
|
||||||
button::Button,
|
|
||||||
checkbox::Checkbox,
|
|
||||||
icon::IconWidget,
|
|
||||||
iconbutton::IconButton,
|
|
||||||
icons::{size12px, size24px, size32px, size48px, size96px},
|
|
||||||
label::Label,
|
|
||||||
smartstate::SmartstateProvider,
|
|
||||||
style::medsize_rgb565_style,
|
|
||||||
ui::{Interaction, Ui},
|
|
||||||
};
|
|
||||||
use mipidsi::{
|
|
||||||
models::ILI9486Rgb565,
|
|
||||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
|
||||||
Builder,
|
|
||||||
};
|
|
||||||
use static_cell::StaticCell;
|
|
||||||
use xpt2046::Xpt2046;
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn touch_task(
|
|
||||||
touch_irq: GpioPin<36>,
|
|
||||||
spi: &'static mut NoopMutex<RefCell<Spi<'static, SPI3, FullDuplexMode>>>,
|
|
||||||
touch_cs: GpioPin<33>,
|
|
||||||
touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
|
|
||||||
) -> ! {
|
|
||||||
let mut touch_driver = Xpt2046::new(
|
|
||||||
SpiDevice::new(spi, Output::new(touch_cs, Level::Low)),
|
|
||||||
Input::new(touch_irq, Pull::Up),
|
|
||||||
xpt2046::Orientation::LandscapeFlipped,
|
|
||||||
);
|
|
||||||
touch_driver.set_num_samples(16);
|
|
||||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
|
||||||
|
|
||||||
let mut debounce = Debouncer::new();
|
|
||||||
println!("touch task");
|
|
||||||
|
|
||||||
loop {
|
|
||||||
touch_driver.run().expect("Running Touch driver failed");
|
|
||||||
if touch_driver.is_touched() {
|
|
||||||
let point = touch_driver.get_touch_point();
|
|
||||||
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
|
|
||||||
} else {
|
|
||||||
touch_signal.signal(None);
|
|
||||||
}
|
|
||||||
Timer::after(Duration::from_millis(1)).await; // 100 a second
|
|
||||||
|
|
||||||
// Your touch handling logic here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[main]
|
|
||||||
async fn main(spawner: Spawner) {
|
|
||||||
let peripherals = Peripherals::take();
|
|
||||||
let system = SystemControl::new(peripherals.SYSTEM);
|
|
||||||
let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
|
||||||
|
|
||||||
// Enable the RWDT watchdog timer:
|
|
||||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
|
||||||
rtc.rwdt.set_timeout(2.secs());
|
|
||||||
rtc.rwdt.enable();
|
|
||||||
println!("RWDT watchdog enabled!");
|
|
||||||
|
|
||||||
// Initialize the SYSTIMER peripheral, and then Embassy:
|
|
||||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
|
||||||
esp_hal_embassy::init(&clocks, timg0.timer0);
|
|
||||||
println!("Embassy initialized!");
|
|
||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
|
||||||
// let mut led = Output::new(io.pins.gpio5, Level::High);
|
|
||||||
// Initialize SPI
|
|
||||||
let sclk = io.pins.gpio14;
|
|
||||||
let miso = io.pins.gpio12;
|
|
||||||
let mosi = io.pins.gpio13;
|
|
||||||
let cs = io.pins.gpio15;
|
|
||||||
let dc = io.pins.gpio2;
|
|
||||||
let mut backlight = Output::new(io.pins.gpio21, Level::Low);
|
|
||||||
|
|
||||||
// Note: RST is not initialized as it's set to -1 in the instructions
|
|
||||||
|
|
||||||
// up to 80MHz is possible (even tho the display driver isn't supposed to be
|
|
||||||
// that fast) Dataseheet sais 10MHz, so we're gonna go with that
|
|
||||||
let mut spi = Spi::new(peripherals.SPI2, 10.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(sclk),
|
|
||||||
Some(mosi),
|
|
||||||
Some(miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
|
|
||||||
static DISP_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let spi_bus = NoopMutex::new(RefCell::new(spi));
|
|
||||||
let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
|
||||||
|
|
||||||
let di = SPIInterface::new(
|
|
||||||
SpiDevice::new(spi_bus, Output::new(cs, Level::Low)),
|
|
||||||
Output::new(dc, Level::Low),
|
|
||||||
);
|
|
||||||
let display = Builder::new(ILI9486Rgb565, di)
|
|
||||||
.orientation(Orientation {
|
|
||||||
rotation: Rotation::Deg90,
|
|
||||||
mirrored: true,
|
|
||||||
})
|
|
||||||
.color_order(ColorOrder::Bgr)
|
|
||||||
.invert_colors(ColorInversion::Inverted)
|
|
||||||
.init(&mut embassy_time::Delay)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut display = ProfilerDisplay::new(display);
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
ui.clear_background().ok();
|
|
||||||
}
|
|
||||||
backlight.set_high();
|
|
||||||
|
|
||||||
// init touchscreen pins
|
|
||||||
let touch_irq = io.pins.gpio36;
|
|
||||||
let touch_mosi = io.pins.gpio32;
|
|
||||||
let touch_miso = io.pins.gpio39;
|
|
||||||
let touch_clk = io.pins.gpio25;
|
|
||||||
let touch_cs = io.pins.gpio33;
|
|
||||||
|
|
||||||
// 2MHz is the MAX! DO NOT DECREASE! This is really important.
|
|
||||||
let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(touch_clk),
|
|
||||||
Some(touch_mosi),
|
|
||||||
Some(touch_miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
static TOUCH_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI3, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let touch_spi_bus = NoopMutex::new(RefCell::new(touch_spi));
|
|
||||||
let touch_spi_bus = TOUCH_SPI_BUS.init(touch_spi_bus);
|
|
||||||
|
|
||||||
let touch_signal = Signal::new();
|
|
||||||
static TOUCH_SIGNAL: StaticCell<Signal<NoopRawMutex, Option<Point>>> = StaticCell::new();
|
|
||||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
|
||||||
|
|
||||||
spawner
|
|
||||||
.spawn(touch_task(touch_irq, touch_spi_bus, touch_cs, touch_signal))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// TODO: Spawn some tasks
|
|
||||||
let _ = spawner;
|
|
||||||
|
|
||||||
// variables
|
|
||||||
let mut checked = false;
|
|
||||||
|
|
||||||
// touchpoints
|
|
||||||
|
|
||||||
let mut last_touch = None;
|
|
||||||
|
|
||||||
static BUF_CELL: StaticCell<[Rgb565; 100 * 100]> = StaticCell::new();
|
|
||||||
let buf = BUF_CELL.init([Rgb565::BLACK; 100 * 100]);
|
|
||||||
|
|
||||||
// Periodically feed the RWDT watchdog timer when our tasks are not running:
|
|
||||||
let mut sm = SmartstateProvider::<20>::new();
|
|
||||||
loop {
|
|
||||||
// SMART REDRAWING ENABLE / DISABLE
|
|
||||||
// sm.force_redraw_all();
|
|
||||||
|
|
||||||
let start_time = embassy_time::Instant::now();
|
|
||||||
sm.restart_counter();
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
if let Some(touch) = touch_signal.try_take() {
|
|
||||||
let interact = match (touch, last_touch) {
|
|
||||||
(Some(point), Some(_)) => Interaction::Drag(point),
|
|
||||||
(Some(point), None) => Interaction::Click(point),
|
|
||||||
(None, Some(point)) => Interaction::Release(point),
|
|
||||||
(None, None) => Interaction::None,
|
|
||||||
};
|
|
||||||
ui.interact(interact);
|
|
||||||
// println!("{:?}, {:?}, {:?}", last_touch, touch, interact);
|
|
||||||
|
|
||||||
last_touch = touch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BUFFER ENABLE/DISABLE
|
|
||||||
// ui.set_buffer(buf);
|
|
||||||
|
|
||||||
let start_draw_time = embassy_time::Instant::now();
|
|
||||||
ui.sub_ui(|ui| {
|
|
||||||
ui.style_mut().default_font = ascii::FONT_9X18_BOLD;
|
|
||||||
ui.add(Label::new("Optimizations Performance Test").smartstate(sm.next()));
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
ui.add_horizontal(Button::new("Button 1").smartstate(sm.next()));
|
|
||||||
ui.add(Button::new("Button 2").smartstate(sm.next()));
|
|
||||||
ui.add_horizontal(IconButton::new(size32px::actions::AddCircle).smartstate(sm.next()));
|
|
||||||
ui.add_horizontal(Label::new("Add / Remove").smartstate(sm.next()));
|
|
||||||
ui.add(IconButton::new(size32px::actions::RemoveSquare).smartstate(sm.next()));
|
|
||||||
ui.add_horizontal(Label::new("Check this Checkbox: ").smartstate(sm.next()));
|
|
||||||
ui.add(Checkbox::new(&mut checked).smartstate(sm.next()));
|
|
||||||
|
|
||||||
ui.add(Label::new("Some Icons: ").smartstate(sm.next()));
|
|
||||||
|
|
||||||
ui.add_horizontal(IconWidget::new(size12px::actions::AddCircle).smartstate(sm.next()));
|
|
||||||
ui.add_horizontal(IconWidget::new(size24px::actions::OpenNewWindow).smartstate(sm.next()));
|
|
||||||
ui.add_horizontal(IconWidget::new(size32px::actions::Cancel).smartstate(sm.next()));
|
|
||||||
ui.add_horizontal(IconWidget::new(size48px::actions::Download).smartstate(sm.next()));
|
|
||||||
ui.add_horizontal(
|
|
||||||
IconWidget::new(size96px::actions::SaveActionFloppy).smartstate(sm.next()),
|
|
||||||
);
|
|
||||||
|
|
||||||
let end_time = embassy_time::Instant::now();
|
|
||||||
let draw_time = display.get_time();
|
|
||||||
let prep_time = start_draw_time - start_time;
|
|
||||||
let proc_time = end_time - start_draw_time;
|
|
||||||
let proc_time = proc_time - min(draw_time, proc_time);
|
|
||||||
rtc.rwdt.feed();
|
|
||||||
|
|
||||||
if draw_time.as_micros() > 0 {
|
|
||||||
println!(
|
|
||||||
"draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms | total time: {}.{:03}ms",
|
|
||||||
draw_time.as_millis(),
|
|
||||||
draw_time.as_micros() % 100,
|
|
||||||
prep_time.as_millis(),
|
|
||||||
prep_time.as_micros() % 100,
|
|
||||||
proc_time.as_millis(),
|
|
||||||
proc_time.as_micros() % 100,
|
|
||||||
(draw_time + prep_time + proc_time).as_millis(),
|
|
||||||
(draw_time + prep_time + proc_time).as_micros() % 100, );
|
|
||||||
}
|
|
||||||
display.reset_time();
|
|
||||||
Timer::after(Duration::from_millis(17)).await; // 60 a second
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,270 +0,0 @@
|
|||||||
#![no_std]
|
|
||||||
#![no_main]
|
|
||||||
|
|
||||||
use core::{cell::RefCell, cmp::min};
|
|
||||||
|
|
||||||
use display_interface_spi::SPIInterface;
|
|
||||||
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
|
|
||||||
use embassy_executor::Spawner;
|
|
||||||
use embassy_sync::{
|
|
||||||
blocking_mutex::{raw::NoopRawMutex, NoopMutex},
|
|
||||||
signal::Signal,
|
|
||||||
};
|
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
|
||||||
use embedded_graphics::{
|
|
||||||
mono_font::ascii,
|
|
||||||
pixelcolor::Rgb565,
|
|
||||||
prelude::{DrawTarget, Point, RgbColor, Size},
|
|
||||||
Drawable,
|
|
||||||
};
|
|
||||||
use embedded_graphics_profiler_display::ProfilerDisplay;
|
|
||||||
use esp_backtrace as _;
|
|
||||||
use esp_hal::{
|
|
||||||
clock::ClockControl,
|
|
||||||
gpio,
|
|
||||||
gpio::{GpioPin, Input, Io, Level, Output, Pull, NO_PIN},
|
|
||||||
peripherals::{Peripherals, SPI2, SPI3},
|
|
||||||
prelude::*,
|
|
||||||
rtc_cntl::Rtc,
|
|
||||||
spi::{master::Spi, FullDuplexMode, SpiMode},
|
|
||||||
system::SystemControl,
|
|
||||||
timer::{timg::TimerGroup, OneShotTimer},
|
|
||||||
};
|
|
||||||
use esp_println::println;
|
|
||||||
use kolibri_cyd_tester_app_embassy::Debouncer;
|
|
||||||
use kolibri_embedded_gui::{
|
|
||||||
button::Button,
|
|
||||||
helpers::keyboard::draw_keyboard,
|
|
||||||
iconbutton::IconButton,
|
|
||||||
icons,
|
|
||||||
label::Label,
|
|
||||||
smartstate::SmartstateProvider,
|
|
||||||
spacer::Spacer,
|
|
||||||
style::medsize_rgb565_style,
|
|
||||||
ui::{Interaction, Ui},
|
|
||||||
};
|
|
||||||
use mipidsi::{
|
|
||||||
models::{ILI9486Rgb565, ILI9486Rgb666},
|
|
||||||
options::{ColorInversion, ColorOrder, Orientation, Rotation},
|
|
||||||
Builder,
|
|
||||||
Display,
|
|
||||||
NoResetPin,
|
|
||||||
};
|
|
||||||
use static_cell::{make_static, StaticCell};
|
|
||||||
use xpt2046::Xpt2046;
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
|
||||||
async fn touch_task(
|
|
||||||
touch_irq: GpioPin<36>,
|
|
||||||
spi: &'static mut NoopMutex<RefCell<Spi<'static, SPI3, FullDuplexMode>>>,
|
|
||||||
touch_cs: GpioPin<33>,
|
|
||||||
touch_signal: &'static Signal<NoopRawMutex, Option<Point>>,
|
|
||||||
) -> ! {
|
|
||||||
let mut touch_driver = Xpt2046::new(
|
|
||||||
SpiDevice::new(spi, Output::new(touch_cs, Level::Low)),
|
|
||||||
Input::new(touch_irq, Pull::Up),
|
|
||||||
xpt2046::Orientation::LandscapeFlipped,
|
|
||||||
);
|
|
||||||
touch_driver.set_num_samples(16);
|
|
||||||
touch_driver.init(&mut embassy_time::Delay).unwrap();
|
|
||||||
|
|
||||||
let mut debounce = Debouncer::new();
|
|
||||||
println!("touch task");
|
|
||||||
|
|
||||||
loop {
|
|
||||||
touch_driver.run().expect("Running Touch driver failed");
|
|
||||||
if touch_driver.is_touched() {
|
|
||||||
let point = touch_driver.get_touch_point();
|
|
||||||
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
|
|
||||||
} else {
|
|
||||||
touch_signal.signal(None);
|
|
||||||
}
|
|
||||||
Timer::after(Duration::from_millis(1)).await; // 100 a second
|
|
||||||
|
|
||||||
// Your touch handling logic here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[main]
|
|
||||||
async fn main(spawner: Spawner) {
|
|
||||||
let peripherals = Peripherals::take();
|
|
||||||
let system = SystemControl::new(peripherals.SYSTEM);
|
|
||||||
let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
|
||||||
|
|
||||||
// Enable the RWDT watchdog timer:
|
|
||||||
let mut rtc = Rtc::new(peripherals.LPWR);
|
|
||||||
rtc.rwdt.set_timeout(2.secs());
|
|
||||||
rtc.rwdt.enable();
|
|
||||||
println!("RWDT watchdog enabled!");
|
|
||||||
|
|
||||||
// Initialize the SYSTIMER peripheral, and then Embassy:
|
|
||||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
|
||||||
esp_hal_embassy::init(&clocks, timg0.timer0);
|
|
||||||
println!("Embassy initialized!");
|
|
||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
|
||||||
// let mut led = Output::new(io.pins.gpio5, Level::High);
|
|
||||||
// Initialize SPI
|
|
||||||
let sclk = io.pins.gpio14;
|
|
||||||
let miso = io.pins.gpio12;
|
|
||||||
let mosi = io.pins.gpio13;
|
|
||||||
let cs = io.pins.gpio15;
|
|
||||||
let dc = io.pins.gpio2;
|
|
||||||
let mut backlight = Output::new(io.pins.gpio21, Level::Low);
|
|
||||||
|
|
||||||
// Note: RST is not initialized as it's set to -1 in the instructions
|
|
||||||
|
|
||||||
// up to 80MHz is possible (even tho the display driver isn't supposed to be
|
|
||||||
// that fast) Dataseheet sais 10MHz, so we're gonna go with that
|
|
||||||
let mut spi = Spi::new(peripherals.SPI2, 10.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(sclk),
|
|
||||||
Some(mosi),
|
|
||||||
Some(miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
|
|
||||||
static DISP_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI2, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let spi_bus = NoopMutex::new(RefCell::new(spi));
|
|
||||||
let spi_bus = DISP_SPI_BUS.init(spi_bus);
|
|
||||||
|
|
||||||
let di = SPIInterface::new(
|
|
||||||
SpiDevice::new(spi_bus, Output::new(cs, Level::Low)),
|
|
||||||
Output::new(dc, Level::Low),
|
|
||||||
);
|
|
||||||
let display = Builder::new(ILI9486Rgb565, di)
|
|
||||||
.orientation(Orientation {
|
|
||||||
rotation: Rotation::Deg90,
|
|
||||||
mirrored: true,
|
|
||||||
})
|
|
||||||
.color_order(ColorOrder::Bgr)
|
|
||||||
.invert_colors(ColorInversion::Inverted)
|
|
||||||
.init(&mut embassy_time::Delay)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut display = ProfilerDisplay::new(display);
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
ui.clear_background().ok();
|
|
||||||
}
|
|
||||||
backlight.set_high();
|
|
||||||
|
|
||||||
// init touchscreen pins
|
|
||||||
let touch_irq = io.pins.gpio36;
|
|
||||||
let touch_mosi = io.pins.gpio32;
|
|
||||||
let touch_miso = io.pins.gpio39;
|
|
||||||
let touch_clk = io.pins.gpio25;
|
|
||||||
let touch_cs = io.pins.gpio33;
|
|
||||||
|
|
||||||
// 2MHz is the MAX! DO NOT DECREASE! This is really important.
|
|
||||||
let mut touch_spi = Spi::new(peripherals.SPI3, 2.MHz(), SpiMode::Mode0, &mut clocks).with_pins(
|
|
||||||
Some(touch_clk),
|
|
||||||
Some(touch_mosi),
|
|
||||||
Some(touch_miso),
|
|
||||||
NO_PIN,
|
|
||||||
);
|
|
||||||
static TOUCH_SPI_BUS: StaticCell<NoopMutex<RefCell<Spi<SPI3, FullDuplexMode>>>> =
|
|
||||||
StaticCell::new();
|
|
||||||
let touch_spi_bus = NoopMutex::new(RefCell::new(touch_spi));
|
|
||||||
let touch_spi_bus = TOUCH_SPI_BUS.init(touch_spi_bus);
|
|
||||||
|
|
||||||
let touch_signal = Signal::new();
|
|
||||||
static TOUCH_SIGNAL: StaticCell<Signal<NoopRawMutex, Option<Point>>> = StaticCell::new();
|
|
||||||
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
|
|
||||||
|
|
||||||
spawner
|
|
||||||
.spawn(touch_task(touch_irq, touch_spi_bus, touch_cs, touch_signal))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// init RGB LED pins
|
|
||||||
|
|
||||||
let mut red_led = Output::new(io.pins.gpio4, Level::High);
|
|
||||||
let mut green_led = Output::new(io.pins.gpio16, Level::High);
|
|
||||||
let mut blue_led = Output::new(io.pins.gpio17, Level::High);
|
|
||||||
|
|
||||||
// init SD card pins
|
|
||||||
let sd_miso = io.pins.gpio19;
|
|
||||||
let sd_mosi = io.pins.gpio23;
|
|
||||||
let sd_sck = io.pins.gpio18;
|
|
||||||
let sd_cs = io.pins.gpio5;
|
|
||||||
|
|
||||||
// TODO: Spawn some tasks
|
|
||||||
let _ = spawner;
|
|
||||||
|
|
||||||
let mut last_touch = None;
|
|
||||||
|
|
||||||
static BUF_CELL: StaticCell<[Rgb565; 100 * 100]> = StaticCell::new();
|
|
||||||
let buf = BUF_CELL.init([Rgb565::BLACK; 100 * 100]);
|
|
||||||
|
|
||||||
// Periodically feed the RWDT watchdog timer when our tasks are not running:
|
|
||||||
let mut sm = SmartstateProvider::<20>::new();
|
|
||||||
let mut ui_data = UiData {
|
|
||||||
timer_started: false,
|
|
||||||
timer_duration: Duration::from_secs(30),
|
|
||||||
timer_start_time: Instant::now(),
|
|
||||||
};
|
|
||||||
loop {
|
|
||||||
let start_time = embassy_time::Instant::now();
|
|
||||||
sm.restart_counter();
|
|
||||||
let mut ui = Ui::new_fullscreen(&mut display, medsize_rgb565_style());
|
|
||||||
ui.set_buffer(buf);
|
|
||||||
if let Some(touch) = touch_signal.try_take() {
|
|
||||||
let interact = match (touch, last_touch) {
|
|
||||||
(Some(point), Some(_)) => Interaction::Drag(point),
|
|
||||||
(Some(point), None) => Interaction::Click(point),
|
|
||||||
(None, Some(point)) => Interaction::Release(point),
|
|
||||||
(None, None) => Interaction::None,
|
|
||||||
};
|
|
||||||
ui.interact(interact);
|
|
||||||
// println!("{:?}, {:?}, {:?}", last_touch, touch, interact);
|
|
||||||
|
|
||||||
last_touch = touch;
|
|
||||||
}
|
|
||||||
let start_draw_time = embassy_time::Instant::now();
|
|
||||||
do_ui(&mut sm, &mut ui, &mut ui_data);
|
|
||||||
let end_time = embassy_time::Instant::now();
|
|
||||||
let draw_time = display.get_time();
|
|
||||||
let prep_time = start_draw_time - start_time;
|
|
||||||
let proc_time = end_time - start_draw_time;
|
|
||||||
let proc_time = proc_time - min(draw_time, proc_time);
|
|
||||||
rtc.rwdt.feed();
|
|
||||||
|
|
||||||
if draw_time.as_micros() > 0 {
|
|
||||||
println!(
|
|
||||||
"draw time: {}.{:03}ms | prep time: {}.{:03}ms | proc time: {}.{:03}ms ",
|
|
||||||
draw_time.as_millis(),
|
|
||||||
draw_time.as_micros() % 100,
|
|
||||||
prep_time.as_millis(),
|
|
||||||
prep_time.as_micros() % 100,
|
|
||||||
proc_time.as_millis(),
|
|
||||||
proc_time.as_micros() % 100,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
display.reset_time();
|
|
||||||
Timer::after(Duration::from_millis(17)).await; // 60 a second
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UiData {
|
|
||||||
timer_started: bool,
|
|
||||||
timer_duration: Duration,
|
|
||||||
timer_start_time: Instant,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_ui<DISP: DrawTarget<Color = Rgb565>>(
|
|
||||||
sm: &mut SmartstateProvider<20>,
|
|
||||||
ui: &mut Ui<DISP, Rgb565>,
|
|
||||||
ui_data: &mut UiData,
|
|
||||||
) {
|
|
||||||
ui.sub_ui(|ui| {
|
|
||||||
ui.style_mut().default_font = profont::PROFONT_24_POINT;
|
|
||||||
ui.add(Label::new("Timer").smartstate(sm.next()));
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
ui.add(Spacer::new(Size::new(0, 16)));
|
|
||||||
ui.add(Spacer::new(Size::new(0, 32)));
|
|
||||||
ui.add_horizontal(IconButton::new(icons::size24px::music::Play).smartstate(sm.next()));
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user