summaryrefslogtreecommitdiffstats
path: root/esp32/main/epd.c
diff options
context:
space:
mode:
Diffstat (limited to 'esp32/main/epd.c')
-rw-r--r--esp32/main/epd.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/esp32/main/epd.c b/esp32/main/epd.c
new file mode 100644
index 0000000..3ba4730
--- /dev/null
+++ b/esp32/main/epd.c
@@ -0,0 +1,290 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <freertos/FreeRTOS.h>
+#include <freertos/task.h>
+
+#include <esp_log.h>
+#include <driver/spi_master.h>
+#include <driver/gpio.h>
+
+#include "epd.h"
+
+#define EPD_CS_PIN GPIO_NUM_15
+#define EPD_DC_PIN GPIO_NUM_27
+#define EPD_RST_PIN GPIO_NUM_26
+#define EPD_CLK_PIN GPIO_NUM_13
+#define EPD_PWR_PIN GPIO_NUM_16
+#define EPD_MOSI_PIN GPIO_NUM_14
+#define EPD_BUSY_PIN GPIO_NUM_25
+
+static const char* TAG = "epd";
+static spi_device_handle_t spi = NULL;
+
+static const unsigned char VOLTAGE_FRAME[] = {
+ 0x6, 0x3F, 0x3F, 0x11, 0x24, 0x7, 0x17,
+};
+
+static const unsigned char LUT_VCOM[] = {
+ 0x0, 0xF, 0xF, 0x0, 0x0, 0x1,
+ 0x0, 0xF, 0x1, 0xF, 0x1, 0x2,
+ 0x0, 0xF, 0xF, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+
+static const unsigned char LUT_WW[] = {
+ 0x10, 0xF, 0xF, 0x0, 0x0, 0x1,
+ 0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
+ 0x20, 0xF, 0xF, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+
+static const unsigned char LUT_BW[] = {
+ 0x10, 0xF, 0xF, 0x0, 0x0, 0x1,
+ 0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
+ 0x20, 0xF, 0xF, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+
+static const unsigned char LUT_WB[] = {
+ 0x80, 0xF, 0xF, 0x0, 0x0, 0x3,
+ 0x84, 0xF, 0x1, 0xF, 0x1, 0x4,
+ 0x40, 0xF, 0xF, 0x0, 0x0, 0x3,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+
+static const unsigned char LUT_BB[] = {
+ 0x80, 0xF, 0xF, 0x0, 0x0, 0x1,
+ 0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
+ 0x40, 0xF, 0xF, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+
+static void spi_pre_cb_handler(spi_transaction_t *t)
+{
+ int dc = (int)t->user;
+ gpio_set_level(EPD_DC_PIN, dc);
+}
+
+static void send_cmd(unsigned char cmd)
+{
+ spi_transaction_t t;
+
+ memset(&t, 0, sizeof(t));
+ t.length = 8;
+ t.tx_data[0] = cmd;
+ t.user = (void*)0;
+ t.flags = SPI_TRANS_USE_TXDATA;
+
+ spi_device_polling_transmit(spi, &t);
+}
+
+static void send_data(unsigned char data)
+{
+ spi_transaction_t t;
+
+ memset(&t, 0, sizeof(t));
+ t.length = 8;
+ t.tx_data[0] = data;
+ t.user = (void*)1;
+ t.flags = SPI_TRANS_USE_TXDATA;
+
+ spi_device_polling_transmit(spi, &t);
+}
+
+static inline void wait_until_idle(void)
+{
+ int busy;
+
+ ESP_LOGI(TAG, "display busy...");
+ do {
+ // triggers watchdog timer, but this was the only way to
+ // get this working
+ // vTaskDelay((TickType_t) 20 / portTICK_PERIOD_MS);
+ send_cmd(0x71);
+ busy = gpio_get_level(EPD_BUSY_PIN);
+ } while (busy == 0);
+
+ vTaskDelay((TickType_t) 200 / portTICK_PERIOD_MS);
+ ESP_LOGI(TAG, "display ready");
+}
+
+static inline void reset(void)
+{
+ gpio_set_level(EPD_RST_PIN, 1);
+ vTaskDelay((TickType_t) 200 / portTICK_PERIOD_MS);
+
+ gpio_set_level(EPD_RST_PIN, 0);
+ vTaskDelay((TickType_t) 2 / portTICK_PERIOD_MS);
+
+ gpio_set_level(EPD_RST_PIN, 1);
+ vTaskDelay((TickType_t) 200 / portTICK_PERIOD_MS);
+}
+
+static inline void config_lut(unsigned char cmd, const unsigned char *lut)
+{
+ send_cmd(cmd);
+
+ for (int i = 0; i < 42; i++)
+ send_data(lut[i]);
+}
+
+void epd_init(void)
+{
+ gpio_config_t io_cfg = {
+ .pin_bit_mask = ((1ULL << EPD_DC_PIN) |
+ (1ULL << EPD_PWR_PIN) |
+ (1ULL << EPD_RST_PIN) |
+ (1ULL << EPD_BUSY_PIN)),
+ .pull_up_en = true
+ };
+
+ ESP_ERROR_CHECK(gpio_config(&io_cfg));
+
+ ESP_ERROR_CHECK(gpio_set_direction(EPD_DC_PIN, GPIO_MODE_OUTPUT));
+ ESP_ERROR_CHECK(gpio_set_direction(EPD_PWR_PIN, GPIO_MODE_OUTPUT));
+ ESP_ERROR_CHECK(gpio_set_direction(EPD_RST_PIN, GPIO_MODE_OUTPUT));
+ ESP_ERROR_CHECK(gpio_set_direction(EPD_BUSY_PIN, GPIO_MODE_INPUT));
+
+ gpio_set_level(EPD_PWR_PIN, 1);
+
+ spi_bus_config_t bus_cfg = {
+ .miso_io_num = -1,
+ .mosi_io_num = EPD_MOSI_PIN,
+ .sclk_io_num = EPD_CLK_PIN,
+ .quadwp_io_num = -1,
+ .quadhd_io_num = -1,
+ .max_transfer_sz = EPD_WIDTH * EPD_HEIGHT
+ };
+
+ ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH_AUTO));
+
+ spi_device_interface_config_t dev_cfg = {
+ .clock_speed_hz = 10 * 1000 * 1000,
+ .mode = 0,
+ .spics_io_num = EPD_CS_PIN,
+ .queue_size = 3,
+ .pre_cb = spi_pre_cb_handler
+ };
+
+ ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &dev_cfg, &spi));
+}
+
+void epd_wake(void)
+{
+ reset();
+
+ send_cmd(0x01);
+ send_data(0x17);
+
+ send_data(*(VOLTAGE_FRAME + 6));
+ send_data(*(VOLTAGE_FRAME + 1));
+ send_data(*(VOLTAGE_FRAME + 2));
+ send_data(*(VOLTAGE_FRAME + 3));
+
+
+ send_cmd(0x82);
+ send_data(*(VOLTAGE_FRAME + 4));
+
+ send_cmd(0x06);
+ send_data(0x27);
+ send_data(0x27);
+ send_data(0x2F);
+ send_data(0x17);
+
+ send_cmd(0x04);
+ vTaskDelay((TickType_t) 100 / portTICK_PERIOD_MS);
+ wait_until_idle();
+
+ send_cmd(0x00);
+ send_data(0x3F);
+
+ send_cmd(0x61);
+ send_data(0x03);
+ send_data(0x20);
+ send_data(0x01);
+ send_data(0xE0);
+
+ send_cmd(0x15);
+ send_data(0x00);
+
+ send_cmd(0x50);
+ send_data(0x10);
+ send_data(0x00);
+
+ send_cmd(0x60);
+ send_data(0x22);
+
+ send_cmd(0x65);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+ send_data(0x00);
+
+ config_lut(0x20, LUT_VCOM);
+ config_lut(0x21, LUT_WW);
+ config_lut(0x22, LUT_BW);
+ config_lut(0x23, LUT_WB);
+ config_lut(0x24, LUT_BB);
+}
+
+static inline void refresh()
+{
+ send_cmd(0x12);
+ vTaskDelay((TickType_t) 100 / portTICK_PERIOD_MS);
+ wait_until_idle();
+}
+
+void epd_clear(void)
+{
+ int height = EPD_HEIGHT;
+ int width = (EPD_WIDTH % 8 == 0) ? (EPD_WIDTH / 8 ) : (EPD_WIDTH / 8 + 1);
+
+ send_cmd(0x10);
+ for(int i = 0; i < height * width; i++)
+ send_data(0xFF);
+
+ send_cmd(0x13);
+ for(int i = 0; i < height * width; i++)
+ send_data(0x00);
+
+ refresh();
+}
+
+void epd_draw(const unsigned char *buf, int n)
+{
+ send_cmd(0x10);
+ for (int i = 0; i < n; i++)
+ send_data(~buf[i]);
+
+ send_cmd(0x13);
+ for (int i = 0; i < n; i++)
+ send_data(buf[i]);
+
+ refresh();
+}
+
+void epd_sleep(void)
+{
+ send_cmd(0x02);
+ wait_until_idle();
+ send_cmd(0x07);
+ send_data(0xA5);
+}
+
+