| @ -0,0 +1,15 @@ | |||
| [target.xtensa-esp32-none-elf] | |||
| runner = "espflash flash --monitor --chip esp32 --log-format defmt" | |||
| [env] | |||
| DEFMT_LOG="info" | |||
| [build] | |||
| rustflags = [ | |||
| "-C", "link-arg=-nostartfiles", | |||
| ] | |||
| target = "xtensa-esp32-none-elf" | |||
| [unstable] | |||
| build-std = ["core"] | |||
| @ -0,0 +1,18 @@ | |||
| # Generated by Cargo | |||
| # will have compiled files and executables | |||
| debug/ | |||
| target/ | |||
| .vscode/ | |||
| # 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/ | |||
| @ -0,0 +1,45 @@ | |||
| [package] | |||
| edition = "2021" | |||
| name = "e-ink-hello" | |||
| version = "0.1.0" | |||
| [[bin]] | |||
| name = "e-ink-hello" | |||
| path = "./src/bin/main.rs" | |||
| [dependencies] | |||
| critical-section = "1.2.0" | |||
| defmt = "0.3.10" | |||
| embassy-executor = { version = "0.7.0", features = [ | |||
| "defmt", | |||
| "task-arena-size-20480", | |||
| ] } | |||
| embassy-time = "0.4.0" | |||
| esp-hal = { version = "1.0.0-beta.0", features = [ | |||
| "defmt", | |||
| "esp32", | |||
| "unstable", | |||
| ] } | |||
| esp-hal-embassy = { version = "0.7.0", features = ["esp32"] } | |||
| esp-println = { version = "0.13.0", features = ["defmt-espflash", "esp32"] } | |||
| static_cell = { version = "2.1.0", features = ["nightly"] } | |||
| epd-waveshare = { features = [ | |||
| "graphics", | |||
| ], git = "https://github.com/ImplFerris/epd-waveshare", branch = "1in54_v2_fix" } | |||
| embedded-hal-bus = { version = "0.1" } | |||
| embedded-graphics = "0.8.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 | |||
| @ -0,0 +1,53 @@ | |||
| fn main() { | |||
| linker_be_nice(); | |||
| println!("cargo:rustc-link-arg=-Tdefmt.x"); | |||
| // 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() | |||
| ); | |||
| } | |||
| @ -0,0 +1,33 @@ | |||
| { | |||
| "version": 1, | |||
| "editor": "wokwi", | |||
| "parts": [ | |||
| { | |||
| "type": "board-esp32-devkit-c-v4", | |||
| "id": "esp", | |||
| "top": 0.59, | |||
| "left": 0.67, | |||
| "attrs": { | |||
| "flashSize": "16" | |||
| } | |||
| } | |||
| ], | |||
| "connections": [ | |||
| [ | |||
| "esp:TX", | |||
| "$serialMonitor:RX", | |||
| "", | |||
| [] | |||
| ], | |||
| [ | |||
| "esp:RX", | |||
| "$serialMonitor:TX", | |||
| "", | |||
| [] | |||
| ] | |||
| ], | |||
| "serialMonitor": { | |||
| "display": "terminal", | |||
| "convertEol": true | |||
| } | |||
| } | |||
| @ -0,0 +1,2 @@ | |||
| [toolchain] | |||
| channel = "book-1.0.0-beta" | |||
| @ -0,0 +1,101 @@ | |||
| #![no_std] | |||
| #![no_main] | |||
| use defmt::info; | |||
| use embassy_executor::Spawner; | |||
| use embassy_time::{Delay, Duration, Timer}; | |||
| use embedded_graphics::mono_font::ascii::FONT_10X20; | |||
| use embedded_graphics::prelude::*; | |||
| use epd_waveshare::prelude::WaveshareDisplay; | |||
| use esp_hal::clock::CpuClock; | |||
| use esp_hal::timer::timg::TimerGroup; | |||
| use esp_println as _; | |||
| use embedded_graphics::mono_font::MonoTextStyleBuilder; | |||
| use embedded_graphics::text::{Baseline, Text}; | |||
| use embedded_hal_bus::spi::ExclusiveDevice; | |||
| use epd_waveshare::color::Color; | |||
| use epd_waveshare::epd1in54_v2::{Display1in54, Epd1in54}; | |||
| use esp_hal::gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull}; | |||
| use esp_hal::spi::master::{Config as SpiConfig, Spi}; | |||
| use esp_hal::spi::Mode as SpiMode; | |||
| use esp_hal::time::Rate; | |||
| #[panic_handler] | |||
| fn panic(info: &core::panic::PanicInfo) -> ! { | |||
| esp_println::println!("Panic occurred: {:?}", info); | |||
| loop {} | |||
| } | |||
| #[esp_hal_embassy::main] | |||
| async fn main(_spawner: Spawner) { | |||
| // generator version: 0.3.1 | |||
| let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); | |||
| let peripherals = esp_hal::init(config); | |||
| let timer0 = TimerGroup::new(peripherals.TIMG1); | |||
| esp_hal_embassy::init(timer0.timer0); | |||
| info!("Embassy initialized!"); | |||
| let spi = Spi::new( | |||
| peripherals.SPI2, | |||
| SpiConfig::default() | |||
| .with_frequency(Rate::from_mhz(4)) | |||
| .with_mode(SpiMode::_0), | |||
| ) | |||
| .unwrap() | |||
| //CLK | |||
| .with_sck(peripherals.GPIO18) | |||
| //DIN | |||
| .with_mosi(peripherals.GPIO23); | |||
| let busy_in = Input::new( | |||
| peripherals.GPIO22, | |||
| InputConfig::default().with_pull(Pull::None), | |||
| ); | |||
| let cs = Output::new(peripherals.GPIO33, Level::Low, OutputConfig::default()); | |||
| let mut spi_dev = ExclusiveDevice::new(spi, cs, Delay); | |||
| let dc = Output::new(peripherals.GPIO17, Level::Low, OutputConfig::default()); | |||
| let reset = Output::new(peripherals.GPIO16, Level::Low, OutputConfig::default()); | |||
| let mut display = Display1in54::default(); | |||
| let mut epd = Epd1in54::new(&mut spi_dev, busy_in, dc, reset, &mut Delay, None).unwrap(); | |||
| epd.clear_frame(&mut spi_dev, &mut Delay).unwrap(); | |||
| epd.display_frame(&mut spi_dev, &mut Delay).unwrap(); | |||
| Timer::after(Duration::from_secs(2)).await; | |||
| display.clear(Color::White).unwrap(); | |||
| epd.update_and_display_frame(&mut spi_dev, display.buffer(), &mut Delay) | |||
| .unwrap(); | |||
| Timer::after(Duration::from_secs(2)).await; | |||
| draw_text(&mut display, "impl Rust for ESP32", 3, 100); | |||
| epd.update_and_display_frame(&mut spi_dev, display.buffer(), &mut Delay) | |||
| .unwrap(); | |||
| Timer::after(Duration::from_secs(5)).await; | |||
| epd.sleep(&mut spi_dev, &mut Delay).unwrap(); | |||
| loop { | |||
| info!("Hello world!"); | |||
| Timer::after(Duration::from_secs(60)).await; | |||
| } | |||
| } | |||
| fn draw_text(display: &mut Display1in54, text: &str, x: i32, y: i32) { | |||
| let text_style = MonoTextStyleBuilder::new() | |||
| .font(&FONT_10X20) | |||
| .text_color(Color::Black) | |||
| .build(); | |||
| Text::with_baseline(text, Point::new(x, y), text_style, Baseline::Top) | |||
| .draw(display) | |||
| .unwrap(); | |||
| } | |||
| @ -0,0 +1 @@ | |||
| #![no_std] | |||
| @ -0,0 +1,31 @@ | |||
| //! Demo test suite using embedded-test | |||
| //! | |||
| //! You can run this using `cargo test` as usual. | |||
| #![no_std] | |||
| #![no_main] | |||
| #[cfg(test)] | |||
| #[embedded_test::tests(executor = esp_hal_embassy::Executor::new())] | |||
| mod tests { | |||
| use defmt::assert_eq; | |||
| use esp_hal::timer::timg::TimerGroup; | |||
| #[init] | |||
| fn init() { | |||
| let peripherals = esp_hal::init(esp_hal::Config::default()); | |||
| let timer0 = TimerGroup::new(peripherals.TIMG1); | |||
| esp_hal_embassy::init(timer0.timer0); | |||
| rtt_target::rtt_init_defmt!(); | |||
| } | |||
| #[test] | |||
| async fn hello_test() { | |||
| defmt::info!("Running test!"); | |||
| embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await; | |||
| assert_eq!(1 + 1, 2); | |||
| } | |||
| } | |||
| @ -0,0 +1,5 @@ | |||
| [wokwi] | |||
| version = 1 | |||
| gdbServerPort = 3333 | |||
| elf = "target/xtensa-esp32-none-elf/debug/e-ink-hello" | |||
| firmware = "target/xtensa-esp32-none-elf/debug/e-ink-hello" | |||