01274f5cb7
Move firmware files from repo root src/ into firmware/ to avoid collision with Symfony's src/ PHP class directory. Add DDEV config targeting PHP 8.4 / PostgreSQL 16 / nginx-fpm with Imagick extension via docker-compose override. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
120 lines
3.3 KiB
C++
120 lines
3.3 KiB
C++
#include <Arduino.h>
|
||
#include <SPI.h>
|
||
#include "image.h"
|
||
|
||
#define EPD_WIDTH 800
|
||
#define EPD_HEIGHT 480
|
||
#define IMG_W 480 // portrait image dimensions
|
||
#define IMG_H 800
|
||
#define PIN_SCK 18
|
||
#define PIN_MOSI 23
|
||
#define PIN_CS 5
|
||
#define PIN_DC 17
|
||
#define PIN_RST 16
|
||
#define PIN_BUSY 4
|
||
|
||
static uint8_t row_buf[EPD_WIDTH / 2];
|
||
|
||
void wait_busy() { while (digitalRead(PIN_BUSY) == LOW) delay(5); }
|
||
|
||
void send_command(uint8_t cmd) {
|
||
digitalWrite(PIN_DC, LOW);
|
||
digitalWrite(PIN_CS, LOW);
|
||
SPI.transfer(cmd);
|
||
digitalWrite(PIN_CS, HIGH);
|
||
}
|
||
|
||
void send_data(uint8_t data) {
|
||
digitalWrite(PIN_DC, HIGH);
|
||
digitalWrite(PIN_CS, LOW);
|
||
SPI.transfer(data);
|
||
digitalWrite(PIN_CS, HIGH);
|
||
}
|
||
|
||
void epd_reset() {
|
||
digitalWrite(PIN_RST, HIGH); delay(20);
|
||
digitalWrite(PIN_RST, LOW); delay(2);
|
||
digitalWrite(PIN_RST, HIGH); delay(20);
|
||
}
|
||
|
||
void epd_init() {
|
||
epd_reset();
|
||
wait_busy();
|
||
delay(30);
|
||
send_command(0xAA);
|
||
send_data(0x49); send_data(0x55); send_data(0x20);
|
||
send_data(0x08); send_data(0x09); send_data(0x18);
|
||
send_command(0x01); send_data(0x3F);
|
||
send_command(0x00); send_data(0x5F); send_data(0x69);
|
||
send_command(0x03);
|
||
send_data(0x00); send_data(0x54); send_data(0x00); send_data(0x44);
|
||
send_command(0x05);
|
||
send_data(0x40); send_data(0x1F); send_data(0x1F); send_data(0x2C);
|
||
send_command(0x06);
|
||
send_data(0x6F); send_data(0x1F); send_data(0x17); send_data(0x49);
|
||
send_command(0x08);
|
||
send_data(0x6F); send_data(0x1F); send_data(0x1F); send_data(0x22);
|
||
send_command(0x30); send_data(0x03);
|
||
send_command(0x50); send_data(0x3F);
|
||
send_command(0x60); send_data(0x02); send_data(0x00);
|
||
send_command(0x61);
|
||
send_data(0x03); send_data(0x20); send_data(0x01); send_data(0xE0);
|
||
send_command(0x84); send_data(0x01);
|
||
send_command(0xE3); send_data(0x2F);
|
||
send_command(0x04);
|
||
wait_busy();
|
||
}
|
||
|
||
void epd_sleep() {
|
||
send_command(0x02); send_data(0x00); wait_busy();
|
||
send_command(0x07); send_data(0xA5);
|
||
}
|
||
|
||
void show_image() {
|
||
send_command(0x10);
|
||
digitalWrite(PIN_DC, HIGH);
|
||
digitalWrite(PIN_CS, LOW);
|
||
|
||
// 90° CW rotation: display(x,y) → portrait(IMG_W-1-y, x)
|
||
// Portrait image is IMG_W×IMG_H, IMAGE_ROW = IMG_W/2 bytes per portrait row.
|
||
for (int y = 0; y < EPD_HEIGHT; y++) {
|
||
int pcol = (IMG_W - 1) - y;
|
||
for (int x = 0; x < EPD_WIDTH; x++) {
|
||
uint32_t bidx = (uint32_t)x * IMAGE_ROW + pcol / 2;
|
||
uint8_t b = pgm_read_byte(&IMAGE_DATA[bidx]);
|
||
uint8_t code = (pcol & 1) ? (b & 0x0F) : (b >> 4);
|
||
if (x & 1)
|
||
row_buf[x / 2] = (row_buf[x / 2] & 0xF0) | code;
|
||
else
|
||
row_buf[x / 2] = (code << 4) | (row_buf[x / 2] & 0x0F);
|
||
}
|
||
SPI.writeBytes(row_buf, sizeof(row_buf));
|
||
}
|
||
digitalWrite(PIN_CS, HIGH);
|
||
|
||
send_command(0x04); wait_busy();
|
||
send_command(0x12); send_data(0x00); wait_busy();
|
||
}
|
||
|
||
void setup() {
|
||
Serial.begin(115200);
|
||
Serial.println("pictureFrame");
|
||
|
||
pinMode(PIN_CS, OUTPUT);
|
||
pinMode(PIN_DC, OUTPUT);
|
||
pinMode(PIN_RST, OUTPUT);
|
||
pinMode(PIN_BUSY, INPUT);
|
||
|
||
SPI.begin(PIN_SCK, -1, PIN_MOSI, PIN_CS);
|
||
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||
|
||
epd_init();
|
||
show_image();
|
||
epd_sleep();
|
||
Serial.println("Done.");
|
||
}
|
||
|
||
void loop() {
|
||
delay(60000);
|
||
}
|