diff --git a/.gitignore b/.gitignore index 73fab07..33b71d5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ target/ # MSVC Windows builds of rustc generate these, which store debugging information *.pdb +.env diff --git a/Cargo.lock b/Cargo.lock index 05a5455..64e866c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,12 @@ 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 = "basic-toml" version = "0.1.10" @@ -344,6 +350,16 @@ dependencies = [ "nb 1.1.0", ] +[[package]] +name = "embedded-graphics-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba9ecd261f991856250d2207f6d8376946cd9f412a2165d3b75bc87a0bc7a044" +dependencies = [ + "az", + "byteorder", +] + [[package]] name = "embedded-hal" version = "0.2.7" @@ -369,6 +385,16 @@ dependencies = [ "embedded-hal 1.0.0", ] +[[package]] +name = "embedded-hal-bus" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513e0b3a8fb7d3013a8ae17a834283f170deaf7d0eeab0a7c1a36ad4dd356d22" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", +] + [[package]] name = "embedded-io" version = "0.6.1" @@ -841,6 +867,15 @@ dependencies = [ "syn", ] +[[package]] +name = "it8951" +version = "0.4.2" +dependencies = [ + "embedded-graphics-core", + "embedded-hal 1.0.0", + "log", +] + [[package]] name = "itoa" version = "1.0.15" @@ -864,6 +899,8 @@ dependencies = [ "embassy-executor", "embassy-net", "embassy-time", + "embedded-hal 1.0.0", + "embedded-hal-bus", "embedded-io", "embedded-io-async", "esp-alloc", @@ -874,6 +911,7 @@ dependencies = [ "esp-println", "esp-wifi", "heapless", + "it8951", "log", "smoltcp", "static_cell", diff --git a/Cargo.toml b/Cargo.toml index b38e4c2..e5a4548 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,8 @@ esp-hal = { version = "1.0.0-beta.1", features = ["esp32", "unstable"] } esp-println = { version = "0.14.0", features = ["esp32", "log-04"] } log = { version = "0.4.27" } esp-alloc = { version = "0.8.0" } +embedded-hal = "1" +embedded-hal-bus = "0" embedded-io = "0.6.1" embedded-io-async = { version = "0.6.1" } esp-wifi = { version = "0.14.1", features = ["esp32", "wifi"] } @@ -43,6 +45,7 @@ embassy-net = { version = "0.7", features = [ ] } esp-hal-embassy = { version = "0.8.1", features = ["esp32", "executors"] } esp-bootloader-esp-idf = { version = "0.1" } +it8951 = { version = "0.4.2", path = "../it8951" } [profile.dev] diff --git a/src/main.rs b/src/main.rs index 301e22d..b25476e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,84 +14,87 @@ #![no_std] #![no_main] +mod wifi; + use embassy_executor::Spawner; -use embassy_net::{Runner, StackResources}; +use embassy_time::Delay; use embassy_time::{Duration, Timer}; +use embedded_hal_bus::spi::{ExclusiveDevice, NoDelay}; use esp_alloc as _; use esp_backtrace as _; -use esp_hal::{clock::CpuClock, rng::Rng, timer::timg::TimerGroup}; -use esp_println::println; -use esp_wifi::{ - init, - wifi::{ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState}, - EspWifiController, +use esp_hal::gpio::{Flex, Pin}; +use esp_hal::time::Rate; +use esp_hal::{ + clock::CpuClock, + spi::master::{Config, Spi}, + timer::timg::TimerGroup, }; +use esp_println::println; +use it8951::{interface::IT8951SPIInterface, IT8951}; esp_bootloader_esp_idf::esp_app_desc!(); -// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html -macro_rules! mk_static { - ($t:ty,$val:expr) => {{ - static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); - #[deny(unused_attributes)] - let x = STATIC_CELL.uninit().write(($val)); - x - }}; -} - -const SSID: &str = env!("SSID"); -const PASSWORD: &str = env!("PASSWORD"); - #[esp_hal_embassy::main] 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); - - esp_alloc::heap_allocator!(size: 72 * 1024); - - let timg0 = TimerGroup::new(peripherals.TIMG0); - let mut rng = Rng::new(peripherals.RNG); - - let esp_wifi_ctrl = &*mk_static!( - EspWifiController<'static>, - init(timg0.timer0, rng, peripherals.RADIO_CLK).unwrap() - ); - - let (controller, interfaces) = esp_wifi::wifi::new(esp_wifi_ctrl, peripherals.WIFI).unwrap(); - - let wifi_interface = interfaces.sta; - let timg1 = TimerGroup::new(peripherals.TIMG1); + esp_hal_embassy::init(timg1.timer0); - let config = embassy_net::Config::dhcpv4(Default::default()); + esp_alloc::heap_allocator!(size: 72 * 1024); // why this value? - let seed = (rng.random() as u64) << 32 | rng.random() as u64; + let mut pin_ext_pwr = Flex::new(peripherals.GPIO5); + let pin_busy = Flex::new(peripherals.GPIO27.degrade()); + let mut pin_reset = Flex::new(peripherals.GPIO23.degrade()); + let pin_chip_select = Flex::new(peripherals.GPIO15.degrade()); + let pin_miso = Flex::new(peripherals.GPIO13.degrade()); + let pin_mosi = Flex::new(peripherals.GPIO12.degrade()); + let pin_sck = Flex::new(peripherals.GPIO14.degrade()); - // Init network stack - let (stack, runner) = embassy_net::new( - wifi_interface, - config, - mk_static!(StackResources<3>, StackResources::<3>::new()), - seed, + pin_ext_pwr.set_high(); + pin_reset.set_high(); + + Timer::after(Duration::from_millis(1000)).await; + + let spi: Spi<'_, esp_hal::Blocking> = Spi::new( + peripherals.SPI2, + Config::default().with_frequency(Rate::from_mhz(10)), + ) + .unwrap() + .with_miso(pin_miso) + .with_mosi(pin_mosi) + .with_sck(pin_sck); + + let spi = ExclusiveDevice::new(spi, pin_chip_select, NoDelay).unwrap(); + + let display_interface = IT8951SPIInterface::new(spi, pin_busy, pin_reset, Delay); + // display_interface.set_busy_timeout(core::time::Duration::from_micros(500)); + + let mut epd = match IT8951::new(display_interface, it8951::Config::default()).init(1605) { + Ok(e) => e, + Err(e) => panic!("{:?}", e), + }; + + epd.reset().unwrap(); + + let stack = wifi::init( + peripherals.TIMG0, + peripherals.RNG, + peripherals.RADIO_CLK, + peripherals.WIFI, + spawner, ); - spawner.spawn(connection(controller)).ok(); - spawner.spawn(net_task(runner)).ok(); - - loop { - if stack.is_link_up() { - break; - } - Timer::after(Duration::from_millis(500)).await; - } - println!("Waiting to get IP address..."); loop { - if let Some(config) = stack.config_v4() { - println!("Got IP: {}", config.address); - break; + if stack.is_link_up() { + if let Some(config) = stack.config_v4() { + println!("Got IP: {}", config.address); + break; + } } Timer::after(Duration::from_millis(500)).await; } @@ -146,47 +149,3 @@ async fn main(spawner: Spawner) -> ! { // Timer::after(Duration::from_millis(30000)).await; // } } - -#[embassy_executor::task] -async fn connection(mut controller: WifiController<'static>) { - println!("start connection task"); - println!("Device capabilities: {:?}", controller.capabilities()); - loop { - if esp_wifi::wifi::wifi_state() == WifiState::StaConnected { - // wait until we're no longer connected - controller.wait_for_event(WifiEvent::StaDisconnected).await; - Timer::after(Duration::from_millis(5000)).await - } - if !matches!(controller.is_started(), Ok(true)) { - let client_config = Configuration::Client(ClientConfiguration { - ssid: SSID.into(), - password: PASSWORD.into(), - ..Default::default() - }); - controller.set_configuration(&client_config).unwrap(); - println!("Starting wifi"); - controller.start_async().await.unwrap(); - println!("Wifi started!"); - - println!("Scan"); - let result = controller.scan_n_async(10).await.unwrap(); - for ap in result { - println!("{:?}", ap); - } - } - println!("About to connect..."); - - match controller.connect_async().await { - Ok(_) => println!("Wifi connected!"), - Err(e) => { - println!("Failed to connect to wifi: {e:?}"); - Timer::after(Duration::from_millis(5000)).await - } - } - } -} - -#[embassy_executor::task] -async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { - runner.run().await -} diff --git a/src/wifi.rs b/src/wifi.rs new file mode 100644 index 0000000..039b586 --- /dev/null +++ b/src/wifi.rs @@ -0,0 +1,97 @@ +use embassy_executor::Spawner; +use embassy_net::{Runner, Stack, StackResources}; +use embassy_time::{Duration, Timer}; +use esp_hal::{ + peripherals::{RADIO_CLK, RNG, TIMG0, WIFI}, + rng::Rng, + timer::timg::TimerGroup, +}; +use esp_println::println; +use esp_wifi::{ + wifi::{ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState}, + EspWifiController, +}; + +const SSID: &str = env!("SSID"); +const PASSWORD: &str = env!("PASSWORD"); + +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +macro_rules! mk_static { + ($t:ty,$val:expr) => {{ + static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); + #[deny(unused_attributes)] + let x = STATIC_CELL.uninit().write(($val)); + x + }}; +} + +pub fn init( + timg0: TIMG0<'static>, + rng: RNG<'static>, + radio_clk: RADIO_CLK<'static>, + wifi: WIFI<'static>, + spawner: Spawner, +) -> Stack<'static> { + let mut rng = Rng::new(rng); + let timg0: TimerGroup<'_, _> = TimerGroup::new(timg0); + let esp_wifi_ctrl = &*mk_static!( + EspWifiController<'static>, + esp_wifi::init(timg0.timer0, rng, radio_clk).unwrap() + ); + + let (controller, interfaces) = esp_wifi::wifi::new(esp_wifi_ctrl, wifi).unwrap(); + + let config = embassy_net::Config::dhcpv4(Default::default()); + let seed = (rng.random() as u64) << 32 | rng.random() as u64; + + let (stack, runner) = embassy_net::new( + interfaces.sta, + config, + mk_static!(StackResources<3>, StackResources::<3>::new()), + seed, + ); + + let client_config = ClientConfiguration { + ssid: SSID.into(), + password: PASSWORD.into(), + ..Default::default() + }; + + spawner.spawn(net_task(runner)).ok(); + spawner.spawn(connection(controller, client_config)).ok(); + + stack +} + +#[embassy_executor::task] +async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { + runner.run().await +} + +#[embassy_executor::task] +async fn connection(mut controller: WifiController<'static>, client_config: ClientConfiguration) { + println!("WiFi Device capabilities: {:?}", controller.capabilities()); + loop { + if esp_wifi::wifi::wifi_state() == WifiState::StaConnected { + // wait until we're no longer connected + controller.wait_for_event(WifiEvent::StaDisconnected).await; + Timer::after(Duration::from_millis(5000)).await + } + if !matches!(controller.is_started(), Ok(true)) { + let client_config = Configuration::Client(client_config.clone()); + controller.set_configuration(&client_config).unwrap(); + println!("Starting WiFi"); + controller.start_async().await.unwrap(); + println!("WiFi started!"); + } + println!("Connecting to {SSID}"); + + match controller.connect_async().await { + Ok(_) => println!("WiFi connected!"), + Err(e) => { + println!("Failed to connect to WiFi: {e:?}"); + Timer::after(Duration::from_millis(5000)).await + } + } + } +}