From 2f63fd5eb7ffa652f78e1226b3930fb7154a2dd9 Mon Sep 17 00:00:00 2001 From: issy Date: Thu, 26 Feb 2026 17:19:50 +0000 Subject: [PATCH 1/8] Add dependencies for ST7789 display --- firmware/Cargo.lock | 174 +++++++++++++++++++++++++++++++++++++++++++- firmware/Cargo.toml | 4 + 2 files changed, 176 insertions(+), 2 deletions(-) diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock index 3cdbc2f..2eba533 100644 --- a/firmware/Cargo.lock +++ b/firmware/Cargo.lock @@ -14,12 +14,27 @@ version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + [[package]] name = "base64" version = "0.13.1" @@ -52,6 +67,12 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + [[package]] name = "bytemuck" version = "1.25.0" @@ -221,6 +242,30 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "display-interface" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7517c040926d7b02b111884aa089177db80878533127f7c1b480d852c5fb4112" + +[[package]] +name = "display-interface" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba2aab1ef3793e6f7804162debb5ac5edb93b3d650fbcc5aeb72fcd0e6c03a0" + +[[package]] +name = "display-interface-spi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9ec30048b1955da2038fcc3c017f419ab21bb0001879d16c0a3749dc6b7a" +dependencies = [ + "byte-slice-cast", + "display-interface 0.5.0", + "embedded-hal 1.0.0", + "embedded-hal-async", +] + [[package]] name = "document-features" version = "0.2.12" @@ -373,6 +418,39 @@ dependencies = [ "nb 1.1.0", ] +[[package]] +name = "embedded-graphics" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8da660bb0c829b34a56a965490597f82a55e767b91f9543be80ce8ccb416fe" +dependencies = [ + "az", + "byteorder", + "embedded-graphics-core 0.4.1", + "float-cmp", + "micromath", +] + +[[package]] +name = "embedded-graphics-core" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b1239db5f3eeb7e33e35bd10bd014e7b2537b17e071f726a09351431337cfa" +dependencies = [ + "az", + "byteorder", +] + +[[package]] +name = "embedded-graphics-core" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95743bef3ff70fcba3930246c4e6872882bbea0dcc6da2ca860112e0cd4bd09f" +dependencies = [ + "az", + "byteorder", +] + [[package]] name = "embedded-hal" version = "0.2.7" @@ -753,9 +831,11 @@ name = "firmware" version = "0.1.0" dependencies = [ "critical-section", + "display-interface-spi", "embassy-executor", "embassy-sync 0.7.2", "embassy-time", + "embedded-graphics", "esp-alloc", "esp-backtrace", "esp-bootloader-esp-idf", @@ -764,9 +844,19 @@ dependencies = [ "esp-rtos", "log", "prost", + "st7789", "static_cell", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -828,6 +918,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hash32" version = "0.3.1" @@ -843,13 +942,26 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32 0.2.1", + "rustc_version", + "spin", + "stable_deref_trait", +] + [[package]] name = "heapless" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "hash32", + "hash32 0.3.1", "stable_deref_trait", ] @@ -859,7 +971,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" dependencies = [ - "hash32", + "hash32 0.3.1", "stable_deref_trait", ] @@ -964,6 +1076,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" @@ -976,6 +1097,12 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "micromath" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" + [[package]] name = "nb" version = "0.1.3" @@ -1176,6 +1303,15 @@ dependencies = [ "svgbobdoc", ] +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -1188,6 +1324,18 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -1246,6 +1394,28 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0f368519fc6c85fc1afdb769fb5a51123f6158013e143656e25a3485a0d401c" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "st7789" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86e89eaa897f8688aa897a7a8a62847e00e3f49f804d918bdebd14d4a1beb5ab" +dependencies = [ + "display-interface 0.4.1", + "embedded-graphics-core 0.3.3", + "embedded-hal 0.2.7", + "heapless 0.7.17", + "nb 1.1.0", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index af76357..5e2fdf7 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -27,6 +27,10 @@ esp-backtrace = { version = "0.18.1", features = ["esp32c6", "panic-handler", "p esp-println = { version = "0.16.1", features = ["esp32c6", "log-04"] } esp-alloc = { version = "0.9.0", features = ["esp32c6"] } +embedded-graphics = { version = "0.8.2" } +st7789 = { version = "0.7.0", features = ["heapless"] } +display-interface-spi = { version = "0.5.0" } + critical-section = "1.2.0" static_cell = "2.1.1" From eb046ce95903b5bfd8a56c792fb7cd00db42413c Mon Sep 17 00:00:00 2001 From: issy Date: Thu, 26 Feb 2026 19:05:24 +0000 Subject: [PATCH 2/8] Dependencies and starting to write display code --- firmware/Cargo.lock | 121 ++++++--------------------------------- firmware/Cargo.toml | 3 +- firmware/src/bin/main.rs | 16 +++++- 3 files changed, 32 insertions(+), 108 deletions(-) diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock index 2eba533..24581b2 100644 --- a/firmware/Cargo.lock +++ b/firmware/Cargo.lock @@ -14,15 +14,6 @@ version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - [[package]] name = "autocfg" version = "1.5.0" @@ -242,12 +233,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "display-interface" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7517c040926d7b02b111884aa089177db80878533127f7c1b480d852c5fb4112" - [[package]] name = "display-interface" version = "0.5.0" @@ -261,7 +246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86b9ec30048b1955da2038fcc3c017f419ab21bb0001879d16c0a3749dc6b7a" dependencies = [ "byte-slice-cast", - "display-interface 0.5.0", + "display-interface", "embedded-hal 1.0.0", "embedded-hal-async", ] @@ -426,21 +411,11 @@ checksum = "4e8da660bb0c829b34a56a965490597f82a55e767b91f9543be80ce8ccb416fe" dependencies = [ "az", "byteorder", - "embedded-graphics-core 0.4.1", + "embedded-graphics-core", "float-cmp", "micromath", ] -[[package]] -name = "embedded-graphics-core" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b1239db5f3eeb7e33e35bd10bd014e7b2537b17e071f726a09351431337cfa" -dependencies = [ - "az", - "byteorder", -] - [[package]] name = "embedded-graphics-core" version = "0.4.1" @@ -832,6 +807,7 @@ version = "0.1.0" dependencies = [ "critical-section", "display-interface-spi", + "embassy-embedded-hal", "embassy-executor", "embassy-sync 0.7.2", "embassy-time", @@ -843,8 +819,8 @@ dependencies = [ "esp-println", "esp-rtos", "log", + "mipidsi", "prost", - "st7789", "static_cell", ] @@ -918,15 +894,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - [[package]] name = "hash32" version = "0.3.1" @@ -942,26 +909,13 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32 0.2.1", - "rustc_version", - "spin", - "stable_deref_trait", -] - [[package]] name = "heapless" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "hash32 0.3.1", + "hash32", "stable_deref_trait", ] @@ -971,7 +925,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" dependencies = [ - "hash32 0.3.1", + "hash32", "stable_deref_trait", ] @@ -1076,15 +1030,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.29" @@ -1103,6 +1048,17 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" +[[package]] +name = "mipidsi" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790ebd28bd67addbccf41b1c0c188c26bb9f5bdcd91d4d6da9bd558e20d97a1d" +dependencies = [ + "embedded-graphics-core", + "embedded-hal 1.0.0", + "heapless 0.8.0", +] + [[package]] name = "nb" version = "0.1.3" @@ -1303,15 +1259,6 @@ dependencies = [ "svgbobdoc", ] -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - [[package]] name = "rustversion" version = "1.0.22" @@ -1324,18 +1271,6 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - [[package]] name = "serde" version = "1.0.228" @@ -1394,28 +1329,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0f368519fc6c85fc1afdb769fb5a51123f6158013e143656e25a3485a0d401c" -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "st7789" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e89eaa897f8688aa897a7a8a62847e00e3f49f804d918bdebd14d4a1beb5ab" -dependencies = [ - "display-interface 0.4.1", - "embedded-graphics-core 0.3.3", - "embedded-hal 0.2.7", - "heapless 0.7.17", - "nb 1.1.0", -] - [[package]] name = "stable_deref_trait" version = "1.2.1" diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index 5e2fdf7..d51ba4f 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -22,13 +22,14 @@ log = "0.4.27" embassy-executor = { version = "0.9.1", features = ["log"] } embassy-time = { version = "0.5.0", features = ["log"] } +embassy-embedded-hal = { version = "0.5.0" } embassy-sync = { version = "0.7.2", features = ["log"] } esp-backtrace = { version = "0.18.1", features = ["esp32c6", "panic-handler", "println"] } esp-println = { version = "0.16.1", features = ["esp32c6", "log-04"] } esp-alloc = { version = "0.9.0", features = ["esp32c6"] } embedded-graphics = { version = "0.8.2" } -st7789 = { version = "0.7.0", features = ["heapless"] } +mipidsi = { version = "0.10.0", features = ["batch", "heapless"] } display-interface-spi = { version = "0.5.0" } critical-section = "1.2.0" diff --git a/firmware/src/bin/main.rs b/firmware/src/bin/main.rs index b1e3bb2..c6cb3f8 100644 --- a/firmware/src/bin/main.rs +++ b/firmware/src/bin/main.rs @@ -67,8 +67,7 @@ async fn midi_out_task(mut uart: UartTx<'static, Async>) { async fn main(spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env(); - let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); - let peripherals = esp_hal::init(config); + let peripherals = esp_hal::init(esp_hal::Config::default().with_cpu_clock(CpuClock::max())); let timg0 = TimerGroup::new(peripherals.TIMG0); let sw_interrupt = @@ -77,6 +76,17 @@ async fn main(spawner: Spawner) -> ! { info!("Embassy initialized!"); + let miso_mosi = peripherals.GPIO23; + let miso = unsafe { miso_mosi.clone_unchecked() }; + let spi = esp_hal::spi::master::Spi::new( + peripherals.SPI2, + esp_hal::spi::master::Config::default().with_frequency(esp_hal::time::Rate::from_mhz(40)), + ) + .expect("Failed to initialize SPI2") + .with_sck(peripherals.GPIO18) + .with_miso(miso) + .with_mosi(miso_mosi); + let uart = Uart::new( peripherals.UART1, UartConfig::default() @@ -85,7 +95,7 @@ async fn main(spawner: Spawner) -> ! { .with_parity(Parity::None) .with_stop_bits(StopBits::_1), ) - .expect("Failed to initialize UART0") + .expect("Failed to initialize UART1") .with_rx(peripherals.GPIO7) .with_tx(peripherals.GPIO8) .into_async(); From f5f095825206658500391de3f9dc227c91dce8cf Mon Sep 17 00:00:00 2001 From: issy Date: Thu, 26 Feb 2026 21:31:10 +0000 Subject: [PATCH 3/8] Initialise new SPI --- firmware/src/bin/main.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/firmware/src/bin/main.rs b/firmware/src/bin/main.rs index c6cb3f8..70b77c1 100644 --- a/firmware/src/bin/main.rs +++ b/firmware/src/bin/main.rs @@ -22,6 +22,8 @@ use embassy_executor::{Spawner, task}; use embassy_sync::{blocking_mutex::raw::NoopRawMutex, channel::Channel}; use esp_hal::Async; use esp_hal::clock::CpuClock; +use esp_hal::spi::Mode; +use esp_hal::spi::slave::Spi; use esp_hal::timer::timg::TimerGroup; use esp_hal::uart::{Config as UartConfig, DataBits, Parity, StopBits, Uart, UartRx, UartTx}; use firmware::midi::{MidiPacket, MidiParser}; @@ -76,16 +78,10 @@ async fn main(spawner: Spawner) -> ! { info!("Embassy initialized!"); - let miso_mosi = peripherals.GPIO23; - let miso = unsafe { miso_mosi.clone_unchecked() }; - let spi = esp_hal::spi::master::Spi::new( - peripherals.SPI2, - esp_hal::spi::master::Config::default().with_frequency(esp_hal::time::Rate::from_mhz(40)), - ) - .expect("Failed to initialize SPI2") - .with_sck(peripherals.GPIO18) - .with_miso(miso) - .with_mosi(miso_mosi); + let spi = Spi::new(peripherals.SPI2, Mode::_0) + .with_sck(peripherals.GPIO18) + .with_mosi(peripherals.GPIO19) + .with_cs(peripherals.GPIO20); let uart = Uart::new( peripherals.UART1, From a9daef9e064db1ebd91c63538b5ddecf5b8b7f1a Mon Sep 17 00:00:00 2001 From: issy Date: Thu, 26 Feb 2026 22:58:54 +0000 Subject: [PATCH 4/8] It finally compiles, but DOES IT WORK??? --- firmware/Cargo.lock | 6 ++++-- firmware/Cargo.toml | 2 +- firmware/src/bin/main.rs | 46 +++++++++++++++++++++++++++++++++------- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock index 24581b2..10397b6 100644 --- a/firmware/Cargo.lock +++ b/firmware/Cargo.lock @@ -1050,13 +1050,15 @@ checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" [[package]] name = "mipidsi" -version = "0.10.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790ebd28bd67addbccf41b1c0c188c26bb9f5bdcd91d4d6da9bd558e20d97a1d" +checksum = "44e2bbd372d8ae9ccd0fc6eb4d91742b971ed8149968bbc623f025506989bd30" dependencies = [ + "display-interface", "embedded-graphics-core", "embedded-hal 1.0.0", "heapless 0.8.0", + "nb 1.1.0", ] [[package]] diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index d51ba4f..9733686 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -29,7 +29,7 @@ esp-println = { version = "0.16.1", features = ["esp32c6", "log-04"] } esp-alloc = { version = "0.9.0", features = ["esp32c6"] } embedded-graphics = { version = "0.8.2" } -mipidsi = { version = "0.10.0", features = ["batch", "heapless"] } +mipidsi = { version = "0.8", features = ["batch", "heapless"] } display-interface-spi = { version = "0.5.0" } critical-section = "1.2.0" diff --git a/firmware/src/bin/main.rs b/firmware/src/bin/main.rs index 70b77c1..1c98623 100644 --- a/firmware/src/bin/main.rs +++ b/firmware/src/bin/main.rs @@ -18,16 +18,26 @@ use esp_alloc as _; )] use esp_backtrace as _; +use core::cell::RefCell; +use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_executor::{Spawner, task}; -use embassy_sync::{blocking_mutex::raw::NoopRawMutex, channel::Channel}; +use embassy_sync::{ + blocking_mutex::{Mutex, raw::NoopRawMutex}, + channel::Channel, +}; +use embassy_time::Delay; +use embedded_graphics::pixelcolor::Rgb565; use esp_hal::Async; use esp_hal::clock::CpuClock; -use esp_hal::spi::Mode; -use esp_hal::spi::slave::Spi; +use esp_hal::gpio::{Level, Output, OutputConfig}; +use esp_hal::spi::master::Spi; +use esp_hal::time::Rate; use esp_hal::timer::timg::TimerGroup; use esp_hal::uart::{Config as UartConfig, DataBits, Parity, StopBits, Uart, UartRx, UartTx}; use firmware::midi::{MidiPacket, MidiParser}; use log::info; +use mipidsi::models::ST7789; +use mipidsi::options::Orientation; // This creates a default app-descriptor required by the esp-idf bootloader. // For more information see: @@ -65,6 +75,8 @@ async fn midi_out_task(mut uart: UartTx<'static, Async>) { clippy::large_stack_frames, reason = "it's not unusual to allocate larger buffers etc. in main" )] +use embedded_graphics::draw_target::DrawTarget; +use embedded_graphics::prelude::RgbColor; #[esp_rtos::main] async fn main(spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env(); @@ -78,10 +90,28 @@ async fn main(spawner: Spawner) -> ! { info!("Embassy initialized!"); - let spi = Spi::new(peripherals.SPI2, Mode::_0) - .with_sck(peripherals.GPIO18) - .with_mosi(peripherals.GPIO19) - .with_cs(peripherals.GPIO20); + let spi = Spi::new( + peripherals.SPI2, + esp_hal::spi::master::Config::default().with_frequency(Rate::from_khz(40)), + ) + .expect("Failed to initialise SPI2 peripheral") + .with_sck(peripherals.GPIO18) + .with_mosi(peripherals.GPIO19) + .with_cs(peripherals.GPIO20); + + let cs = Output::new(peripherals.GPIO5, Level::High, OutputConfig::default()); + let spi_bus: Mutex = Mutex::new(RefCell::new(spi)); + let spi_device = SpiDevice::new(&spi_bus, cs); + + let dc = Output::new(peripherals.GPIO21, Level::Low, OutputConfig::default()); + let di = display_interface_spi::SPIInterface::new(spi_device, dc); + let mut display = mipidsi::Builder::new(ST7789, di) + .display_size(240, 240) + .orientation(Orientation::default()) + .init(&mut Delay) + .expect("Failed to initialise ST7789 display"); + + display.clear(Rgb565::BLACK).unwrap(); let uart = Uart::new( peripherals.UART1, @@ -91,7 +121,7 @@ async fn main(spawner: Spawner) -> ! { .with_parity(Parity::None) .with_stop_bits(StopBits::_1), ) - .expect("Failed to initialize UART1") + .expect("Failed to initialise UART1") .with_rx(peripherals.GPIO7) .with_tx(peripherals.GPIO8) .into_async(); From 2b301342282fd974b897007649c142d01bf101f8 Mon Sep 17 00:00:00 2001 From: issy Date: Thu, 26 Feb 2026 23:17:42 +0000 Subject: [PATCH 5/8] Start drawing --- firmware/src/bin/main.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/firmware/src/bin/main.rs b/firmware/src/bin/main.rs index 1c98623..53a745b 100644 --- a/firmware/src/bin/main.rs +++ b/firmware/src/bin/main.rs @@ -26,7 +26,11 @@ use embassy_sync::{ channel::Channel, }; use embassy_time::Delay; -use embedded_graphics::pixelcolor::Rgb565; +use embedded_graphics::draw_target::DrawTarget; +use embedded_graphics::mono_font::MonoTextStyle; +use embedded_graphics::mono_font::ascii::FONT_10X20; +use embedded_graphics::prelude::*; +use embedded_graphics::{pixelcolor::Rgb565, text::Text}; use esp_hal::Async; use esp_hal::clock::CpuClock; use esp_hal::gpio::{Level, Output, OutputConfig}; @@ -75,8 +79,6 @@ async fn midi_out_task(mut uart: UartTx<'static, Async>) { clippy::large_stack_frames, reason = "it's not unusual to allocate larger buffers etc. in main" )] -use embedded_graphics::draw_target::DrawTarget; -use embedded_graphics::prelude::RgbColor; #[esp_rtos::main] async fn main(spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env(); @@ -112,6 +114,10 @@ async fn main(spawner: Spawner) -> ! { .expect("Failed to initialise ST7789 display"); display.clear(Rgb565::BLACK).unwrap(); + let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN); + Text::new("Hello, world!", Point::new(10, 30), style) + .draw(&mut display) + .unwrap(); let uart = Uart::new( peripherals.UART1, @@ -137,5 +143,6 @@ async fn main(spawner: Spawner) -> ! { info!("MIDI out task spawned"); info!("Startup complete."); + loop {} } From 995424f3f0b04e2b8cd24e9afeeec912a0c65809 Mon Sep 17 00:00:00 2001 From: issy Date: Fri, 27 Feb 2026 17:29:47 +0000 Subject: [PATCH 6/8] Add display layout helper --- firmware/Cargo.lock | 1 + firmware/Cargo.toml | 1 + firmware/src/bin/main.rs | 77 +++++++++++++++++++++---- firmware/src/layout/mod.rs | 111 +++++++++++++++++++++++++++++++++++++ firmware/src/lib.rs | 1 + 5 files changed, 180 insertions(+), 11 deletions(-) create mode 100644 firmware/src/layout/mod.rs diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock index 10397b6..09a962a 100644 --- a/firmware/Cargo.lock +++ b/firmware/Cargo.lock @@ -818,6 +818,7 @@ dependencies = [ "esp-hal", "esp-println", "esp-rtos", + "heapless 0.9.2", "log", "mipidsi", "prost", diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index 9733686..bca423f 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -27,6 +27,7 @@ embassy-sync = { version = "0.7.2", features = ["log"] } esp-backtrace = { version = "0.18.1", features = ["esp32c6", "panic-handler", "println"] } esp-println = { version = "0.16.1", features = ["esp32c6", "log-04"] } esp-alloc = { version = "0.9.0", features = ["esp32c6"] } +heapless = { version = "0.9.2" } embedded-graphics = { version = "0.8.2" } mipidsi = { version = "0.8", features = ["batch", "heapless"] } diff --git a/firmware/src/bin/main.rs b/firmware/src/bin/main.rs index e05a633..3c30756 100644 --- a/firmware/src/bin/main.rs +++ b/firmware/src/bin/main.rs @@ -19,6 +19,7 @@ use esp_alloc as _; use esp_backtrace as _; use core::cell::RefCell; +use core::ops::Add; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_executor::{Spawner, task}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; @@ -29,9 +30,10 @@ use embassy_sync::{ use embassy_time::Delay; use embassy_time::Timer; use embedded_graphics::draw_target::DrawTarget; -use embedded_graphics::mono_font::MonoTextStyle; -use embedded_graphics::mono_font::ascii::FONT_10X20; +use embedded_graphics::mono_font::{MonoTextStyleBuilder, ascii::FONT_10X20}; use embedded_graphics::prelude::*; +use embedded_graphics::primitives::PrimitiveStyleBuilder; +use embedded_graphics::text::{Alignment, Baseline, TextStyleBuilder}; use embedded_graphics::{pixelcolor::Rgb565, text::Text}; use esp_hal::Async; use esp_hal::clock::CpuClock; @@ -41,10 +43,12 @@ use esp_hal::time::Rate; use esp_hal::timer::timg::TimerGroup; use esp_hal::uart::{Config as UartConfig, DataBits, Parity, StopBits, Uart, UartRx, UartTx}; use esp_println::println; +use firmware::layout::DisplayLayout; use firmware::midi::{MidiPacket, MidiParser}; use log::info; use mipidsi::models::ST7789; -use mipidsi::options::Orientation; +use mipidsi::options::Rotation::{Deg90, Deg270}; +use mipidsi::options::{ColorInversion, Orientation}; // This creates a default app-descriptor required by the esp-idf bootloader. // For more information see: @@ -97,7 +101,7 @@ async fn main(spawner: Spawner) -> ! { let spi = Spi::new( peripherals.SPI2, - esp_hal::spi::master::Config::default().with_frequency(Rate::from_khz(40)), + esp_hal::spi::master::Config::default().with_frequency(Rate::from_mhz(40)), ) .expect("Failed to initialise SPI2 peripheral") .with_sck(peripherals.GPIO18) @@ -111,16 +115,67 @@ async fn main(spawner: Spawner) -> ! { let dc = Output::new(peripherals.GPIO21, Level::Low, OutputConfig::default()); let di = display_interface_spi::SPIInterface::new(spi_device, dc); let mut display = mipidsi::Builder::new(ST7789, di) - .display_size(240, 240) - .orientation(Orientation::default()) + .display_size(240, 280) + .orientation(Orientation::default().rotate(Deg270)) + .display_offset(0, 20) + .invert_colors(ColorInversion::Inverted) + // TODO: Add reset pin .init(&mut Delay) .expect("Failed to initialise ST7789 display"); display.clear(Rgb565::BLACK).unwrap(); - let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN); - Text::new("Hello, world!", Point::new(10, 30), style) - .draw(&mut display) - .unwrap(); + + embedded_graphics::primitives::Rectangle::new( + Point::zero(), + Size::new(display.size().width, display.size().height / 3), + ) + .into_styled( + PrimitiveStyleBuilder::new() + .fill_color(Rgb565::CSS_ORANGE) + .build(), + ) + .draw(&mut display) + .unwrap(); + embedded_graphics::primitives::Rectangle::new( + Point::new( + 0, + display.size().height as i32 - display.size().height as i32 / 3, + ), + Size::new(display.size().width, display.size().height / 3), + ) + .into_styled( + PrimitiveStyleBuilder::new() + .fill_color(Rgb565::BLUE) + .build(), + ) + .draw(&mut display) + .unwrap(); + + let text_style = TextStyleBuilder::new() + .alignment(Alignment::Center) + .baseline(Baseline::Middle) + .build(); + let character_style = MonoTextStyleBuilder::new() + .font(&FONT_10X20) + .text_color(Rgb565::GREEN) + .build(); + Text::with_text_style( + "Hello, world!", + display + .bounding_box() + .top_left + .add(Point::new(display.size().width as i32 / 2, 60)), + character_style, + text_style, + ) + .draw(&mut display) + .unwrap(); + + let mut layout = DisplayLayout::new(&mut display); + layout.clear_middle().expect("Clear middle"); + layout.draw_boxes().expect("Draw boxes"); + layout.draw_top_text("Foo").expect("Top"); + layout.draw_bottom_text("Bar").expect("Bottom"); let uart = Uart::new( peripherals.UART1, @@ -148,7 +203,7 @@ async fn main(spawner: Spawner) -> ! { info!("Startup complete."); loop { - Timer::after_secs(1).await; + Timer::after_secs(5).await; println!("Heartbeat"); } } diff --git a/firmware/src/layout/mod.rs b/firmware/src/layout/mod.rs new file mode 100644 index 0000000..e4d6d44 --- /dev/null +++ b/firmware/src/layout/mod.rs @@ -0,0 +1,111 @@ +use core::fmt::Write; +use core::ops::Add; +use core::ops::Div; +use core::result::{Result, Result::Ok}; +use embedded_graphics::{ + mono_font::{MonoTextStyleBuilder, ascii::FONT_10X20}, + pixelcolor::Rgb565, + prelude::*, + primitives::{PrimitiveStyle, Rectangle}, + text::Text, +}; +use heapless::String; + +pub struct DisplayLayout<'a, D> { + display: &'a mut D, + top_text: String<16>, + top_box_color: Rgb565, + bottom_text: String<16>, + bottom_box_color: Rgb565, + text_style: embedded_graphics::mono_font::MonoTextStyle<'a, Rgb565>, +} + +impl<'a, D> DisplayLayout<'a, D> +where + D: DrawTarget, +{ + pub fn new(display: &'a mut D) -> Self { + let text_style = MonoTextStyleBuilder::new() + .font(&FONT_10X20) + .text_color(Rgb565::WHITE) + .build(); + + let mut top_text = String::new(); + top_text.write_str("Hello").unwrap(); + let mut bottom_text = String::new(); + bottom_text.write_str("World").unwrap(); + + Self { + display, + top_text, + top_box_color: Rgb565::GREEN, + bottom_text, + bottom_box_color: Rgb565::BLUE, + text_style, + } + } + + pub fn draw_boxes(&mut self) -> Result<(), D::Error> { + let display_size = self.display.bounding_box().size; + + // Top box + Rectangle::new( + Point::zero(), + Size::new(display_size.width, display_size.height.div(3)), + ) + .into_styled(PrimitiveStyle::with_fill(self.top_box_color)) + .draw(self.display)?; + + // Bottom box + Rectangle::new( + Point::new( + 0, + display_size + .height + .div(3) + .add(display_size.height.div_ceil(3)) as i32, + ), + Size::new(display_size.width, display_size.height.div(3)), + ) + .into_styled(PrimitiveStyle::with_fill(self.bottom_box_color)) + .draw(self.display)?; + + Ok(()) + } + + pub fn draw_top_text(&mut self, text: &str) -> Result<(), D::Error> { + Text::new(text, Point::new(5, 10), self.text_style).draw(self.display)?; + Ok(()) + } + + pub fn draw_bottom_text(&mut self, text: &str) -> Result<(), D::Error> { + Text::new(text, Point::new(5, 210), self.text_style).draw(self.display)?; + Ok(()) + } + + pub fn clear_middle(&mut self) -> Result<(), D::Error> { + let display_size = self.display.bounding_box().size; + Rectangle::new( + Point::new(0, display_size.height.div(3) as i32), + Size::new(display_size.width, display_size.height.div_ceil(3)), + ) + .into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK)) + .draw(self.display) + } + + pub fn set_top_box_colour(&mut self, colour: Rgb565) { + self.top_box_color = colour; + } + + pub fn set_bottom_box_colour(&mut self, colour: Rgb565) { + self.bottom_box_color = colour; + } + + pub fn draw(&mut self, top_text: &str, bottom_text: &str) -> Result<(), D::Error> { + self.draw_boxes()?; + self.draw_top_text(top_text)?; + self.draw_bottom_text(bottom_text)?; + self.clear_middle()?; + Ok(()) + } +} diff --git a/firmware/src/lib.rs b/firmware/src/lib.rs index bce0d4a..3bfb9e2 100644 --- a/firmware/src/lib.rs +++ b/firmware/src/lib.rs @@ -7,6 +7,7 @@ pub mod generated { pub mod device_v1; } +pub mod layout; pub mod midi; pub mod protocol; From ac77b4a3d831c2d61b82c5e9a34d7d1c025214ea Mon Sep 17 00:00:00 2001 From: issy Date: Fri, 27 Feb 2026 17:58:19 +0000 Subject: [PATCH 7/8] Restructure --- firmware/src/bin/main.rs | 11 ++++++----- firmware/src/layout/mod.rs | 33 ++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/firmware/src/bin/main.rs b/firmware/src/bin/main.rs index 3c30756..a22cdb1 100644 --- a/firmware/src/bin/main.rs +++ b/firmware/src/bin/main.rs @@ -45,9 +45,10 @@ use esp_hal::uart::{Config as UartConfig, DataBits, Parity, StopBits, Uart, Uart use esp_println::println; use firmware::layout::DisplayLayout; use firmware::midi::{MidiPacket, MidiParser}; +use heapless::String; use log::info; use mipidsi::models::ST7789; -use mipidsi::options::Rotation::{Deg90, Deg270}; +use mipidsi::options::Rotation::Deg270; use mipidsi::options::{ColorInversion, Orientation}; // This creates a default app-descriptor required by the esp-idf bootloader. @@ -86,6 +87,7 @@ async fn midi_out_task(mut uart: UartTx<'static, Async>) { clippy::large_stack_frames, reason = "it's not unusual to allocate larger buffers etc. in main" )] +use core::str::FromStr; #[esp_rtos::main] async fn main(spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env(); @@ -172,10 +174,9 @@ async fn main(spawner: Spawner) -> ! { .unwrap(); let mut layout = DisplayLayout::new(&mut display); - layout.clear_middle().expect("Clear middle"); - layout.draw_boxes().expect("Draw boxes"); - layout.draw_top_text("Foo").expect("Top"); - layout.draw_bottom_text("Bar").expect("Bottom"); + layout.set_top_text(String::from_str("Foo").unwrap()); + layout.set_bottom_text(String::from_str("Bar").unwrap()); + layout.draw().unwrap(); let uart = Uart::new( peripherals.UART1, diff --git a/firmware/src/layout/mod.rs b/firmware/src/layout/mod.rs index e4d6d44..ea5e11f 100644 --- a/firmware/src/layout/mod.rs +++ b/firmware/src/layout/mod.rs @@ -11,11 +11,13 @@ use embedded_graphics::{ }; use heapless::String; +type DisplayText = String<16>; + pub struct DisplayLayout<'a, D> { display: &'a mut D, - top_text: String<16>, + top_text: DisplayText, top_box_color: Rgb565, - bottom_text: String<16>, + bottom_text: DisplayText, bottom_box_color: Rgb565, text_style: embedded_graphics::mono_font::MonoTextStyle<'a, Rgb565>, } @@ -73,13 +75,18 @@ where Ok(()) } - pub fn draw_top_text(&mut self, text: &str) -> Result<(), D::Error> { - Text::new(text, Point::new(5, 10), self.text_style).draw(self.display)?; + pub fn draw_top_text(&mut self) -> Result<(), D::Error> { + Text::new(self.top_text.as_str(), Point::new(5, 10), self.text_style).draw(self.display)?; Ok(()) } - pub fn draw_bottom_text(&mut self, text: &str) -> Result<(), D::Error> { - Text::new(text, Point::new(5, 210), self.text_style).draw(self.display)?; + pub fn draw_bottom_text(&mut self) -> Result<(), D::Error> { + Text::new( + self.bottom_text.as_str(), + Point::new(5, 210), + self.text_style, + ) + .draw(self.display)?; Ok(()) } @@ -101,10 +108,18 @@ where self.bottom_box_color = colour; } - pub fn draw(&mut self, top_text: &str, bottom_text: &str) -> Result<(), D::Error> { + pub fn set_top_text(&mut self, text: DisplayText) { + self.top_text = text; + } + + pub fn set_bottom_text(&mut self, text: DisplayText) { + self.bottom_text = text; + } + + pub fn draw(&mut self) -> Result<(), D::Error> { self.draw_boxes()?; - self.draw_top_text(top_text)?; - self.draw_bottom_text(bottom_text)?; + self.draw_top_text()?; + self.draw_bottom_text()?; self.clear_middle()?; Ok(()) } From b05af82b56a363a918baf3c01f290b55e1718a75 Mon Sep 17 00:00:00 2001 From: issy Date: Fri, 27 Feb 2026 18:02:54 +0000 Subject: [PATCH 8/8] Put import at the top --- firmware/src/bin/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/src/bin/main.rs b/firmware/src/bin/main.rs index a22cdb1..81ba023 100644 --- a/firmware/src/bin/main.rs +++ b/firmware/src/bin/main.rs @@ -20,6 +20,7 @@ use esp_backtrace as _; use core::cell::RefCell; use core::ops::Add; +use core::str::FromStr; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice; use embassy_executor::{Spawner, task}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; @@ -87,7 +88,6 @@ async fn midi_out_task(mut uart: UartTx<'static, Async>) { clippy::large_stack_frames, reason = "it's not unusual to allocate larger buffers etc. in main" )] -use core::str::FromStr; #[esp_rtos::main] async fn main(spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env();