slideshow/src/main.rs
2025-09-10 21:24:18 +03:00

329 lines
8.5 KiB
Rust

/*!
* 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<T: DelayNs> {
spi: Spi,
delay: T,
}
impl<T: DelayNs> embedded_hal::spi::ErrorType for Device<T> {
type Error = Infallible;
}
impl<T: DelayNs> embedded_hal::spi::SpiDevice for Device<T> {
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<T: DelayNs, DCPin: PinOps, RSTPin: PinOps> {
spi: Spi,
cs: ChipSelectPin<port::PB2>,
dc: Pin<mode::Output, DCPin>,
rst: Pin<mode::Output, RSTPin>,
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<T: DelayNs, DCPin: PinOps, RSTPin: PinOps> Display<T, DCPin, RSTPin> {
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::<CoreClock>::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::<CoreClock>::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::<CoreClock>::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();
}
}