This commit is contained in:
2026-09-07 23:33:05 -05:00
parent 3ad59eac09
commit 8d8eabc56b
5 changed files with 626 additions and 87 deletions
Generated
+396
View File
@@ -2,6 +2,21 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c583acf993cf4245c4acb0a2cc2ab1f9cc097de73411bb6d3647ff6af2b1013d"
[[package]]
name = "autocfg"
version = "1.5.1"
@@ -70,12 +85,38 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "005ec2760ca554fae18df7a11195552ec576cd665632a881bc011d5bb2fd4d80"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "const-default"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa"
[[package]]
name = "cordyceps"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9ab7e0ca1d179628fa0172b2b97203c7fa0cd81be2448bd446fb9559ca9261"
dependencies = [
"loom",
"tracing",
]
[[package]]
name = "cpufeatures"
version = "0.3.1"
@@ -110,6 +151,16 @@ dependencies = [
"hybrid-array",
]
[[package]]
name = "darling"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
dependencies = [
"darling_core 0.20.11",
"darling_macro 0.20.11",
]
[[package]]
name = "darling"
version = "0.21.3"
@@ -130,6 +181,20 @@ dependencies = [
"darling_macro 0.24.1",
]
[[package]]
name = "darling_core"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.119",
]
[[package]]
name = "darling_core"
version = "0.21.3"
@@ -156,6 +221,17 @@ dependencies = [
"syn 3.0.5",
]
[[package]]
name = "darling_macro"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core 0.20.11",
"quote",
"syn 2.0.119",
]
[[package]]
name = "darling_macro"
version = "0.21.3"
@@ -266,6 +342,37 @@ dependencies = [
"nb 1.1.0",
]
[[package]]
name = "embassy-executor"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d0d3b15c9d7dc4fec1d8cb77112472fb008b3b28c51ad23838d83587a6d2f1e"
dependencies = [
"cordyceps",
"critical-section",
"document-features",
"embassy-executor-macros",
"embassy-executor-timer-queue",
]
[[package]]
name = "embassy-executor-macros"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d11a246f53de5f97a387f40ac24726817cd0b6f833e7603baac784f29d6ff276"
dependencies = [
"darling 0.20.11",
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "embassy-executor-timer-queue"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c"
[[package]]
name = "embassy-futures"
version = "0.1.2"
@@ -323,6 +430,41 @@ dependencies = [
"heapless 0.9.3",
]
[[package]]
name = "embassy-time"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "592b0c143ec626e821d4d90da51a2bd91d559d6c442b7c74a47d368c9e23d97a"
dependencies = [
"cfg-if",
"critical-section",
"document-features",
"embassy-time-driver",
"embedded-hal 0.2.7",
"embedded-hal 1.0.0",
"embedded-hal-async",
"futures-core",
]
[[package]]
name = "embassy-time-driver"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ee71af1b3a0deaa53eaf2d39252f83504c853646e472400b763060389b9fcc9"
dependencies = [
"document-features",
]
[[package]]
name = "embassy-time-queue-utils"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168297bf80aaf114b3c9ad589bf38b01b3009b9af7f97cd18086c5bbf96f5693"
dependencies = [
"embassy-executor-timer-queue",
"heapless 0.9.3",
]
[[package]]
name = "embedded-can"
version = "0.4.1"
@@ -462,6 +604,22 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "esp-alloc"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f73e8d355019c740f6a5a78429633040617d28a378c271464caadc52c78216e3"
dependencies = [
"allocator-api2",
"document-features",
"enumset",
"esp-config",
"esp-metadata-generated",
"esp-sync",
"linked_list_allocator",
"rlsf",
]
[[package]]
name = "esp-backtrace"
version = "0.20.0"
@@ -634,6 +792,29 @@ dependencies = [
"esp32c6",
]
[[package]]
name = "esp-rtos"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f8e99f512a839c78a77c2e55e1f0d208851cfa48935847d5e0b5e8b2c5a6289"
dependencies = [
"document-features",
"embassy-executor",
"embassy-sync 0.8.0",
"embassy-time-driver",
"embassy-time-queue-utils",
"esp-alloc",
"esp-config",
"esp-hal",
"esp-hal-procmacros",
"esp-metadata-generated",
"esp-rom-sys",
"esp-sync",
"portable-atomic",
"riscv",
"xtensa-lx",
]
[[package]]
name = "esp-storage"
version = "0.10.0"
@@ -769,18 +950,28 @@ dependencies = [
name = "espboard"
version = "0.1.0"
dependencies = [
"embassy-executor",
"embassy-time",
"embedded-graphics",
"embedded-hal 1.0.0",
"embedded-hal-bus",
"esp-backtrace",
"esp-bootloader-esp-idf",
"esp-hal",
"esp-hal-smartled",
"esp-println",
"esp-rtos",
"mipidsi",
"smart-leds",
"smart-leds-trait",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d"
[[package]]
name = "float-cmp"
version = "0.9.0"
@@ -840,6 +1031,21 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
[[package]]
name = "generator"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae"
dependencies = [
"cc",
"cfg-if",
"libc",
"log",
"rustversion",
"windows-link",
"windows-result",
]
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -980,12 +1186,24 @@ dependencies = [
"syn 2.0.119",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
name = "linked_list_allocator"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b23ac50abb8261cb38c6e2a7192d3302e0836dac1628f6a93b82b4fad185897"
[[package]]
name = "litrs"
version = "1.0.0"
@@ -998,6 +1216,28 @@ version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
[[package]]
name = "loom"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
dependencies = [
"cfg-if",
"generator",
"scoped-tls",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]]
name = "memchr"
version = "2.8.3"
@@ -1036,6 +1276,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -1054,6 +1303,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "paste"
version = "1.0.15"
@@ -1126,6 +1381,23 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "regex-automata"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "rgb"
version = "0.8.53"
@@ -1191,6 +1463,18 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1376b15f3ff160e9b1e8ea564ce427f2f6fcf77528cc0a8bf405cb476f9cea7"
[[package]]
name = "rlsf"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07393724337be2ee43a9d86164df4505746874a3fa65913374bc6d6a92314362"
dependencies = [
"cfg-if",
"const-default",
"libc",
"rustversion",
]
[[package]]
name = "rustversion"
version = "1.0.23"
@@ -1203,6 +1487,12 @@ version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "serde"
version = "1.0.229"
@@ -1257,6 +1547,27 @@ dependencies = [
"digest 0.11.3",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]]
name = "shlex"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "smallvec"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f"
[[package]]
name = "smart-leds"
version = "0.4.0"
@@ -1394,6 +1705,15 @@ dependencies = [
"syn 3.0.5",
]
[[package]]
name = "thread_local"
version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070"
dependencies = [
"cfg-if",
]
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
@@ -1424,6 +1744,67 @@ dependencies = [
"winnow",
]
[[package]]
name = "tracing"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "tracing-core"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex-automata",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
name = "typenum"
version = "1.20.1"
@@ -1448,6 +1829,12 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "vcell"
version = "0.1.3"
@@ -1481,6 +1868,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
+4
View File
@@ -5,12 +5,16 @@ edition = "2024"
[dependencies]
embedded-graphics = "0.8"
embedded-hal = "1.0"
embedded-hal-bus = "0.3"
embassy-executor = "0.10"
embassy-time = "0.5"
esp-backtrace = { version = "0.20.0", features = ["esp32c6", "println", "panic-handler"] }
esp-bootloader-esp-idf = { version = "0.6.0", features = ["esp32c6"] }
esp-hal = { version = "1.2.0", features = ["esp32c6", "unstable"] }
esp-hal-smartled = { version = "0.18", default-features = false, features = ["esp32c6"] }
esp-println = { version = "0.18.0", default-features = false, features = ["esp32c6", "jtag-serial"] }
esp-rtos = { version = "0.4", features = ["embassy", "esp32c6"] }
mipidsi = "0.10"
smart-leds = "0.4"
smart-leds-trait = "0.3"
+121 -30
View File
@@ -1,11 +1,10 @@
use embedded_hal_bus::spi::{ExclusiveDevice, NoDelay};
use esp_hal::delay::Delay;
use embedded_hal::spi::{ErrorType, Operation, SpiDevice};
use esp_hal::gpio::{Level, Output, OutputConfig};
use esp_hal::peripherals::{GPIO14, GPIO15, GPIO21, GPIO6, GPIO7, SPI2};
use esp_hal::spi::master::{Config as SpiConfig, Spi};
use esp_hal::spi::Mode;
use esp_hal::peripherals::{DMA_CH0, GPIO14, GPIO15, GPIO21, GPIO6, GPIO7, SPI2};
use esp_hal::spi::master::{Config as SpiConfig, Spi, SpiDma};
use esp_hal::spi::{Error as SpiError, Mode};
use esp_hal::time::Rate;
use esp_hal::Blocking;
use esp_hal::Async;
use mipidsi::interface::SpiInterface;
use mipidsi::models::ST7789;
use mipidsi::options::{ColorInversion, ColorOrder, Orientation, Rotation};
@@ -14,43 +13,97 @@ use mipidsi::{Builder, Display};
pub const WIDTH: u32 = 172;
pub const HEIGHT: u32 = 320;
const SPI_FREQ: Rate = Rate::from_mhz(40);
const SPI_FREQ: Rate = Rate::from_mhz(60);
/// Column offset of the 172-px-wide panel within the ST7789's 240-px framebuffer.
const COLUMN_OFFSET: u16 = 34;
type Device = ExclusiveDevice<Spi<'static, Blocking>, Output<'static>, NoDelay>;
type Interface<'a> = SpiInterface<'a, Device, Output<'static>>;
/// Size of the internal DMA copy buffer used by `write_async`.
const DMA_BUF_SIZE: usize = 32000;
/// The mipidsi [`Display`], which implements embedded-graphics' [`DrawTarget`].
///
/// The lifetime is the borrow of the pixel buffer passed to [`init`].
pub type SpiDmaBus = SpiDma<'static, Async>;
/// SPI bus + CS, presented to mipidsi as an `SpiDevice` for init, while keeping
/// the raw pieces recoverable for the async framebuffer path.
pub struct LcdDevice {
spi: SpiDmaBus,
cs: Output<'static>,
}
impl LcdDevice {
pub fn into_inner(self) -> (SpiDmaBus, Output<'static>) {
(self.spi, self.cs)
}
}
impl ErrorType for LcdDevice {
type Error = SpiError;
}
impl SpiDevice for LcdDevice {
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
self.cs.set_low();
let result = (|| {
for operation in operations {
match operation {
Operation::Write(buf) => self.spi.write(buf)?,
Operation::Read(buf) => self.spi.read(buf)?,
Operation::Transfer(read, write) => self.spi.transfer(read, write)?,
Operation::TransferInPlace(buf) => self.spi.transfer_in_place(buf)?,
Operation::DelayNs(_) => {},
}
}
Ok(())
})();
self.cs.set_high();
result
}
}
type Interface<'a> = SpiInterface<'a, LcdDevice, Output<'static>>;
/// The mipidsi [`Display`] used to initialize the panel.
pub type Lcd<'a> = Display<Interface<'a>, ST7789, Output<'static>>;
pub fn init<'a>(
spi2: SPI2<'static>,
sck: GPIO7<'static>,
mosi: GPIO6<'static>,
dc: GPIO15<'static>,
cs: GPIO14<'static>,
rst: GPIO21<'static>,
buffer: &'a mut [u8],
) -> Lcd<'a> {
let spi = Spi::new(spi2, SpiConfig::default().with_frequency(SPI_FREQ).with_mode(Mode::_0))
.expect("Failed to configure SPI")
.with_sck(sck)
.with_mosi(mosi);
/// All the peripheral resources the LCD needs.
pub struct LcdPins {
pub spi2: SPI2<'static>,
pub sck: GPIO7<'static>,
pub mosi: GPIO6<'static>,
pub dc: GPIO15<'static>,
pub cs: GPIO14<'static>,
pub rst: GPIO21<'static>,
pub dma_ch: DMA_CH0<'static>,
}
let cs_pin = Output::new(cs, Level::High, OutputConfig::default());
let device = ExclusiveDevice::new_no_delay(spi, cs_pin).expect("Failed to create SPI device");
pub fn init<'a>(pins: LcdPins, buffer: &'a mut [u8]) -> Lcd<'a> {
let dma_tx_buf = esp_hal::dma_tx_buffer!(DMA_BUF_SIZE).expect("Failed to create DMA TX buffer");
let dma_rx_buf = esp_hal::dma_rx_buffer!(4).expect("Failed to create DMA RX buffer");
let dc_pin = Output::new(dc, Level::Low, OutputConfig::default());
let spi = Spi::new(
pins.spi2,
SpiConfig::default().with_frequency(SPI_FREQ).with_mode(Mode::_0),
)
.expect("Failed to configure SPI")
.with_sck(pins.sck)
.with_mosi(pins.mosi)
.with_dma(pins.dma_ch)
.with_buffers(dma_rx_buf, dma_tx_buf)
.into_async();
let cs_pin = Output::new(pins.cs, Level::High, OutputConfig::default());
let device = LcdDevice {
spi,
cs: cs_pin,
};
let dc_pin = Output::new(pins.dc, Level::Low, OutputConfig::default());
let interface = SpiInterface::new(device, dc_pin, buffer);
let mut rst_pin = Output::new(rst, Level::High, OutputConfig::default());
let mut rst_pin = Output::new(pins.rst, Level::High, OutputConfig::default());
rst_pin.set_high();
let mut delay = Delay::new();
let mut delay = esp_hal::delay::Delay::new();
Builder::new(ST7789, interface)
.display_size(WIDTH as u16, HEIGHT as u16)
@@ -62,3 +115,41 @@ pub fn init<'a>(
.init(&mut delay)
.expect("Failed to init display")
}
/// Stream a full framebuffer to the panel asynchronously (DMA).
///
/// Sends the address window and RAMWR command, then the pixel bytes as one
/// (internally chunked) DMA transfer. Returns when the transfer completes.
pub async fn send_framebuffer(
spi: &mut SpiDmaBus,
dc: &mut Output<'static>,
cs: &mut Output<'static>,
bytes: &[u8],
) -> Result<(), SpiError> {
let x0 = COLUMN_OFFSET;
let x1 = COLUMN_OFFSET + WIDTH as u16 - 1;
let y1 = HEIGHT as u16 - 1;
cs.set_low();
// MIPI DCS: DC low for the command byte, high for its arguments.
dc.set_low();
spi.write_async(&[0x2A]).await?;
dc.set_high();
spi.write_async(&[(x0 >> 8) as u8, x0 as u8, (x1 >> 8) as u8, x1 as u8])
.await?;
dc.set_low();
spi.write_async(&[0x2B]).await?;
dc.set_high();
spi.write_async(&[0, 0, (y1 >> 8) as u8, y1 as u8]).await?;
dc.set_low();
spi.write_async(&[0x2C]).await?;
dc.set_high();
spi.write_async(bytes).await?;
cs.set_high();
Ok(())
}
+20 -18
View File
@@ -1,32 +1,37 @@
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::geometry::{OriginDimensions, Size};
use embedded_graphics::pixelcolor::{Rgb565, RgbColor};
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::IntoStorage;
use embedded_graphics::Pixel;
use crate::display::{HEIGHT, WIDTH};
const PIXEL_COUNT: usize = (WIDTH * HEIGHT) as usize;
const BYTE_COUNT: usize = PIXEL_COUNT * 2;
/// The full-screen back buffer (172 × 320 × 2 bytes ≈ 110 KB).
static mut PIXELS: [Rgb565; PIXEL_COUNT] = [Rgb565::BLACK; PIXEL_COUNT];
/// Full-screen back buffer (172 × 320 × 2 bytes ≈ 110 KB).
///
/// Pixels are stored as RGB565 **big-endian** byte pairs, which is the wire
/// format the ST7789 expects, so the buffer can be handed straight to DMA.
static mut PIXELS: [u8; BYTE_COUNT] = [0; BYTE_COUNT];
/// A full-frame framebuffer that implements embedded-graphics' [`DrawTarget`].
///
/// Draw primitives into it, then blit the whole thing to the display once per
/// frame to avoid flicker. The backing memory is a `static`, so this is only
/// safe to use from a single thread (which is all this application has).
/// safe to use from a single task (the display task).
pub struct Framebuffer;
impl Framebuffer {
pub fn clear(&mut self) {
// SAFETY: only used from the single main loop.
unsafe { &mut *core::ptr::addr_of_mut!(PIXELS) }.fill(Rgb565::BLACK);
// SAFETY: only used from the single display task.
unsafe { &mut *core::ptr::addr_of_mut!(PIXELS) }.fill(0);
}
/// The raw pixels, ready to be sent to the display.
pub fn pixels(&self) -> &'static [Rgb565] {
// SAFETY: the buffer lives for the whole program and is only borrowed
// for the duration of the (blocking) blit.
/// The pixels as bytes in the display's wire format (RGB565 big-endian).
pub fn as_bytes(&self) -> &'static [u8] {
// SAFETY: the buffer lives for the whole program and is only read for
// the duration of the (blocking-await) blit.
unsafe { &*core::ptr::addr_of!(PIXELS) }
}
}
@@ -39,13 +44,16 @@ impl DrawTarget for Framebuffer {
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
// SAFETY: only used from the single main loop.
// SAFETY: only used from the single display task.
let buffer = unsafe { &mut *core::ptr::addr_of_mut!(PIXELS) };
for pixel in pixels {
let (x, y) = (pixel.0.x, pixel.0.y);
if x >= 0 && y >= 0 && x < WIDTH as i32 && y < HEIGHT as i32 {
buffer[(y as usize) * WIDTH as usize + (x as usize)] = pixel.1;
let idx = (y as usize) * WIDTH as usize + (x as usize);
let value = pixel.1.into_storage();
buffer[idx * 2] = (value >> 8) as u8;
buffer[idx * 2 + 1] = value as u8;
}
}
@@ -58,9 +66,3 @@ impl OriginDimensions for Framebuffer {
Size::new(WIDTH, HEIGHT)
}
}
impl Default for Framebuffer {
fn default() -> Self {
Self
}
}
+85 -39
View File
@@ -6,55 +6,53 @@ mod display;
mod framebuffer;
mod led;
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::*;
use embedded_graphics::primitives::{PrimitiveStyle, Rectangle, Triangle};
use embedded_graphics::primitives::{PrimitiveStyle, Triangle};
use embassy_executor::Spawner;
use embassy_time::Timer;
use esp_backtrace as _;
use esp_bootloader_esp_idf::esp_app_desc;
use esp_hal::gpio::Output;
use esp_hal::timer::timg::TimerGroup;
use esp_hal::{init, rmt::Rmt, time::Rate, Config};
use esp_println::println;
use smart_leds::hsv::{hsv2rgb, Hsv};
use smart_leds::RGB8;
const SAT: u8 = 200;
const VAL: u8 = 200;
const SAT: u8 = 255;
const VAL: u8 = 255;
esp_app_desc!();
#[esp_hal::main]
fn main() -> ! {
let peripherals = init(Config::default());
#[embassy_executor::task]
async fn led_task(mut led: led::RgbLed) {
let mut frame = 0u32;
loop {
let hue = (frame % 256) as u8;
let lit = hsv2rgb(Hsv {
hue,
sat: SAT,
val: VAL,
});
led.set_rgb(lit).unwrap();
Timer::after_millis(30).await;
frame = frame.wrapping_add(1);
}
}
let mut led = {
let rmt = Rmt::new(peripherals.RMT, Rate::from_mhz(80)).expect("Failed to init RMT");
led::RgbLed::new(rmt.channel0, peripherals.GPIO8).expect("Failed to init RGB LED")
};
let (_ledc, timer) =
backlight::setup_timer(peripherals.LEDC).expect("Failed to init backlight timer");
#[embassy_executor::task]
async fn display_task(
mut spi: display::SpiDmaBus,
mut dc: Output<'static>,
mut cs: Output<'static>,
mut fb: framebuffer::Framebuffer,
timer: esp_hal::ledc::timer::Timer<'static, esp_hal::ledc::LowSpeed>,
bl_pin: esp_hal::peripherals::GPIO22<'static>,
) {
let mut backlight =
backlight::LcdBacklight::new(&timer, peripherals.GPIO22).expect("Failed to init backlight");
backlight::LcdBacklight::new(&timer, bl_pin).expect("Failed to init backlight");
backlight.set_level(0.5).unwrap();
let mut buffer = [0u8; 4096];
let mut lcd = display::init(
peripherals.SPI2,
peripherals.GPIO7,
peripherals.GPIO6,
peripherals.GPIO15,
peripherals.GPIO14,
peripherals.GPIO21,
&mut buffer,
);
let delay = esp_hal::delay::Delay::new();
println!("LCD {}x{} initialized", display::WIDTH, display::HEIGHT);
lcd.clear(Rgb565::BLACK).unwrap();
let mut fb = framebuffer::Framebuffer;
let screen = Rectangle::new(Point::zero(), Size::new(display::WIDTH, display::HEIGHT));
println!("backlight set to 0.5");
let mut pts = [
Point::new(86, 20),
@@ -72,8 +70,7 @@ fn main() -> ! {
sat: SAT,
val: VAL,
});
led.set_rgb(RGB8::new(0,0,0)).unwrap();
let accent = Rgb565::new(lit.r / 8, lit.g / 4, lit.b / 8);
let accent = Rgb565::new(lit.r/8, lit.g/4, lit.b/8);
for p in &mut pts {
p.x += vx;
@@ -98,7 +95,8 @@ fn main() -> ! {
.draw(&mut fb)
.unwrap();
lcd.fill_contiguous(&screen, fb.pixels().iter().cloned())
display::send_framebuffer(&mut spi, &mut dc, &mut cs, fb.as_bytes())
.await
.unwrap();
if frame % 32 == 0 {
@@ -109,6 +107,54 @@ fn main() -> ! {
}
frame = frame.wrapping_add(1);
//delay.delay_millis(30);
}
}
#[esp_rtos::main]
async fn main(spawner: Spawner) -> ! {
let peripherals = init(Config::default());
let timg0 = TimerGroup::new(peripherals.TIMG0);
esp_rtos::start(timg0.timer0, peripherals.FROM_CPU_INTR0);
let led = {
let rmt = Rmt::new(peripherals.RMT, Rate::from_mhz(80)).expect("Failed to init RMT");
led::RgbLed::new(rmt.channel0, peripherals.GPIO8).expect("Failed to init RGB LED")
};
let (_ledc, timer) =
backlight::setup_timer(peripherals.LEDC).expect("Failed to init backlight timer");
let mut buffer = [0u8; 4096];
let lcd = display::init(
display::LcdPins {
spi2: peripherals.SPI2,
sck: peripherals.GPIO7,
mosi: peripherals.GPIO6,
dc: peripherals.GPIO15,
cs: peripherals.GPIO14,
rst: peripherals.GPIO21,
dma_ch: peripherals.DMA_CH0,
},
&mut buffer,
);
let (interface, _model, _rst) = lcd.release();
let (device, dc) = interface.release();
let (spi, cs) = device.into_inner();
println!("LCD {}x{} initialized", display::WIDTH, display::HEIGHT);
spawner.spawn(led_task(led).unwrap());
spawner.spawn(display_task(
spi,
dc,
cs,
framebuffer::Framebuffer,
timer,
peripherals.GPIO22,
).unwrap());
loop {
Timer::after_millis(1000).await;
}
}