use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use anyhow::{Result, anyhow, bail};
use esp_idf_hal::{
i2c::{
I2cDriver, I2c,
I2cConfig,
},
gpio::{
Pin, InputPin, OutputPin,
},
delay::BLOCK,
peripheral::Peripheral,
};
use esp_idf_hal::delay::FreeRtos;
use std::thread::sleep;
use std::time::Duration;
use std::sync::{Arc, Mutex};
// struct Ssd1306<'d> {
// driver: Arc<Mutex<I2cDriver<'d>>>,
// address: u8,
// }
// impl<'d> Ssd1306<'d> {
// pub fn new(driver: Arc<Mutex<I2cDriver<'d>>>, address: u8) -> Result<Self>
// {
// Ok(Self{ driver, address })
// }
// }
pub struct LcdPcf8574<'d> {
driver: Arc<Mutex<I2cDriver<'d>>>,
address: u8,
control: [(u8, u8); 2],
}
impl<'d> LcdPcf8574<'d> {
fn write(&self, cmd: u8, value: &[u8], full: u8) -> Result<()> {
// cmd:: 0: cmd, 1: data
let (xn, en) = self.control[(cmd % 2) as usize];
let send: Vec<u8> = match full {
0b11 => value
.iter()
.flat_map(|v| {
let (h, l) = (v & 0xF0, (v << 4) & 0xF0);
[h | en, h | xn, l | en, l | xn]
})
.collect(),
0b10 => value
.iter()
.flat_map(|v| {
let (h, l) = (v & 0xF0, (v << 4) & 0xF0);
[h | en, h | xn]
})
.collect(),
0b01 => value
.iter()
.flat_map(|v| {
let (h, l) = (v & 0xF0, (v << 4) & 0xF0);
[l | en, l | xn]
})
.collect(),
_ => bail!("Wrong write mode!"),
};
loop {
if let Ok(ref mut driver) = self.driver.try_lock() {
driver.write(self.address, &send, BLOCK)?;
break;
}
sleep(Duration::from_micros(10));
}
sleep(Duration::from_micros(100));
Ok(())
}
pub fn init(&self) -> Result<()> {
// 4 bit mode initialization
sleep(Duration::from_millis(50));
self.write(0b0, &[0x33], 0b10)?;
sleep(Duration::from_millis(6));
self.write(0b0, &[0x33], 0b10)?;
sleep(Duration::from_millis(2));
self.write(0b0, &[0x33], 0b10)?;
sleep(Duration::from_millis(10));
self.write(0b0, &[0x20], 0b10)?; // 4-bit mode
sleep(Duration::from_millis(10));
// display initialzation
self.write(0b0, &[0x28], 0b11)?;
sleep(Duration::from_millis(1));
self.write(0b0, &[0x0F], 0b11)?;
sleep(Duration::from_millis(1));
self.write(0b0, &[0x06], 0b11)?;
sleep(Duration::from_millis(1));
self.write(0b0, &[0x0F], 0b11)?;
sleep(Duration::from_millis(1));
self.clear()?;
//
Ok(())
}
pub fn set_cur(&self, row: u8, col: u8) -> Result<()> {
let cmd = match row {
0 => Ok(col | 0x80),
1 => Ok(col | 0xC0),
2 => Ok(col | 0x94),
3 => Ok(col | 0xD4),
_ => Err(anyhow!("Out of limit, row: {}", row)),
}?;
self.write(0b0, &[cmd], 0b11)?;
sleep(Duration::from_millis(1));
//
Ok(())
}
pub fn set_light(&mut self, light: bool) {
self.control = if light {
[(0x08, 0x0C), (0x09, 0x0D)]
} else {
[(0x00, 0x04), (0x01, 0x05)]
}
}
pub fn clear(&self,) -> Result<()> {
self.write(0b0, &[0x01], 0b11);
sleep(Duration::from_millis(1));
Ok(())
}
pub fn send_str(&self, s: &str) -> Result<()> {
self.write(0b1, s.as_bytes(), 0b11)?;
sleep(Duration::from_millis(1));
Ok(())
}
pub fn send_bytes(&self, s: &[u8]) -> Result<()> {
self.write(0b1, s, 0b11)?;
sleep(Duration::from_millis(1));
Ok(())
}
}
impl<'d> From<(&Arc<Mutex<I2cDriver<'d>>>, u8)> for LcdPcf8574<'d> {
fn from(value: (&Arc<Mutex<I2cDriver<'d>>>, u8)) -> Self {
let driver = value.0.clone();
let address = value.1;
let control = [(0x08, 0x0C), (0x09, 0x0D)];
LcdPcf8574 { driver, address, control }
}
}
pub struct Ssd1306<'d> {
driver: Arc<Mutex<I2cDriver<'d>>>,
address: u8,
}
impl<'d> Ssd1306<'d> {
fn write(&self, cmd: bool, data: &[u8]) -> Result<()> {
let mut send: Vec<u8> = Vec::with_capacity(data.len() + 1);
send.push(if cmd { 0x00 } else { 0x40 });
send.extend_from_slice(data);
loop {
if let Ok(ref mut driver) = self.driver.try_lock() {
let rt = driver.write(self.address, &send, BLOCK);
break;
}
sleep(Duration::from_micros(10));
}
sleep(Duration::from_micros(1));
Ok(())
}
pub fn init(&self) -> Result<()> {
self.write(
true,
&[
0xae, // display off
0xd4, //
0x80, //
0xa8, //
0x3f, //
0xd3, //
0x00, //
0x40, //
0x8d, //
0x14, //
0xa1, //
0xc8, //
0xda, //
0x12, //
0x81, //
0xcf, //
0xf1, //
0xdb, //
0x40, //
0xa4, //
0xa6, //
0xaf, // display on
0x20, 0x02, // display mode
],
)?;
Ok(())
}
pub fn draw(&self, data: &[u8], cur: Option<(u8, u8)>) -> Result<()> {
if let Some((page, column)) = cur {
self.write(
true,
&[0xB0 + page % 8, (column >> 4) & 0x0F | 0x10, column & 0x0F],
)?;
}
self.write(false, &data)?;
Ok(())
}
}
impl<'d> From<(&Arc<Mutex<I2cDriver<'d>>>, u8)> for Ssd1306<'d> {
fn from(value: (&Arc<Mutex<I2cDriver<'d>>>, u8)) -> Self {
let driver = value.0.clone();
let address = value.1;
Ssd1306 { driver, address }
}
}
fn main() -> Result<()> {
use esp_idf_hal::prelude::FromValueType;
esp_idf_sys::link_patches();
println!("Hello, world!");
let peripherals = esp_idf_hal::peripherals::Peripherals::take().unwrap();
let i2c = peripherals.i2c0;
let sda = peripherals.pins.gpio0;
let scl = peripherals.pins.gpio1;
let config = I2cConfig::new().baudrate(100_u32.kHz().into()).sda_enable_pullup(false);
let iic = Arc::new(Mutex::new(I2cDriver::new(i2c, sda, scl, &config)?));
let lcd1602 = LcdPcf8574::from((&iic, 0x27_u8));
let lcd2004 = LcdPcf8574::from((&iic, 0x29_u8));
lcd1602.init()?;
lcd1602.set_cur(0, 0)?;
lcd1602.send_str("ABCDEFGHIJKLMOPQ")?;
lcd1602.set_cur(1, 0)?;
lcd1602.send_str("ABCDEFGHIJKLMOPQ")?;
lcd2004.init()?;
lcd2004.set_cur(0, 0)?;
lcd2004.send_str("ABCDEFGHIJKLMOPQRSTU")?;
lcd2004.set_cur(1, 0)?;
lcd2004.send_str("ABCDEFGHIJKLMOPQ")?;
lcd2004.send_bytes(&[0xC2, 255]);
lcd2004.set_cur(2, 0)?;
lcd2004.send_str("ABCDEFGHIJKLMOPQ")?;
lcd2004.set_cur(3, 0)?;
lcd2004.send_str("ABCDEFGHIJKLMOPQ")?;
let mut ssd1306 = Ssd1306::from((&iic, 0x3c));
// println!("asd");
ssd1306.init()?;
// println!("asd");
let i = 0;
// println!("asd");
// https://www.23bei.com/tool/218.html
let data: [u8; 16*4] = [
0x00,0x04,0x04,0x04,0xff,0x54,0x54,0x54,0x54,0x54,0xff,0x04,0x06,0x84,0x00,0x00,
0x00,0x00,0xfe,0x22,0x22,0xe2,0x22,0x22,0x22,0x22,0x22,0xa2,0x3f,0x02,0x00,0x00,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xff,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x00,
0x80,0x88,0xa8,0xa8,0xa9,0xaa,0xae,0xf8,0xac,0xaa,0xab,0xa8,0xac,0x88,0x80,0x00,
];
ssd1306.draw(&data, Some((0, 0)))?;
// println!("asd");
let data: [u8; 16*4] = [
0x11,0x11,0x89,0x89,0x95,0x93,0x91,0xfd,0x91,0x9b,0x95,0xc5,0x89,0x19,0x09,0x00,
0x80,0x60,0x1f,0x00,0x00,0x3f,0x44,0x44,0x42,0x42,0x41,0x41,0x40,0x40,0x70,0x00,
0x40,0x40,0x20,0x20,0x10,0x0c,0x0b,0x30,0x03,0x0c,0x10,0x10,0x20,0x60,0x20,0x00,
0x80,0x84,0x84,0x44,0x44,0x24,0x14,0x0f,0x14,0x24,0x24,0x44,0x46,0xc4,0x40,0x00
];
ssd1306.draw(&data, Some((1, 0)))?;
// println!("asd");
// let wifi_logo: [[u8; 32]; 4] = [
// [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xf0,
// 0xf0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,],
// [0x00,0x00,0x00,0x0c,0x1e,0x0f,0x47,0xe7,0xe3,0xf3,0x79,0x79,0x39,0x38,0x1c,0x1c,
// 0x1c,0x1c,0x38,0x39,0x39,0x79,0xf3,0xe3,0xe7,0x47,0x0f,0x1e,0x0c,0x00,0x00,0x00,],
// [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0e,0x0f,0x8f,0xc7,0xe7,
// 0xe7,0xc7,0x8f,0x0f,0x0e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,],
// [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x07,
// 0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,],
// ];
// for i in 0..4 {
// // iic.write(0x3c, &[0, 0xB2 + i, 0x00, 0x15], BLOCK)?;
// ssd1306.draw(&wifi_logo[i as usize], Some((2 + i, 0x50)))?;
// // println!("asd {}", i);
// }
let wifi_logo: [[u8; 16]; 2] = [
[0x00,0xc0,0xf0,0xf8,0x38,0x1c,0x00,0xfe,0xfe,0x00,0x1c,0x38,0xf0,0xe0,0x00,0x00,],
[0x00,0x03,0x0f,0x1f,0x38,0x30,0x70,0x71,0x71,0x70,0x38,0x3c,0x1f,0x0f,0x00,0x00,],
];
for i in 0..2 {
// iic.write(0x3c, &[0, 0xB2 + i, 0x00, 0x15], BLOCK)?;
ssd1306.draw(&wifi_logo[i as usize], Some((2 + i, 0x50)))?;
// println!("asd {}", i);
}
ssd1306.draw(&[0x20,0x1c,0x1c,0x20,0x00,0x00,0x00,0x00], Some((2, 0)))?;
// loop {
// // we are sleeping here to make sure the watchdog isn't triggered
// FreeRtos::delay_ms(500);
// iic.write(0x3C, &[0, 0xa6], BLOCK)?;
// FreeRtos::delay_ms(500);
// iic.write(0x3C, &[0, 0xa7], BLOCK)?;
// }
Ok(())
}
Loading
esp32-c3-devkitm-1
esp32-c3-devkitm-1