/*! * Blink the builtin LED - the "Hello World" of embedded programming. */ #![no_std] #![no_main] use core::convert::Infallible; use atmega_hal::{ Spi, Usart, port::{self, Pin, PinOps, mode}, prelude::_embedded_hal_blocking_spi_Write, spi::{self, ChipSelectPin, Settings}, usart::Baudrate, }; use embedded_hal::spi::{Operation, SpiBus}; use embedded_hal::{delay::DelayNs, digital::OutputPin}; use panic_halt as _; type CoreClock = atmega_hal::clock::MHz8; struct Device { spi: Spi, delay: T, } impl embedded_hal::spi::ErrorType for Device { type Error = Infallible; } impl embedded_hal::spi::SpiDevice for Device { fn transaction( &mut self, operations: &mut [embedded_hal::spi::Operation<'_, u8>], ) -> Result<(), Self::Error> { for op in operations { match op { Operation::Read(items) => { self.spi.read(*items)?; } Operation::Write(items) => { SpiBus::write(&mut self.spi, *items)?; } Operation::Transfer(read, write) => { self.spi.transfer(read, write)?; } Operation::TransferInPlace(items) => { self.spi.transfer_in_place(items)?; } Operation::DelayNs(time) => { self.delay.delay_ns(*time); } } } Ok(()) } } #[derive(Default, Clone, Copy)] struct Position { x: u16, y: u16, } impl Position { fn as_bytes(&self) -> [u8; 4] { let [x1, x2] = self.x.to_be_bytes(); let [y1, y2] = self.y.to_be_bytes(); [x1, x2, y1, y2] } } #[derive(Default, Clone, Copy)] struct Color { color: u16, } impl Color { fn as_bytes(&self) -> [u8; 2] { self.color.to_be_bytes() } } struct Display { spi: Spi, cs: ChipSelectPin, dc: Pin, rst: Pin, delay: T, } enum Command { NOP = 0x0, SoftReset = 0x1, RddID = 0x4, RddST = 0x9, SleepIn = 0x10, SleepOut = 0x11, PTLON = 0x12, NoRon = 0x13, InversionOff = 0x20, InversionOn = 0x21, DisplayOff = 0x28, DisplayOn = 0x29, ColumnAlignmentSet = 0x2A, RowAlignmentSet = 0x2B, RamWR = 0x2C, RamRD = 0x2E, PTLAR = 0x30, VSCRDEF = 0x33, ColorMode = 0x3A, MADCTL = 0x36, VSCSAD = 0x37, // MadCTLMY = 0x80, // MadCTLMX = 0x40, // MadCTLMV = 0x20, // MadCTLML = 0x10, // MadCTLBGR = 0x08, // MadCTLMH = 0x04, // MadCTLRGB = 0x00, // RDID1 = 0xDA, // RDID2 = 0xDB, // RDID3 = 0xDC, // RDID4 = 0xDD, // ColorMode65K = 0x50, // ColorMode262K = 0x60, // ColorMode12BIT = 0x03, // ColorMode16BIT = 0x05, // ColorMode18BIT = 0x06, // ColorMode16M = 0x07, } enum ColorMode { ColorMode65K = 0x50, ColorMode262K = 0x60, ColorMode12BIT = 0x03, ColorMode16BIT = 0x05, ColorMode18BIT = 0x06, ColorMode16M = 0x07, } enum Writeable<'d> { Command(Command), Data(&'d [u8]), } enum Rotation { Portrait = 0x00, Landscape = 0x60, InvertedPortrait = 0xc0, InvertedLandscape = 0xa0, } impl Display { fn write(&mut self, writeable: Writeable) { self.cs.set_low().unwrap(); match writeable { Writeable::Command(cmd) => { self.dc.set_low(); SpiBus::write(&mut self.spi, &[cmd as u8]).unwrap() } Writeable::Data(data) => { self.dc.set_high(); SpiBus::write(&mut self.spi, data).unwrap(); self.cs.set_high().unwrap(); } } } fn hard_reset(&mut self) { self.cs.set_low().unwrap(); self.rst.set_high(); self.delay.delay_ms(50); self.rst.set_low(); self.delay.delay_ms(50); self.rst.set_high(); self.delay.delay_ms(150); self.cs.set_high().unwrap(); } fn soft_reset(&mut self) { self.write(Writeable::Command(Command::SoftReset)); self.delay.delay_ms(150); } fn set_sleep(&mut self, sleep: bool) { match sleep { true => self.write(Writeable::Command(Command::SleepIn)), false => self.write(Writeable::Command(Command::SleepOut)), } } fn set_inversion(&mut self, inversion: bool) { match inversion { true => self.write(Writeable::Command(Command::InversionOn)), false => self.write(Writeable::Command(Command::InversionOff)), } } fn set_rotation(&mut self, rotation: Rotation) { self.write(Writeable::Command(Command::MADCTL)); self.write(Writeable::Data(&[rotation as u8])); } fn set_color_mode(&mut self, mode: u8) { self.write(Writeable::Command(Command::ColorMode)); self.write(Writeable::Data(&[mode & 0x77])); } fn set_columns(&mut self, start: u16, end: u16) { let [start1, start2] = start.to_be_bytes(); let [end1, end2] = end.to_be_bytes(); self.write(Writeable::Command(Command::ColumnAlignmentSet)); self.write(Writeable::Data(&[start1, start2, end1, end2])); } fn set_rows(&mut self, start: u16, end: u16) { let [start1, start2] = start.to_be_bytes(); let [end1, end2] = end.to_be_bytes(); self.write(Writeable::Command(Command::RowAlignmentSet)); self.write(Writeable::Data(&[start1, start2, end1, end2])); } fn set_window(&mut self, pos0: Position, pos1: Position) { self.set_columns(pos0.x, pos1.x); self.set_rows(pos0.y, pos1.y); self.write(Writeable::Command(Command::RamWR)); } fn pixel(&mut self, position: Position, color: Color) { self.set_window(position, position); self.write(Writeable::Data(&color.as_bytes())); } fn draw_rect(&mut self, pos0: Position, pos1: Position, color: Color) { self.set_window(pos0, pos1); self.dc.set_high(); let width = pos1.x - pos0.x; let height = pos1.y - pos0.y; let pixels = width * height; let chunks = pixels / 256; let mut full_buf = [0; 512]; let [col1, col2] = color.as_bytes(); for i in 0..256 { full_buf[i * 2] = col1; full_buf[i * 2 + 1] = col2; } for _ in 0..chunks { self.write(Writeable::Data(&full_buf)); } for _ in 0..(pixels % 256) { self.write(Writeable::Data(&color.as_bytes())); } } } #[avr_device::entry] fn main() -> ! { let dp = atmega_hal::Peripherals::take().unwrap(); let pins = atmega_hal::pins!(dp); let rx = pins.pd0; let tx = pins.pd1; let mut serial = Usart::new( dp.USART0, rx, tx.into_output(), Baudrate::::new(57600), ); let cs = pins.pb2.into_output(); let (mut spi, mut cs) = spi::Spi::new( dp.SPI, pins.pb5.into_output(), pins.pb3.into_output(), pins.pb4.into_pull_up_input(), cs, Settings { data_order: spi::DataOrder::MostSignificantFirst, clock: spi::SerialClockRate::OscfOver2, mode: embedded_hal::spi::Mode { polarity: embedded_hal::spi::Polarity::IdleHigh, phase: embedded_hal::spi::Phase::CaptureOnFirstTransition, }, }, ); let mut display = Display { spi, dc: pins.pb1.into_output(), cs, rst: pins.pd7.into_output(), delay: atmega_hal::delay::Delay::::new(), }; display.hard_reset(); display.soft_reset(); display.set_sleep(false); display.set_color_mode((ColorMode::ColorMode65K as u8) | (ColorMode::ColorMode16BIT as u8)); display.delay.delay_ms(50); display.set_inversion(false); display.write(Writeable::Command(Command::NoRon)); display.pixel(Position::default(), Color::default()); display.write(Writeable::Command(Command::DisplayOn)); let mut delay = atmega_hal::delay::Delay::::new(); delay.delay_ms(1000); loop { // color += 40; delay.delay_ms(1000); display.draw_rect( Position { x: 0, y: 0 }, Position { x: 200, y: 200 }, Color::default(), ); ufmt::uwriteln!(&mut serial, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap(); } }