Add firmware

This commit is contained in:
Jakub Hlusička 2025-10-09 00:03:12 +02:00
parent 2e69cea11c
commit 2521dc7949
11 changed files with 2681 additions and 0 deletions

View file

@ -0,0 +1,16 @@
[target.xtensa-esp32s3-none-elf]
runner = "espflash flash --monitor --chip esp32s3"
[env]
ESP_LOG="info"
[build]
rustflags = [
"-C", "link-arg=-nostartfiles",
"-Z", "stack-protector=all",
]
target = "xtensa-esp32s3-none-elf"
[unstable]
build-std = ["alloc", "core"]

42
firmware/.github/workflows/rust_ci.yml vendored Normal file
View file

@ -0,0 +1,42 @@
name: Continuous Integration
on:
push:
branches:
- main
paths-ignore:
- "**/README.md"
pull_request:
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
rust-checks:
name: Rust Checks
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
action:
- command: build
args: --release
- command: fmt
args: --all -- --check
- command: clippy
args: --all-features --workspace -- -D warnings
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Rust
uses: esp-rs/xtensa-toolchain@v1.5
with:
default: true
buildtargets: esp32s3
ldproxy: false
- name: Enable caching
uses: Swatinem/rust-cache@v2
- name: Run command
run: cargo ${{ matrix.action.command }} ${{ matrix.action.args }}

19
firmware/.gitignore vendored Normal file
View file

@ -0,0 +1,19 @@
# will have compiled files and executables
debug/
target/
.vscode/
.zed/
.helix/
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

1469
firmware/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

52
firmware/Cargo.toml Normal file
View file

@ -0,0 +1,52 @@
[package]
edition = "2021"
name = "acid-firmware"
rust-version = "1.86"
version = "0.1.0"
[[bin]]
name = "acid-firmware"
path = "./src/bin/main.rs"
[dependencies]
# TODO: Remove the `git = ...` fields, which are here because IntelliSense is broken in 1.0.0-rc.0
esp-bootloader-esp-idf = { version = "0.2.0", git = "https://github.com/esp-rs/esp-hal", features = ["esp32s3"] }
esp-hal = { version = "=1.0.0-rc.0", git = "https://github.com/esp-rs/esp-hal", features = [
"esp32s3",
"log-04",
"unstable",
"psram",
] }
log = "0.4.27"
critical-section = "1.2.0"
embassy-executor = { version = "0.9.0", features = [
"log",
# "task-arena-size-20480",
] }
embassy-time = { version = "0.4.0", features = ["log"] }
esp-alloc = { version = "0.8.0", git = "https://github.com/esp-rs/esp-hal" }
esp-backtrace = { version = "0.17.0", git = "https://github.com/esp-rs/esp-hal", features = [
"esp32s3",
# "exception-handler",
"panic-handler",
"println",
] }
esp-hal-embassy = { version = "0.9.0", git = "https://github.com/esp-rs/esp-hal", features = ["esp32s3", "log-04"] }
esp-println = { version = "0.15.0", git = "https://github.com/esp-rs/esp-hal", features = ["esp32s3", "log-04"] }
static_cell = "2.1.1"
[profile.dev]
# Rust debug is too slow.
# For debug builds always builds with some optimization
opt-level = "s"
[profile.release]
codegen-units = 1 # LLVM can perform better optimizations using a single thread
debug = 2
debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 's'
overflow-checks = false

20
firmware/README.md Normal file
View file

@ -0,0 +1,20 @@
# Building and running
```
cargo build --release && espflash flash --port COM5 .\target\xtensa-esp32s3-none-elf\release\acid-firmware --monitor
```
A different port may need to be chosen.
# Monitoring
```
espflash monitor -p COM5
```
A different port may need to be chosen.
# Debugging
Sometimes the firmware keeps crashing.
Pulling GPIO0 high during reset seems to fix this?

52
firmware/build.rs Normal file
View file

@ -0,0 +1,52 @@
fn main() {
linker_be_nice();
// make sure linkall.x is the last linker script (otherwise might cause problems with flip-link)
println!("cargo:rustc-link-arg=-Tlinkall.x");
}
fn linker_be_nice() {
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 {
let kind = &args[1];
let what = &args[2];
match kind.as_str() {
"undefined-symbol" => match what.as_str() {
"_defmt_timestamp" => {
eprintln!();
eprintln!("💡 `defmt` not found - make sure `defmt.x` is added as a linker script and you have included `use defmt_rtt as _;`");
eprintln!();
}
"_stack_start" => {
eprintln!();
eprintln!("💡 Is the linker script `linkall.x` missing?");
eprintln!();
}
"esp_wifi_preempt_enable"
| "esp_wifi_preempt_yield_task"
| "esp_wifi_preempt_task_create" => {
eprintln!();
eprintln!("💡 `esp-wifi` has no scheduler enabled. Make sure you have the `builtin-scheduler` feature enabled, or that you provide an external scheduler.");
eprintln!();
}
"embedded_test_linker_file_not_added_to_rustflags" => {
eprintln!();
eprintln!("💡 `embedded-test` not found - make sure `embedded-test.x` is added as a linker script for tests");
eprintln!();
}
_ => (),
},
// we don't have anything helpful for "missing-lib" yet
_ => {
std::process::exit(1);
}
}
std::process::exit(0);
}
println!(
"cargo:rustc-link-arg=-Wl,--error-handling-script={}",
std::env::current_exe().unwrap().display()
);
}

View file

@ -0,0 +1,2 @@
[toolchain]
channel = "esp"

996
firmware/src/bin/main.rs Normal file
View file

@ -0,0 +1,996 @@
#![no_std]
#![no_main]
#![deny(
clippy::mem_forget,
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
holding buffers for the duration of a data transfer."
)]
#![feature(iter_intersperse)]
#![feature(allocator_api)]
use core::alloc::{GlobalAlloc, Layout};
use core::future::IntoFuture;
use core::iter::once;
use alloc::vec::Vec;
use embassy_executor::Spawner;
use embassy_time::{Duration, Timer};
use esp_alloc::{HeapRegion, MemoryCapability};
use esp_backtrace as _;
use esp_hal::clock::CpuClock;
use esp_hal::delay::Delay;
use esp_hal::dma::{
Channel, DmaChannel, DmaDescriptor, DmaDescriptorFlags, DmaLoopBuf, DmaRxTxBuf, DmaTxBuf,
};
use esp_hal::gpio::{self, Flex, Level, Output, OutputConfig, OutputPin, Pin};
use esp_hal::lcd_cam::lcd::dpi::{self, Dpi, Format, FrameTiming};
use esp_hal::lcd_cam::lcd::{self, ClockMode, DelayMode, Lcd, Phase, Polarity};
use esp_hal::lcd_cam::{BitOrder, LcdCam};
use esp_hal::mcpwm::operator::PwmPin;
use esp_hal::mcpwm::{McPwm, PeripheralClockConfig};
use esp_hal::peripherals::PSRAM;
use esp_hal::rtc_cntl::sleep;
use esp_hal::spi::master::{Address, Command, DataMode, Spi};
use esp_hal::time::Rate;
use esp_hal::timer::systimer::SystemTimer;
use esp_hal::{dma_buffers, dma_loop_buffer, dma_tx_buffer, Async};
use log::info;
extern crate alloc;
// This creates a default app-descriptor required by the esp-idf bootloader.
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
esp_bootloader_esp_idf::esp_app_desc!();
static PSRAM_ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
#[esp_hal_embassy::main]
async fn main(spawner: Spawner) {
// generator version: 0.5.0
esp_println::logger::init_logger_from_env();
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals: esp_hal::peripherals::Peripherals = esp_hal::init(config);
// Initialize the PSRAM allocator.
{
let (psram_offset, psram_size) = esp_hal::psram::psram_raw_parts(&peripherals.PSRAM);
unsafe {
PSRAM_ALLOCATOR.add_region(HeapRegion::new(
psram_offset,
psram_size,
MemoryCapability::External.into(),
));
}
}
let dma_buf_desc = DmaDescriptor {
buffer: unsafe {
PSRAM_ALLOCATOR.alloc(Layout::from_size_align(2 * 360 * 960, 32).unwrap())
},
next: core::ptr::null_mut(),
flags: {
let mut flags = DmaDescriptorFlags(0);
flags.set_length(2 * 360 * 960);
flags.set_owner(false);
flags.set_size(2 * 360 * 960);
flags.set_suc_eof(false);
flags
},
};
// let dma_buf = DmaTxBuf::new(&[dma_buf_desc], todo!()).unwrap();
// Use the internal DRAM as the heap.
esp_alloc::heap_allocator!(#[link_section = ".dram2_uninit"] size: 64 * 1024);
let timer0 = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(timer0.alarm0);
info!("Embassy initialized!");
// TODO: Spawn some tasks
let _ = spawner;
// Enable LDO2
let _ = Output::new(peripherals.GPIO17, Level::High, OutputConfig::default());
// let mut o = Output::new(peripherals.GPIO35, Level::Low, OutputConfig::default());
// loop {
// o.set_high();
// Timer::after(Duration::from_secs(1)).await;
// o.set_low();
// Timer::after(Duration::from_secs(1)).await;
// info!("yeet");
// Timer::after(Duration::from_secs(1)).await;
// }
// let mut x = Spi::new(
// peripherals.SPI2,
// esp_hal::spi::master::Config::default().with_frequency(Rate::from_mhz(1)), // For debugging
// )
// .unwrap()
// .with_mosi(peripherals.GPIO35)
// .with_sck(peripherals.GPIO36);
// let init = [
// &b"\xff\x05w\x01\x00\x00\x13"[..],
// b"\xef\x01\x08",
// b"\xff\x05w\x01\x00\x00\x10",
// b"\xc0\x02w\x00",
// b"\xc1\x02\x11\x0c",
// b"\xc2\x02\x07\x02",
// b"\xcc\x010",
// b"\xb0\x10\x06\xcf\x14\x0c\x0f\x03\x00\n\x07\x1b\x03\x12\x10%6\x1e",
// b"\xb1\x10\x0c\xd4\x18\x0c\x0e\x06\x03\x06\x08#\x06\x12\x100/\x1f",
// b"\xff\x05w\x01\x00\x00\x11",
// b"\xb0\x01s",
// b"\xb1\x01|",
// b"\xb2\x01\x83",
// b"\xb3\x01\x80",
// b"\xb5\x01I",
// b"\xb7\x01\x87",
// b"\xb8\x013",
// b"\xb9\x02\x10\x1f",
// b"\xbb\x01\x03",
// b"\xc1\x01\x08",
// b"\xc2\x01\x08",
// b"\xd0\x01\x88",
// b"\xe0\x06\x00\x00\x02\x00\x00\x0c",
// b"\xe1\x0b\x05\x96\x07\x96\x06\x96\x08\x96\x00DD",
// b"\xe2\x0c\x00\x00\x03\x03\x00\x00\x02\x00\x00\x00\x02\x00",
// b"\xe3\x04\x00\x0033",
// b"\xe4\x02DD",
// b"\xe5\x10\r\xd4(\x8c\x0f\xd6(\x8c\t\xd0(\x8c\x0b\xd2(\x8c",
// b"\xe6\x04\x00\x0033",
// b"\xe7\x02DD",
// b"\xe8\x10\x0e\xd5(\x8c\x10\xd7(\x8c\n\xd1(\x8c\x0c\xd3(\x8c",
// b"\xeb\x06\x00\x01\xe4\xe4D\x00",
// b"\xed\x10\xf3\xc1\xba\x0ffwDUUDwf\xf0\xab\x1c?",
// b"\xef\x06\x10\r\x04\x08?\x1f",
// b"\xff\x05w\x01\x00\x00\x13",
// b"\xe8\x02\x00\x0e",
// b"\x11\x80x",
// b"\xe8\x82\x00\x0c\n",
// b"\xe8\x02@\x00",
// b"\xff\x05w\x01\x00\x00\x00",
// b"6\x01\x00",
// b":\x01f",
// b")\x80\x14",
// b"\xff\x05w\x01\x00\x00\x10",
// b"\xe5\x02\x00\x00",
// ]
// .into_iter()
// .flatten()
// .copied()
// .collect::<Vec<u8>>();
// info!("init sequence writing");
// x.write(&init).unwrap();
// info!("init sequence written");
// TODO: Use PWM to control the pwm_pin.
let mut _pwm = McPwm::new(peripherals.MCPWM0, PeripheralClockConfig::with_prescaler(1));
let mut _pwm_pin = Output::new(peripherals.GPIO21, Level::High, OutputConfig::default());
let mut sck = Output::new(peripherals.GPIO36, Level::High, OutputConfig::default());
let mut mosi = Flex::new(peripherals.GPIO35);
let mut cs = Output::new(peripherals.GPIO6, Level::High, OutputConfig::default());
mosi.set_input_enable(false);
mosi.set_output_enable(true);
info!("init sequence writing");
cs.set_low();
for op in INIT_SEQUENCE {
match *op {
InitOp::WriteComm(data) => spi_write_word(false, data, &mut mosi, &mut sck),
InitOp::WriteData(data) => spi_write_word(true, data, &mut mosi, &mut sck),
InitOp::SleepMs(ms) => Timer::after_millis(ms).await,
_ => panic!(),
}
}
cs.set_high();
info!("init sequence written");
// Timer::after_secs(1).await;
// x.half_duplex_write(
// DataMode::Single,
// Command::_9Bit(0xFFFF, DataMode::Single),
// Address::None,
// 0,
// &[],
// )
// .unwrap();
// info!("Derp");
let mut lcd = LcdCam::new(peripherals.LCD_CAM).into_async().lcd;
let lcd_config = lcd::dpi::Config::default()
.with_frequency(Rate::from_mhz(16)) // From Adafruit
.with_clock_mode(ClockMode {
polarity: Polarity::IdleLow, // From Adafruit
phase: Phase::ShiftHigh, // From Adafruit
})
.with_format(Format {
enable_2byte_mode: true,
..Default::default()
})
.with_timing({
// Adafruit's config for this LCD:
// https://github.com/adafruit/Adafruit_CircuitPython_Qualia/blob/742d336e05e6a4d8bdaa46e15bbf60c9f30d2eba/adafruit_qualia/displays/bar240x960.py#L81-L97
// https://github.com/adafruit/Adafruit_CircuitPython_Qualia/blob/742d336e05e6a4d8bdaa46e15bbf60c9f30d2eba/adafruit_qualia/displays/__init__.py#L59-L62
// CircuitPython code handling Adafruit's config
// https://github.com/adafruit/circuitpython/blob/97c6617817e95b1f6aa2ce458778aaa8371de39b/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c#L63
let horizontal_resolution: usize = 240;
let vertical_resolution = 960;
let overscan_left = 120;
let vsync_width = 8;
let hsync_width = 8;
let horizontal_blank_front_porch = 20;
let horizontal_blank_back_porch = 20;
let vertical_blank_front_porch = 20;
let vertical_blank_back_porch = 20;
let hsync_position = 0;
let horizontal_active_width = (horizontal_resolution + overscan_left).div_ceil(16) * 16; // Round up to a multiple of 16.
let vertical_active_height = vertical_resolution;
FrameTiming {
horizontal_total_width: horizontal_active_width
+ hsync_width
+ horizontal_blank_back_porch
+ horizontal_blank_back_porch,
vertical_total_height: vertical_active_height
+ vsync_width
+ vertical_blank_back_porch
+ vertical_blank_front_porch,
horizontal_blank_front_porch,
vertical_blank_front_porch,
horizontal_active_width,
vertical_active_height,
vsync_width,
hsync_width,
hsync_position,
}
})
.with_hsync_idle_level(Level::High)
.with_vsync_idle_level(Level::High)
.with_de_idle_level(Level::Low);
// let mut dma_buf = dma_loop_buffer!(2 * 32);
let mut dma_buf = dma_tx_buffer!(2 * 960 * 320 / 4).unwrap();
// let tx_buf = dma_tx_buffer!(core::mem::size_of::<u16>() * 280 * 1000).unwrap();
// let (c_rx, c_tx) = peripherals.DMA_CH0.split();
// TODO: https://github.com/esp-rs/esp-hal/blob/main/qa-test/src/bin/lcd_dpi.rs
let mut dpi = Dpi::new(lcd, peripherals.DMA_CH2, lcd_config)
.unwrap()
.with_de(peripherals.GPIO37)
.with_pclk(peripherals.GPIO34)
.with_hsync(peripherals.GPIO44)
.with_vsync(peripherals.GPIO43)
// Blue
.with_data0(peripherals.GPIO38)
.with_data1(peripherals.GPIO39)
.with_data2(peripherals.GPIO40)
.with_data3(peripherals.GPIO41)
.with_data4(peripherals.GPIO42)
// Green
.with_data5(peripherals.GPIO5)
.with_data6(peripherals.GPIO12)
.with_data7(peripherals.GPIO13)
.with_data8(peripherals.GPIO14)
.with_data9(peripherals.GPIO15)
.with_data10(peripherals.GPIO16)
// Red
.with_data11(peripherals.GPIO0)
.with_data12(peripherals.GPIO1)
.with_data13(peripherals.GPIO2)
.with_data14(peripherals.GPIO3)
.with_data15(peripherals.GPIO4);
const MAX_RED: u8 = (1 << 5) - 1;
const MAX_GREEN: u8 = (1 << 6) - 1;
const MAX_BLUE: u8 = (1 << 5) - 1;
fn rgb(r: u8, g: u8, b: u8) -> u16 {
(((r & MAX_RED) as u16) << 11) | (((g & MAX_GREEN) as u16) << 5) | ((b & MAX_BLUE) as u16)
}
let mut colors = core::iter::empty()
// Start with red and gradually add green
.chain((0..=MAX_GREEN).map(|g| rgb(MAX_RED, g, 0)))
// Then remove the red
.chain((0..=MAX_RED).rev().map(|r| rgb(r, MAX_GREEN, 0)))
// Then add blue
.chain((0..=MAX_BLUE).map(|b| rgb(0, MAX_GREEN, b)))
// Then remove green
.chain((0..=MAX_GREEN).rev().map(|g| rgb(0, g, MAX_BLUE)))
// Then add red
.chain((0..=MAX_RED).map(|r| rgb(r, 0, MAX_BLUE)))
// Then remove blue
.chain((0..=MAX_BLUE).rev().map(|b| rgb(MAX_RED, 0, b)))
// Once we get we have red, and we can start again.
.cycle();
// let write = |command: u8, args: &[u8]| {
// // TODO: 3-wire SPI requires 9-bit words, where each 8-bit word is prefixed by 1 bit
// // signifying whether the word is a parameter or not.
// // Interleave into a buffer and terminate with NOP commands.
// x.half_duplex_write(
// DataMode::Single,
// Command::_9Bit(command as u16, DataMode::Single),
// Address::None,
// 0,
// &[],
// )
// .unwrap();
// };
loop {
// let mut buf = [0u8; 3];
// x.half_duplex_read(
// DataMode::Single,
// Command::_9Bit(0x04, DataMode::Single),
// Address::None,
// 1,
// &mut buf,
// )
// .unwrap();
let mut buf = [0_u8, 0, 0];
spi_read(
0xDA,
false,
&mut mosi,
&mut sck,
&mut cs,
&mut buf[0..][..1],
);
spi_read(
0xDB,
false,
&mut mosi,
&mut sck,
&mut cs,
&mut buf[1..][..1],
);
spi_read(
0xDC,
false,
&mut mosi,
&mut sck,
&mut cs,
&mut buf[2..][..1],
);
let mut buf2 = [0_u8, 0, 0];
spi_read(0x04, true, &mut mosi, &mut sck, &mut cs, &mut buf2);
// info!("Hello world! {buf:02x?} {buf2:02x?}");
for (chunk, color) in dma_buf.as_mut_slice().chunks_mut(2).zip(&mut colors) {
chunk.copy_from_slice(&color.to_le_bytes());
}
colors.next(); // Shift colors
let transfer = dpi.send(false, dma_buf).map_err(|e| e.0).unwrap();
(_, dpi, dma_buf) = transfer.wait();
// x.half_duplex_write(
// DataMode::Single,
// Command::_9Bit(0xFFFF, DataMode::Single),
// Address::None,
// 0,
// &[0x77],
// )
// .unwrap();
// Timer::after(Duration::from_secs(1)).await;
}
// for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.0.0-rc.0/examples/src/bin
}
fn spi_delay() {
Delay::new().delay_micros(1);
}
fn spi_dummy_bit(sck: &mut Output) {
sck.set_low();
spi_delay();
sck.set_high();
spi_delay();
}
fn spi_write_bit(bit: bool, mosi: &mut Flex, sck: &mut Output) {
mosi.set_level(if bit { Level::High } else { Level::Low });
sck.set_low();
spi_delay();
sck.set_high();
spi_delay();
}
fn spi_read_bit(mosi: &mut Flex, sck: &mut Output) -> bool {
sck.set_low();
spi_delay();
sck.set_high();
spi_delay();
mosi.is_high()
}
fn spi_write_bits(bits: impl Iterator<Item = bool>, mosi: &mut Flex, sck: &mut Output) {
for bit in bits {
spi_write_bit(bit, mosi, sck);
}
}
fn spi_write_word(is_param: bool, data: u8, mosi: &mut Flex, sck: &mut Output) {
assert!(sck.is_set_high());
spi_write_bits(
once(is_param).chain((0..8).map(|i| (data >> i) & 1 != 0).rev()),
mosi,
sck,
);
}
fn spi_write(command: u8, args: &[u8], mosi: &mut Flex, sck: &mut Output, cs: &mut Output) {
cs.set_low();
spi_write_word(false, command, mosi, sck);
for &arg in args {
spi_write_word(true, arg, mosi, sck);
}
cs.set_high();
}
fn spi_read(
command: u8,
dummy_cycle: bool,
mosi: &mut Flex,
sck: &mut Output,
cs: &mut Output,
output_buffer: &mut [u8],
) {
output_buffer.fill(0);
cs.set_low();
spi_write_word(false, command, mosi, sck);
mosi.set_output_enable(false);
mosi.set_input_enable(true);
if dummy_cycle {
spi_dummy_bit(sck);
}
for output_byte in output_buffer {
for i in (0..8).rev() {
if spi_read_bit(mosi, sck) {
*output_byte |= 1 << i;
}
}
}
mosi.set_input_enable(false);
mosi.set_output_enable(true);
cs.set_high();
}
#[derive(Clone, Copy)]
enum InitOp {
Command(u8, &'static [u8]),
WriteComm(u8),
WriteData(u8),
SleepMs(u64),
}
// impl InitOp {
// async fn execute<'a>(&'a self, mosi: &'a mut Output<'a>, sck: &'a mut Output<'a>) {
// match *self {
// InitOp::WriteComm(data) => spi_write(false, data, mosi, sck),
// InitOp::WriteData(data) => spi_write(true, data, mosi, sck),
// InitOp::SleepMs(ms) => Timer::after_millis(ms).await,
// }
// }
// }
use InitOp::*;
const INIT_SEQUENCE: &[InitOp] = &[
WriteComm(0xff),
WriteData(0x77),
WriteData(0x01),
WriteData(0x00),
WriteData(0x00),
WriteData(0x13),
WriteComm(0xef),
WriteData(0x08),
WriteComm(0xff),
WriteData(0x77),
WriteData(0x01),
WriteData(0x00),
WriteData(0x00),
WriteData(0x10),
WriteComm(0xc0),
WriteData(0x77),
WriteData(0x00),
WriteComm(0xc1),
WriteData(0x11),
WriteData(0x0c),
WriteComm(0xc2),
WriteData(0x07),
WriteData(0x02),
WriteComm(0xcc),
WriteData(0x30),
WriteComm(0xB0),
WriteData(0x06),
WriteData(0xCF),
WriteData(0x14),
WriteData(0x0C),
WriteData(0x0F),
WriteData(0x03),
WriteData(0x00),
WriteData(0x0A),
WriteData(0x07),
WriteData(0x1B),
WriteData(0x03),
WriteData(0x12),
WriteData(0x10),
WriteData(0x25),
WriteData(0x36),
WriteData(0x1E),
WriteComm(0xB1),
WriteData(0x0C),
WriteData(0xD4),
WriteData(0x18),
WriteData(0x0C),
WriteData(0x0E),
WriteData(0x06),
WriteData(0x03),
WriteData(0x06),
WriteData(0x08),
WriteData(0x23),
WriteData(0x06),
WriteData(0x12),
WriteData(0x10),
WriteData(0x30),
WriteData(0x2F),
WriteData(0x1F),
WriteComm(0xff),
WriteData(0x77),
WriteData(0x01),
WriteData(0x00),
WriteData(0x00),
WriteData(0x11),
WriteComm(0xb0),
WriteData(0x73),
WriteComm(0xb1),
WriteData(0x7C),
WriteComm(0xb2),
WriteData(0x83),
WriteComm(0xb3),
WriteData(0x80),
WriteComm(0xb5),
WriteData(0x49),
WriteComm(0xb7),
WriteData(0x87),
WriteComm(0xb8),
WriteData(0x33),
WriteComm(0xb9),
WriteData(0x10),
WriteData(0x1f),
WriteComm(0xbb),
WriteData(0x03),
WriteComm(0xc1),
WriteData(0x08),
WriteComm(0xc2),
WriteData(0x08),
WriteComm(0xd0),
WriteData(0x88),
WriteComm(0xe0),
WriteData(0x00),
WriteData(0x00),
WriteData(0x02),
WriteData(0x00),
WriteData(0x00),
WriteData(0x0c),
WriteComm(0xe1),
WriteData(0x05),
WriteData(0x96),
WriteData(0x07),
WriteData(0x96),
WriteData(0x06),
WriteData(0x96),
WriteData(0x08),
WriteData(0x96),
WriteData(0x00),
WriteData(0x44),
WriteData(0x44),
WriteComm(0xe2),
WriteData(0x00),
WriteData(0x00),
WriteData(0x03),
WriteData(0x03),
WriteData(0x00),
WriteData(0x00),
WriteData(0x02),
WriteData(0x00),
WriteData(0x00),
WriteData(0x00),
WriteData(0x02),
WriteData(0x00),
WriteComm(0xe3),
WriteData(0x00),
WriteData(0x00),
WriteData(0x33),
WriteData(0x33),
WriteComm(0xe4),
WriteData(0x44),
WriteData(0x44),
WriteComm(0xe5),
WriteData(0x0d),
WriteData(0xd4),
WriteData(0x28),
WriteData(0x8c),
WriteData(0x0f),
WriteData(0xd6),
WriteData(0x28),
WriteData(0x8c),
WriteData(0x09),
WriteData(0xd0),
WriteData(0x28),
WriteData(0x8c),
WriteData(0x0b),
WriteData(0xd2),
WriteData(0x28),
WriteData(0x8c),
WriteComm(0xe6),
WriteData(0x00),
WriteData(0x00),
WriteData(0x33),
WriteData(0x33),
WriteComm(0xe7),
WriteData(0x44),
WriteData(0x44),
WriteComm(0xe8),
WriteData(0x0e),
WriteData(0xd5),
WriteData(0x28),
WriteData(0x8c),
WriteData(0x10),
WriteData(0xd7),
WriteData(0x28),
WriteData(0x8c),
WriteData(0x0a),
WriteData(0xd1),
WriteData(0x28),
WriteData(0x8c),
WriteData(0x0c),
WriteData(0xd3),
WriteData(0x28),
WriteData(0x8c),
WriteComm(0xeb),
WriteData(0x00),
WriteData(0x01),
WriteData(0xe4),
WriteData(0xe4),
WriteData(0x44),
WriteData(0x00),
WriteComm(0xed),
WriteData(0xf3),
WriteData(0xc1),
WriteData(0xba),
WriteData(0x0f),
WriteData(0x66),
WriteData(0x77),
WriteData(0x44),
WriteData(0x55),
WriteData(0x55),
WriteData(0x44),
WriteData(0x77),
WriteData(0x66),
WriteData(0xf0),
WriteData(0xab),
WriteData(0x1c),
WriteData(0x3f),
WriteComm(0xef),
WriteData(0x10),
WriteData(0x0d),
WriteData(0x04),
WriteData(0x08),
WriteData(0x3f),
WriteData(0x1f),
WriteComm(0xff),
WriteData(0x77),
WriteData(0x01),
WriteData(0x00),
WriteData(0x00),
WriteData(0x13),
WriteComm(0xe8),
WriteData(0x00),
WriteData(0x0e),
WriteComm(0x11),
SleepMs(120),
WriteComm(0xe8),
WriteData(0x00),
WriteData(0x0c),
SleepMs(10),
WriteComm(0xe8),
WriteData(0x40),
WriteData(0x00),
WriteComm(0xff),
WriteData(0x77),
WriteData(0x01),
WriteData(0x00),
WriteData(0x00),
WriteData(0x00),
WriteComm(0x36),
WriteData(0x00),
WriteComm(0x3A),
WriteData(0x66),
WriteComm(0x29),
SleepMs(20),
/*
WriteComm (0xff);
WriteData (0x77);
WriteData (0x01);
WriteData (0x00);
WriteData (0x00);
WriteData (0x10);
WriteComm (0xe5);
WriteData (0x00);
WriteData (0x00);
*/
];
/*
TODO: Use this init sequence
WriteComm (0xff);
WriteData (0x77);
WriteData (0x01);
WriteData (0x00);
WriteData (0x00);
WriteData (0x13);
WriteComm (0xef);
WriteData (0x08);
WriteComm (0xff);
WriteData (0x77);
WriteData (0x01);
WriteData (0x00);
WriteData (0x00);
WriteData (0x10);
WriteComm (0xc0);
WriteData (0x77);
WriteData (0x00);
WriteComm (0xc1);
WriteData (0x11);
WriteData (0x0c);
WriteComm (0xc2);
WriteData (0x07);
WriteData (0x02);
WriteComm (0xcc);
WriteData (0x30);
WriteComm (0xB0);
WriteData (0x06);
WriteData (0xCF);
WriteData (0x14);
WriteData (0x0C);
WriteData (0x0F);
WriteData (0x03);
WriteData (0x00);
WriteData (0x0A);
WriteData (0x07);
WriteData (0x1B);
WriteData (0x03);
WriteData (0x12);
WriteData (0x10);
WriteData (0x25);
WriteData (0x36);
WriteData (0x1E);
WriteComm (0xB1);
WriteData (0x0C);
WriteData (0xD4);
WriteData (0x18);
WriteData (0x0C);
WriteData (0x0E);
WriteData (0x06);
WriteData (0x03);
WriteData (0x06);
WriteData (0x08);
WriteData (0x23);
WriteData (0x06);
WriteData (0x12);
WriteData (0x10);
WriteData (0x30);
WriteData (0x2F);
WriteData (0x1F);
WriteComm (0xff);
WriteData (0x77);
WriteData (0x01);
WriteData (0x00);
WriteData (0x00);
WriteData (0x11);
WriteComm (0xb0);
WriteData (0x73);
WriteComm (0xb1);
WriteData (0x7C);
WriteComm (0xb2);
WriteData (0x83);
WriteComm (0xb3);
WriteData (0x80);
WriteComm (0xb5);
WriteData (0x49);
WriteComm (0xb7);
WriteData (0x87);
WriteComm (0xb8);
WriteData (0x33);
WriteComm (0xb9);
WriteData (0x10);
WriteData (0x1f);
WriteComm (0xbb);
WriteData (0x03);
WriteComm (0xc1);
WriteData (0x08);
WriteComm (0xc2);
WriteData (0x08);
WriteComm (0xd0);
WriteData (0x88);
WriteComm (0xe0);
WriteData (0x00);
WriteData (0x00);
WriteData (0x02);
WriteData (0x00);
WriteData (0x00);
WriteData (0x0c);
WriteComm (0xe1);
WriteData (0x05);
WriteData (0x96);
WriteData (0x07);
WriteData (0x96);
WriteData (0x06);
WriteData (0x96);
WriteData (0x08);
WriteData (0x96);
WriteData (0x00);
WriteData (0x44);
WriteData (0x44);
WriteComm (0xe2);
WriteData (0x00);
WriteData (0x00);
WriteData (0x03);
WriteData (0x03);
WriteData (0x00);
WriteData (0x00);
WriteData (0x02);
WriteData (0x00);
WriteData (0x00);
WriteData (0x00);
WriteData (0x02);
WriteData (0x00);
WriteComm (0xe3);
WriteData (0x00);
WriteData (0x00);
WriteData (0x33);
WriteData (0x33);
WriteComm (0xe4);
WriteData (0x44);
WriteData (0x44);
WriteComm (0xe5);
WriteData (0x0d);
WriteData (0xd4);
WriteData (0x28);
WriteData (0x8c);
WriteData (0x0f);
WriteData (0xd6);
WriteData (0x28);
WriteData (0x8c);
WriteData (0x09);
WriteData (0xd0);
WriteData (0x28);
WriteData (0x8c);
WriteData (0x0b);
WriteData (0xd2);
WriteData (0x28);
WriteData (0x8c);
WriteComm (0xe6);
WriteData (0x00);
WriteData (0x00);
WriteData (0x33);
WriteData (0x33);
WriteComm (0xe7);
WriteData (0x44);
WriteData (0x44);
WriteComm (0xe8);
WriteData (0x0e);
WriteData (0xd5);
WriteData (0x28);
WriteData (0x8c);
WriteData (0x10);
WriteData (0xd7);
WriteData (0x28);
WriteData (0x8c);
WriteData (0x0a);
WriteData (0xd1);
WriteData (0x28);
WriteData (0x8c);
WriteData (0x0c);
WriteData (0xd3);
WriteData (0x28);
WriteData (0x8c);
WriteComm (0xeb);
WriteData (0x00);
WriteData (0x01);
WriteData (0xe4);
WriteData (0xe4);
WriteData (0x44);
WriteData (0x00);
WriteComm (0xed);
WriteData (0xf3);
WriteData (0xc1);
WriteData (0xba);
WriteData (0x0f);
WriteData (0x66);
WriteData (0x77);
WriteData (0x44);
WriteData (0x55);
WriteData (0x55);
WriteData (0x44);
WriteData (0x77);
WriteData (0x66);
WriteData (0xf0);
WriteData (0xab);
WriteData (0x1c);
WriteData (0x3f);
WriteComm (0xef);
WriteData (0x10);
WriteData (0x0d);
WriteData (0x04);
WriteData (0x08);
WriteData (0x3f);
WriteData (0x1f);
WriteComm (0xff);
WriteData (0x77);
WriteData (0x01);
WriteData (0x00);
WriteData (0x00);
WriteData (0x13);
WriteComm (0xe8);
WriteData (0x00);
WriteData (0x0e);
WriteComm (0x11);
Delay_ms(120);
WriteComm (0xe8);
WriteData (0x00);
WriteData (0x0c);
Delay_ms(10);
WriteComm (0xe8);
WriteData (0x40);
WriteData (0x00);
WriteComm (0xff);
WriteData (0x77);
WriteData (0x01);
WriteData (0x00);
WriteData (0x00);
WriteData (0x00);
WriteComm (0x36);
WriteData (0x00);
WriteComm (0x3A);
WriteData (0x66);
WriteComm (0x29);
Delay_ms(20);
/*
WriteComm (0xff);
WriteData (0x77);
WriteData (0x01);
WriteData (0x00);
WriteData (0x00);
WriteData (0x10);
WriteComm (0xe5);
WriteData (0x00);
WriteData (0x00);
*/
*/

4
firmware/src/lib.rs Normal file
View file

@ -0,0 +1,4 @@
#![no_std]
#![deny(clippy::mem_forget)]
pub mod st7701s;

9
firmware/src/st7701s.rs Normal file
View file

@ -0,0 +1,9 @@
use esp_hal::gpio::OutputPin;
pub struct St7701s {}
impl St7701s {
pub fn new() -> Self {
todo!()
}
}