Skip to content

Commit

Permalink
Begin work on adafruit Epaper Component
Browse files Browse the repository at this point in the history
  • Loading branch information
natelust committed Dec 15, 2022
1 parent 25d355c commit 735917f
Show file tree
Hide file tree
Showing 6 changed files with 571 additions and 0 deletions.
Empty file.
242 changes: 242 additions & 0 deletions esphome/components/adafruit_epaper/adafruit_epaper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
#include "adafruit_epaper.h"


namespace esphome {
namespace adafruit_epaper {

static const char * const TAG = "display.adafruit";

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::busy_wait() {
if (this->busy_pin_ != nullptr) {
ESP_LOGD(TAG, "Hardware busy waiting");
while (this->busy_pin_->digital_read()) {
delay(10);
}
} else {
delay(500);
}
}

template <int WIDTH, int HEIGHT, bool COLOR>
float AdafruitEPaper<WIDTH, HEIGHT, COLOR>::get_setup_priority() const {
return setup_priority::PROCESSOR;
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::setup() {
ESP_LOGD(TAG, "Initializing EPaper display");

this->clear_buffers();
this->cs_->digital_write(true);
//this->init_commands();
this->hardware_reset();

/*
for (int i = 30 ; i < 61; i++ ) {
for (int j = 30; j < 61; j++)
draw_absolute_pixel_internal(i, j, Color(1, 0, 0));
}
*/
//this->display();
//this->clear();
//this->power_down();
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::write_framebuffer_to_display(Buffer buf_number, bool invert) {
this->start_write(buf_number);
this->dc_pin_->digital_write(true);

uint8_t * buffer = buf_number == 0 ? black_buffer : color_buffer;

for (uint32_t i = 0; i < buffer_size; ++i) {
uint8_t data = buffer[i];
if (invert) {
data = ~data;
}
this->enable();
this->write_byte(data);
this->disable();
}
//this->disable();
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::display() {
this->power_up();
this->setRAMAddress(0, 0);
this->write_framebuffer_to_display(Buffer::BLACK, false);
if (COLOR) {
this->setRAMAddress(0, 0);
this->write_framebuffer_to_display(Buffer::COLOR, false);
}
this->update_display();
this->power_down();
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::clear_buffers() {
uint8_t black_value = this->invert_black_color[Buffer::BLACK] ? 0xFF : 0x00;
memset(black_buffer, black_value, buffer_size);

if (COLOR) {
uint8_t color_value = this->invert_black_color[Buffer::COLOR] ? 0xFF : 0x00;
memset(color_buffer, color_value, buffer_size);

}
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::clear() {
clear_buffers();
display();
delay(100);
// do it again to remove ghosts
display();
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::on_safe_shutdown() {
this->clear();
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::init_commands() {
if (init_code == nullptr) {
ESP_LOGE(TAG, "No init commands failed, component cant be initialized");
this->mark_failed();
return;
}
uint8_t buf[64];

while (init_code[0] != 0xFE) {
uint8_t cmd = init_code[0];
init_code++;
uint8_t num_args = init_code[0];
init_code++;
if (cmd == 0xFF) {
busy_wait();
delay(num_args);
continue;
}

for (int i = 0; i < num_args; ++i) {
buf[i] = init_code[0];
init_code++;
}
command(cmd, buf, num_args);
}
}


template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::command(uint8_t cmd, bool end) {
this->cs_->digital_write(true);
this->dc_pin_->digital_write(false);

this->enable();
this->write_byte(cmd);

if (end) {
this->disable();
}
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::command(uint8_t cmd, const uint8_t *buf, uint16_t length) {
this->command(cmd, true);

this->dc_pin_->digital_write(true);

for (uint16_t i = 0; i < length; i++) {
this->enable();
this->write_byte(buf[i]);
this->disable();
}
//this->disable();

}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::hardware_reset() {
if (this->reset_pin_ != nullptr) {
ESP_LOGD(TAG, "hardware reset");
this->reset_pin_->digital_write(true);
delay(10);
this->reset_pin_->digital_write(false);
delay(10);
this->reset_pin_->digital_write(true);
} else {
ESP_LOGD(TAG, "no hardware reset available");

}
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::draw_absolute_pixel_internal(int x, int y, Color color){
if ( x >= WIDTH || y >= HEIGHT) {
ESP_LOGE(TAG, "got pixel data, above bounds");
return;

}
if ( x < 0 || y < 0 ) {
ESP_LOGE(TAG, "got pixel data, below bounds");
return;
}

uint16_t offset = ((uint32_t)(WIDTH - 1 - x) * (uint32_t)_HEIGHT + y) / 8;

uint8_t * black_buf_off = this->black_buffer + offset;
uint8_t * color_buf_off = this->color_buffer + offset;

bool is_black = (color.r == 0) && (color.g == 0) && (color.b == 0);
if (is_black) {
if (!this->invert_black_color[Buffer::BLACK]) {
*black_buf_off &= ~(1 << (7 - y % 8));
} else {
*black_buf_off |= (1 << (7 - y % 8));
}
}

static uint8_t counter = 0;

if (COLOR) {
//bool is_red = color.r > 0;
bool is_red = color.is_on();
if (is_red) {
if (!this->invert_black_color[Buffer::COLOR]) {
*color_buf_off |= (1 << (7 - y % 8));
} else {
*color_buf_off &= ~(1 << (7 - y % 8));
}
}
}
}

template <int WIDTH, int HEIGHT, bool COLOR>
void AdafruitEPaper<WIDTH, HEIGHT, COLOR>::update() {
this->do_update_();
this->display();
}


#ifdef USE_THINKINK_213_TRICOLOR_RW
template void AdafruitEPaper<250, 122, true>::busy_wait();
template void AdafruitEPaper<250, 122, true>::setup();
template float AdafruitEPaper<250, 122, true>::get_setup_priority() const;
template void AdafruitEPaper<250, 122, true>::write_framebuffer_to_display(Buffer buf_number, bool invert);
template void AdafruitEPaper<250, 122, true>::display();
template void AdafruitEPaper<250, 122, true>::clear_buffers();
template void AdafruitEPaper<250, 122, true>::clear();
template void AdafruitEPaper<250, 122, true>::on_safe_shutdown();
template void AdafruitEPaper<250, 122, true>::init_commands();
template void AdafruitEPaper<250, 122, true>::command(uint8_t cmd, bool end);
template void AdafruitEPaper<250, 122, true>::command(uint8_t cmd, const uint8_t *buf, uint16_t length);
template void AdafruitEPaper<250, 122, true>::hardware_reset();
template void AdafruitEPaper<250, 122, true>::draw_absolute_pixel_internal(int x, int y, Color color);
template void AdafruitEPaper<250, 122, true>::update();
#endif

} // namespace adafruit_epaper
} // namespace esphome
82 changes: 82 additions & 0 deletions esphome/components/adafruit_epaper/adafruit_epaper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#pragma once

#include "esphome/core/defines.h"
#include "esphome/core/component.h"
#include "esphome/components/spi/spi.h"
#include "esphome/components/display/display_buffer.h"

namespace esphome {
namespace adafruit_epaper {

enum Buffer {
BLACK = 0,
COLOR = 1
};

template <int WIDTH, int HEIGHT, bool COLOR>
class AdafruitEPaper : public PollingComponent,
public display::DisplayBuffer,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST,
spi::CLOCK_POLARITY_LOW,
spi::CLOCK_PHASE_LEADING,
spi::DATA_RATE_4MHZ> {
public:
void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; }
void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; }
void set_busy_pin(GPIOPin *busy) { this->busy_pin_ = busy; }

float get_setup_priority() const override;

void display();
void clear();

void on_safe_shutdown() override;
void setup() override;

void update() override;

void busy_wait();

protected:
//void draw_absolute_pixel_internal(int x, int y, Color color) override;
void write_framebuffer_to_display(Buffer buf_number, bool invert=false);
void command(uint8_t cmd, bool end=true);
void command(uint8_t cmd, const uint8_t *buf, uint16_t length);
void clear_buffers();
void init_commands();
void hardware_reset();
void draw_absolute_pixel_internal(int x, int y, Color color) override;

int get_height_internal() override {
return HEIGHT;
}

int get_width_internal() override {
return WIDTH;
}

// Methods to be overridden by subclasses
virtual void power_up() = 0;
virtual void power_down() = 0;
virtual void update_display();
virtual void start_write(Buffer buf_number) = 0;
virtual void setRAMAddress(uint16_t x, uint16_t y) = 0;
//virtual uint8_t * get_buffer_from_number(Buffer buf_num) = 0;

// class members
GPIOPin *reset_pin_ = nullptr;
GPIOPin *dc_pin_ = nullptr;
GPIOPin *busy_pin_ = nullptr;

const static uint16_t _HEIGHT = HEIGHT + (HEIGHT % 8 != 0) * (8 - (HEIGHT % 8));

const static uint32_t buffer_size = WIDTH*_HEIGHT/8;
uint8_t black_buffer[buffer_size];
const uint8_t * init_code = nullptr;
bool invert_black_color[2] = {true, false};
uint8_t * _epd_init_code = nullptr;
// use only a single byte if color is not needed
uint8_t color_buffer[COLOR*buffer_size];
};
} // namespace adafruit_epaper
} // namespace esphome
Loading

0 comments on commit 735917f

Please sign in to comment.