feat: progress

This commit is contained in:
Yandrik 2024-09-25 16:47:28 +02:00
parent 04e1b1f9ae
commit 3d7e506dd5
24 changed files with 2398 additions and 67 deletions

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,3 @@
{
}

File diff suppressed because one or more lines are too long

33
.idea/cody_history.xml Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChatHistory">
<accountData>
<list>
<AccountData>
<accountId value="VXNlcjozODgwNDA=" />
<defaultLlm>
<llm>
<model value="anthropic/claude-3-5-sonnet-20240620" />
<provider value="Anthropic" />
<tags>
<list>
<option value="gateway" />
<option value="power" />
<option value="recommended" />
<option value="free" />
</list>
</tags>
<title value="Claude 3.5 Sonnet" />
<usage>
<list>
<option value="chat" />
<option value="edit" />
</list>
</usage>
</llm>
</defaultLlm>
</AccountData>
</list>
</accountData>
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxBlameSettings">
<option name="version" value="2" />
</component>
</project>

27
.idea/jsonSchemas.xml Normal file
View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JsonSchemaMappingsProjectConfiguration">
<state>
<map>
<entry key="Cody Settings">
<value>
<SchemaInfo>
<option name="name" value="Cody Settings" />
<option name="relativePathToSchema" value="$PROJECT_DIR$/.idea/.sourcegraph/cody_settings.schema.json" />
<option name="schemaVersion" value="JSON Schema 7" />
<option name="patterns">
<list>
<Item>
<option name="pattern" value="true" />
<option name="path" value="*/cody_settings.json" />
<option name="mappingKind" value="Pattern" />
</Item>
</list>
</option>
</SchemaInfo>
</value>
</entry>
</map>
</state>
</component>
</project>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="EMPTY_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/app/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/embedded-graphics-profiler-display/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/app/target" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/kolibri-cyd-tester-app-embassy.iml" filepath="$PROJECT_DIR$/.idea/kolibri-cyd-tester-app-embassy.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["rust-lang.rust-analyzer", "tamasfe.even-better-toml"]
}

10
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
"editor.formatOnSave": true,
// Even Better TOML:
"evenBetterToml.formatter.alignComments": true,
"evenBetterToml.formatter.alignEntries": true,
"evenBetterToml.formatter.arrayAutoExpand": true,
"evenBetterToml.formatter.arrayTrailingComma": true,
"evenBetterToml.formatter.reorderArrays": true
}

65
Cargo.lock generated
View File

@ -53,9 +53,18 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.87"
version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8"
checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356"
[[package]]
name = "atomic"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994"
dependencies = [
"bytemuck",
]
[[package]]
name = "atomic-polyfill"
@ -101,9 +110,9 @@ checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]]
name = "bitfield"
version = "0.16.2"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee8655230d3b9bcaa07b9c013a523afa39d3454e631d32794c8a0df71cb22139"
checksum = "d5acf59e2452f0c4b968b15ce4b9468f57b45f7733b919d68b19fcc39264bfb8"
[[package]]
name = "bitflags"
@ -163,7 +172,7 @@ version = "4.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
dependencies = [
"heck 0.5.0",
"heck",
"proc-macro2",
"quote",
"syn 2.0.77",
@ -415,6 +424,15 @@ dependencies = [
"byteorder",
]
[[package]]
name = "embedded-graphics-profiler-display"
version = "0.1.0"
dependencies = [
"atomic",
"embassy-time",
"embedded-graphics",
]
[[package]]
name = "embedded-hal"
version = "0.2.7"
@ -477,6 +495,18 @@ dependencies = [
"embedded-io",
]
[[package]]
name = "embedded-sdmmc"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "150f320125310e179b9e73b081173b349e63c5c7d4ca44db4e5b9121b10387ec"
dependencies = [
"byteorder",
"embedded-hal 1.0.0",
"heapless 0.8.0",
"log",
]
[[package]]
name = "embedded-storage"
version = "0.3.1"
@ -494,11 +524,11 @@ dependencies = [
[[package]]
name = "enum-as-inner"
version = "0.6.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a"
checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
dependencies = [
"heck 0.4.1",
"heck",
"proc-macro2",
"quote",
"syn 2.0.77",
@ -784,12 +814,6 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
@ -822,6 +846,7 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
name = "kolibri-cyd-tester-app-embassy"
version = "0.1.0"
dependencies = [
"bit_field",
"display-interface",
"display-interface-spi",
"embassy-embedded-hal",
@ -829,7 +854,9 @@ dependencies = [
"embassy-sync 0.6.0",
"embassy-time",
"embedded-graphics",
"embedded-graphics-profiler-display",
"embedded-hal 1.0.0",
"embedded-sdmmc",
"esp-backtrace",
"esp-hal",
"esp-hal-embassy",
@ -844,7 +871,7 @@ dependencies = [
[[package]]
name = "kolibri-embedded-gui"
version = "0.0.0-alpha.1"
source = "git+https://github.com/Yandrik/kolibri.git#91555d8c53b2280ce7af0f1ae169a2e86d37fa99"
source = "git+https://github.com/Yandrik/kolibri.git?branch=optimizations#1bd7d733a6772f208a8a08f05cf33f5467c02d34"
dependencies = [
"embedded-graphics",
"embedded-iconoir",
@ -1167,7 +1194,7 @@ version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck 0.5.0",
"heck",
"proc-macro2",
"quote",
"rustversion",
@ -1247,9 +1274,9 @@ checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
[[package]]
name = "unicode-ident"
version = "1.0.12"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "utf8parse"
@ -1378,7 +1405,7 @@ dependencies = [
[[package]]
name = "xpt2046"
version = "0.3.1"
source = "git+https://github.com/Yandrik/xpt2046.git#7dcacbe3018d2da4d7c5547f9b516eff289924cc"
source = "git+https://github.com/Yandrik/xpt2046.git#8d8cf9481268f61580e3dccf90717bbbeb50aa99"
dependencies = [
"embedded-graphics",
"embedded-graphics-core",

View File

@ -1,35 +1,6 @@
[package]
name = "kolibri-cyd-tester-app-embassy"
version = "0.1.0"
edition = "2021"
rust-version = "1.76.0"
[[bin]]
name = "firmware"
path = "src/bin/firmware.rs"
[lib]
[dependencies]
display-interface = "0.5.0"
display-interface-spi = "0.5.0"
embassy-embedded-hal = "0.2.0"
# defmt = "0.3.8"
# defmt-rtt = "0.4.1"
embassy-executor = { version = "0.6.0", features = ["log"] }
embassy-sync = "0.6.0"
embassy-time = { version = "0.3.1", features = ["generic-queue-8"] }
embedded-graphics = "0.8.1"
embedded-hal = "1.0.0"
esp-backtrace = { version = "0.14.1", features = ["esp32", "println", "exception-handler", "panic-handler"] }
esp-hal = { version = "0.20.1", features = ["esp32", "log", "async"] }
esp-hal-embassy = { version = "0.3.0", features = ["esp32", "log"] }
esp-println = { version = "0.11.0", features = ["esp32", "log"] }
heapless = { version = "0.8.0", features = ["serde"] }
kolibri-embedded-gui = { git = "https://github.com/Yandrik/kolibri.git", version = "0.0.0-alpha.1" }
mipidsi = "0.8.0"
static_cell = { version = "2.1.0", features = ["nightly"] }
xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }
[workspace]
members = [ "app" , "embedded-graphics-profiler-display"]
resolver = "2"
[profile.release]
debug = true # Debug info is useful, and does not affect the size of the final binary

1442
app/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

44
app/Cargo.toml Normal file
View File

@ -0,0 +1,44 @@
[package]
name = "kolibri-cyd-tester-app-embassy"
version = "0.1.0"
edition = "2021"
rust-version = "1.76.0"
[[bin]]
name = "firmware"
path = "src/bin/firmware.rs"
[[bin]]
name = "xpt"
path = "src/bin/xpt.rs"
[[bin]]
name = "calibrate"
path = "src/bin/calibrate.rs"
[lib]
[dependencies]
bit_field = "0.10.2"
display-interface = "0.5.0"
display-interface-spi = "0.5.0"
embassy-embedded-hal = "0.2.0"
# defmt = "0.3.8"
# defmt-rtt = "0.4.1"
embassy-executor = { version = "0.6.0", features = ["log"] }
embassy-sync = "0.6.0"
embassy-time = { version = "0.3.1", features = ["generic-queue-8"] }
embedded-graphics = "0.8.1"
embedded-graphics-profiler-display = { version = "0.1.0", path = "../embedded-graphics-profiler-display" }
embedded-hal = "1.0.0"
embedded-sdmmc = "0.8.0"
esp-backtrace = { version = "0.14.1", features = ["esp32", "println", "exception-handler", "panic-handler"] }
esp-hal = { version = "0.20.1", features = ["esp32", "log", "async"] }
esp-hal-embassy = { version = "0.3.0", features = ["esp32", "log"] }
esp-println = { version = "0.11.0", features = ["esp32", "log"] }
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" }
mipidsi = "0.8.0"
static_cell = { version = "2.1.0", features = ["nightly"] }
xpt2046 = { git = "https://github.com/Yandrik/xpt2046.git", version = "0.3.1" }

View File

@ -11,9 +11,11 @@ use embassy_sync::{
signal::Signal,
};
use embassy_time::{Duration, Timer};
use embedded_graphics::{mono_font::ascii, prelude::Point};
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::RgbColor;
use embedded_graphics::{
mono_font::ascii,
pixelcolor::Rgb565,
prelude::{DrawTarget, Point, RgbColor},
};
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
@ -28,8 +30,12 @@ use esp_hal::{
};
use esp_println::println;
use kolibri_cyd_tester_app_embassy::Debouncer;
use kolibri_embedded_gui::{button::Button, label::Label, style::medsize_rgb565_style, ui::Ui};
use kolibri_embedded_gui::ui::Interaction;
use kolibri_embedded_gui::{
button::Button,
label::Label,
style::medsize_rgb565_style,
ui::{Interaction, Ui},
};
use mipidsi::{
models::{ILI9486Rgb565, ILI9486Rgb666},
options::{ColorInversion, ColorOrder, Orientation, Rotation},
@ -50,7 +56,7 @@ async fn touch_task(
Input::new(touch_irq, Pull::Up),
xpt2046::Orientation::LandscapeFlipped,
);
touch_driver.set_num_samples(32);
touch_driver.set_num_samples(16);
touch_driver.init(&mut embassy_time::Delay).unwrap();
let mut debounce = Debouncer::new();
@ -60,7 +66,7 @@ async fn touch_task(
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, 240-point.y)));
touch_signal.signal(Some(Point::new(point.x + 25, 240 - point.y)));
} else {
touch_signal.signal(None);
}
@ -140,7 +146,8 @@ async fn main(spawner: Spawner) {
let touch_clk = io.pins.gpio25;
let touch_cs = io.pins.gpio33;
let mut touch_spi = Spi::new(peripherals.SPI3, 10.MHz(), SpiMode::Mode0, &mut clocks)
// 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();
@ -152,12 +159,7 @@ async fn main(spawner: Spawner) {
let touch_signal = &*TOUCH_SIGNAL.init(touch_signal);
spawner
.spawn(touch_task(
touch_irq,
touch_spi_bus,
touch_cs,
touch_signal,
))
.spawn(touch_task(touch_irq, touch_spi_bus, touch_cs, touch_signal))
.unwrap();
// init RGB LED pins
@ -166,6 +168,17 @@ async fn main(spawner: Spawner) {
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;

179
app/src/bin/calibrate.rs Normal file
View File

@ -0,0 +1,179 @@
#![no_std]
#![no_main]
use core::cell::RefCell;
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, prelude::Point};
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::{DrawTarget, RgbColor};
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, style::medsize_rgb565_style, ui::Ui};
use kolibri_embedded_gui::ui::Interaction;
use mipidsi::{
models::{ILI9486Rgb565, ILI9486Rgb666},
options::{ColorInversion, ColorOrder, Orientation, Rotation},
Builder,
};
use static_cell::{make_static, StaticCell};
use xpt2046::Xpt2046;
#[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(200000.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 mut 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 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;
let mut touch_spi = Spi::new(peripherals.SPI3, 10.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);
let mut touch_driver = Xpt2046::new(
SpiDevice::new(touch_spi_bus, Output::new(touch_cs, Level::Low)),
Input::new(touch_irq, Pull::Up),
xpt2046::Orientation::LandscapeFlipped,
);
touch_driver.set_num_samples(128);
touch_driver.init(&mut embassy_time::Delay).unwrap();
touch_driver.calibrate(&mut display, &mut embassy_time::Delay).unwrap();
// println!("{:?}", touch_driver.calibration_data);
loop {
touch_driver.run();
println!("{:?}", touch_driver.get_touch_point());
}
// 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);
// 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:
loop {
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;
}
ui.sub_ui(|ui| {
ui.style_mut().default_font = ascii::FONT_9X18_BOLD;
ui.add(Label::new("Kolibri Tester"));
Ok(())
})
.ok();
ui.add_horizontal(Button::new("Works!"));
ui.add(Button::new("And pretty nicely!"));
rtc.rwdt.feed();
Timer::after(Duration::from_millis(17)).await; // 60 a second
}
}

243
app/src/bin/firmware.rs Normal file
View File

@ -0,0 +1,243 @@
#![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()));
rtc.rwdt.feed();
let draw_time = display.get_time();
let prep_time = start_draw_time - start_time;
let proc_time = embassy_time::Instant::now() - start_draw_time;
let proc_time = proc_time - min(draw_time, proc_time);
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
}
}

170
app/src/bin/xpt.rs Normal file
View File

@ -0,0 +1,170 @@
#![no_std]
#![no_main]
use core::cell::RefCell;
use bit_field::{BitArray, BitField};
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 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,
style::medsize_rgb565_style,
ui::{Interaction, Ui},
};
use mipidsi::{
models::{ILI9486Rgb565, ILI9486Rgb666},
options::{ColorInversion, ColorOrder, Orientation, Rotation},
Builder,
};
use static_cell::{make_static, StaticCell};
use xpt2046::Xpt2046;
#[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 mut 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 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;
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);
// 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);
// TODO: Spawn some tasks
let _ = spawner;
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:
loop {
// XPT read raw
let mut input = [0x91, 0x00, 0x00]; // measure X pos
touch_spi.transfer(&mut input).unwrap();
let mut input = [0x91, 0x00, 0x00]; // measure X pos
touch_spi.transfer(&mut input).unwrap();
let mut input = [0x91, 0x00, 0x00]; // measure X pos
touch_spi.transfer(&mut input).unwrap();
// println!("read: {:08b} {:08b} {:08b}", input[0], input[1], input[2]);
let x = u16::from_be_bytes([input[1], input[2]]) >> 3;
// println!("{:16b} ({})", num, num);
let mut input = [0xD1, 0x00, 0x00]; // measure y pos
touch_spi.transfer(&mut input).unwrap();
let mut input = [0xD1, 0x00, 0x00]; // measure y pos
touch_spi.transfer(&mut input).unwrap();
let mut input = [0xD1, 0x00, 0x00]; // measure y pos
touch_spi.transfer(&mut input).unwrap();
// println!("read: {:08b} {:08b} {:08b}", input[0], input[1], input[2]);
let y = u16::from_be_bytes([input[1], input[2]]) >> 3;
// println!("{:16b} ({})", num, num);
println!("x: {}, y: {}", (x as f32 * 0.078125) as u16, (y as f32 * 0.05859375) as u16);
rtc.rwdt.feed();
Timer::after(Duration::from_millis(17)).await; // 60 a second
}
}

View File

@ -0,0 +1,9 @@
[package]
name = "embedded-graphics-profiler-display"
version = "0.1.0"
edition = "2021"
[dependencies]
atomic = "0.6.0"
embassy-time = "0.3.2"
embedded-graphics = "0.8"

View File

@ -0,0 +1,5 @@
#![no_std]
#![no_main]
mod profiler;
pub use profiler::ProfilerDisplay;

View File

@ -0,0 +1,109 @@
use atomic::Atomic;
use embassy_time::{Duration, Instant};
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::{Drawable, Pixel};
use embedded_graphics::geometry::Dimensions;
use embedded_graphics::primitives::Rectangle;
pub struct ProfilerDisplay<DRAW_TARGET: DrawTarget> {
drawtarget: DRAW_TARGET,
time_draw: Duration,
time_draw_iter: Duration,
time_fill_contiguous: Duration,
time_fill_solid: Duration,
}
impl<DRAW_TARGET: DrawTarget> Dimensions for ProfilerDisplay<DRAW_TARGET> {
fn bounding_box(&self) -> Rectangle {
self.drawtarget.bounding_box()
}
}
impl<DRAW_TARGET: DrawTarget> DrawTarget for ProfilerDisplay<DRAW_TARGET> {
type Color = DRAW_TARGET::Color;
type Error = DRAW_TARGET::Error;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item=Pixel<Self::Color>>
{
let start = Instant::now();
let res = self.drawtarget.draw_iter(pixels);
self.time_draw_iter += Instant::now() - start;
res
}
fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item=Self::Color>
{
let start = Instant::now();
let res = self.drawtarget.fill_contiguous(area, colors);
self.time_fill_contiguous += Instant::now() - start;
res
}
fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
let start = Instant::now();
let res = self.drawtarget.fill_solid(area, color);
self.time_fill_solid += Instant::now() - start;
res
}
fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
let start = Instant::now();
let res = self.drawtarget.clear(color);
self.time_fill_solid += Instant::now() - start;
res
}
}
impl<DRAW_TARGET: DrawTarget> ProfilerDisplay<DRAW_TARGET> {
/// Creates a new `ProfilerDisplay` instance with the given drawable target.
///
/// # Arguments
///
/// * `drawable` - The draw target to be profiled.
pub fn new(drawable: DRAW_TARGET) -> Self {
ProfilerDisplay {
drawtarget: drawable,
time_draw: Duration::from_millis(0),
time_draw_iter: Duration::from_millis(0),
time_fill_contiguous: Duration::from_millis(0),
time_fill_solid: Duration::from_millis(0),
}
}
/// Returns the total time spent in the `draw` operation.
pub fn get_time_draw(&self) -> Duration {
self.time_draw
}
/// Returns the total time spent in the `draw_iter` operation.
pub fn get_time_draw_iter(&self) -> Duration {
self.time_draw_iter
}
/// Returns the total time spent in the `fill_contiguous` operation.
pub fn get_time_fill_contiguous(&self) -> Duration {
self.time_fill_contiguous
}
/// Returns the total time spent in the `fill_solid` operation.
pub fn get_time_fill_solid(&self) -> Duration {
self.time_fill_solid
}
/// Returns the total time spent across all profiled draw operations.
pub fn get_time(&self) -> Duration {
self.time_draw + self.time_draw_iter + self.time_fill_contiguous + self.time_fill_solid
}
/// Resets time tracking to zero.
pub fn reset_time(&mut self) {
self.time_draw = Duration::from_millis(0);
self.time_draw_iter = Duration::from_millis(0);
self.time_fill_contiguous = Duration::from_millis(0);
self.time_fill_solid = Duration::from_millis(0);
}
}