-
-
Notifications
You must be signed in to change notification settings - Fork 54
EPDiy open book project
EPDiy PCB V6 with a 6" eink display (Schematic PDF)
EPDiy is a project I discovered on Hackaday some months ago and it really blow up my mind. I never though you could control parallel epapers this way using I2S protocol in LCD master transmitting mode. But there it is working for many supported epapers.
The complex part is to order and build a EPDiy PCB something that requires a bit of experience in electronic manufacturing. Because many providers like JLC and others will deliver most of the things already mounted, but I heard that part of them have to be soldered by hand. And that dealing with this surface mounted components requires some skills to get it to work.
I will go through this process soon and update this Wiki with the relevant information. Once the EPDiy PCB is working and you select what epaper you want to use then building your own Epub reader using this repository is quite straight-forward. You need:
- A 3.7 volt Lithium Ion battery. 2000 or 3000 mAh should be enough to get your device long days running.
- 3 simple push buttons (From free GPIOs and connected with a resistance 3.3 volt)
- 1 On/Off switch (Optional)
- A supported 8 data lines parallel epaper (>=800x600 better but any resolution will do)
That's all hardware requirements. The free GPIOs we used to test are referenced in platformio.ini (environment: epdiy) I've used like you can see on the picture an open format since I want to test another einks with my only EPDiy board. But is possible also to design a closed case that looks more compact.
I buy them mostly from Aliexpress. But be aware that it's kind of lottery. You never really know if the epaper is new, refurbished or it was collected from some factory garbage. Be careful to select one of the EPDiy supported einks. And take care with the extras announced. As an example the epaper shown in the picture above was announced as "New 6 inch epaper with touch ED060XC5(LF)" and it does not have touch. That simple FPC cable it's just a front light. There are mostly no specifications, so you got no clue what voltage it needs to turn on the LEDs. After much testing I discovered that sending the frontlight 15 volt with a 220 Ohm resistance it works out so the 5 LEDs should be in parallel and each consumes aprox. 2.7 v. Did a reclaim in Aliexpress and got back half of the 40 dollars spent. Buy the cheapest ones! As you can see is a bit of luck so the less to loose the better.
After using 8 data lines plus other GPIOs to drive the parallel epaper display there is a shortage of Input / Output pins in the ESP32. That's why in version 6 of the PCB introduces pca9555 that is defined as:
A 16 bits of General Purpose parallel. Input/Output (GPIO) expansion using I2C-bus. The PCA9555 consists of two 8-bit Configuration (Input or Output selection); Input, Output and Polarity Inversion (active HIGH or active LOW operation) registers. The system controller can enable the I/Os as either inputs or outputs by writing to the I/O configuration bits. More info and datasheet in nxp.com
Note: Button is marked in IO7 but is moved to use first 2 bits IO0 & IO1 in current version
The PCA9555 has also an Interrupt PIN that is called CFG_INTR. This output is LOW when one of the 16 IOs updates his state so you can proceed and read using I2C what is it's value. For this test we connect the IO0 & IO1 with a 10K pull-up resistance to 3.3 volt and each push Button will connect it to GND.
Basically the upper bits of the 8-port IO expander is used internally by the EPDiy controller and the other one is exposed in the PCB letting you use them for your own Firmware. We use it in the open book project to read the buttons since it's an ePub reader and we don't need speed. Reading the buttons is quite easy and has the benefit that you don't need debouncing. In this examples below we are going to expose how we are using this in your Firmware for the Epub reader. To resume it in a sentence: Instead of reading the button states with GPIO interrupts we are going to start a Task in core 1 and loop until we detect PCA's CFG_INTR in a low state. Then we proceed to read our button state using I2C read. This two functions where taken from EPDiy's own pca9555.c implementation.
Example from our C++ implementation: ButtonControlsEpdiyV6.h
#pragma once
#include "pca9555.h"
#include <driver/i2c.h>
// Excluding other includes to make this shorter
// This CFG_INTR is defined on display_ops.h
#define CFG_INTR GPIO_NUM_35
#define EPDIY_I2C_PORT I2C_NUM_0
#define REG_INPUT_PORT0 0
class ButtonControls
{
private:
gpio_num_t gpio_down;
gpio_num_t gpio_select;
int active_level;
Button *select;
ActionCallback_t on_action;
// I2C related for IO expander PCA9555
static const int EPDIY_PCA9555_ADDR = 0x20;
// This 2 where shameless copied from pca9555.c epdiy component:
esp_err_t i2c_master_read_slave(i2c_port_t i2c_num, uint8_t* data_rd, size_t size, int reg);
uint8_t pca9555_read_input(i2c_port_t port, int high_port);
// Note: pca9555 IO ports are declared as input as default. Important: IOs should be pulled-up to 3.3v
// IO returns: 1 when IO0 is released. 2 when IO1 is released (PCA input ports)
static void control_task(void *param) {
ButtonControls *bc = (ButtonControls*) param;
for (;;) {
if (gpio_get_level(CFG_INTR) == 0) {
uint8_t read = bc->pca9555_read_input(EPDIY_I2C_PORT, 0);
if (read == 2) {
bc->on_action(UIAction::UP);
} else if (read == 1) {
bc->on_action(UIAction::DOWN);
}
ESP_LOGI("Controls", "Read I2C:%d\n", read);
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}
public:
ButtonControls(
gpio_num_t gpio_select,
int active_level,
ActionCallback_t on_action);
};
ButtonControlsEpdiyV6.cpp
#include "ButtonControlsEpdiyV6.h"
ButtonControls::ButtonControls(
gpio_num_t gpio_select,
int active_level,
ActionCallback_t on_action)
: gpio_down(gpio_down), gpio_select(gpio_select),
active_level(active_level),
on_action(on_action)
{
gpio_install_isr_service(0);
select = new Button(gpio_select, active_level, [this]()
{ this->on_action(UIAction::SELECT); });
// We start a task in Core 1 that will loop and read the I2C IO state changes
xTaskCreatePinnedToCore(this->control_task, "control_task", 4096, this, 2, NULL, 1);
}
esp_err_t ButtonControls::i2c_master_read_slave(i2c_port_t i2c_num, uint8_t* data_rd, size_t size, int reg)
{
if (size == 0) {
return ESP_OK;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( EPDIY_PCA9555_ADDR << 1 ) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, reg, true);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
if (ret != ESP_OK) {
return ret;
}
i2c_cmd_link_delete(cmd);
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( EPDIY_PCA9555_ADDR << 1 ) | I2C_MASTER_READ, true);
if (size > 1) {
i2c_master_read(cmd, data_rd, size - 1, I2C_MASTER_ACK);
}
i2c_master_read_byte(cmd, data_rd + size - 1, I2C_MASTER_NACK);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
if (ret != ESP_OK) {
return ret;
}
i2c_cmd_link_delete(cmd);
return ESP_OK;
}
uint8_t ButtonControls::pca9555_read_input(i2c_port_t i2c_port, int high_port) {
esp_err_t err;
uint8_t r_data[1];
err = i2c_master_read_slave(i2c_port, r_data, 1, REG_INPUT_PORT0 + high_port);
if (err != ESP_OK) {
ESP_LOGE("PCA9555", "%s failed", __func__);
return 0;
}
return r_data[0];
}
Preview full code update to implement this in my pull request #63 IMPORTANT: Even if the buttons are active when high they should be pulled down with a 10K resistance to Ground. Otherwise they are super sensible and they will get pressed state with any noise. In this example UP and DOWN buttons are read by I2C and SELECT connected directly to a GPIO but of course it could be any configuration just changing the Firmware minimally.
At the moment I didn't found a way to "hook" into EPDiy V6 own instantiation in order to use this. Meaning you will have to implement the I2C read functions in your side of the Firmware. It would be nice that you could add your own callback function somehow, so the PCA9555 management stays in the side of EPDiy and it's easier to use it from your Firmware side (As the IO expander is really a functional part of the epaper controller but also offers outside functionality) It's also to my knowledge, powered off when EPDiy is in this state or in deepsleep mode, so you won't be able to read the CFG_INTR using the ultra low power processor to wake up in the ESP32.
An example that works using free GPIOs after using I2C to read 2 buttons is presented here below. Provided you use one of this 3.3v SD card readers that come already with the pull-up resistances in place, you only have to assign this 4 IOs in platformio.ini epdiy environment to get the card working:
; IMPORTANT: If this parameter is commented then it defaults to use SD Card
;-D USE_SPIFFS
; setup the pins for the SDCard
-DSD_CARD_PIN_NUM_MISO=GPIO_NUM_36
-DSD_CARD_PIN_NUM_MOSI=GPIO_NUM_0
-DSD_CARD_PIN_NUM_CLK=GPIO_NUM_13
-DSD_CARD_PIN_NUM_CS=GPIO_NUM_14
diy-esp32-epub-reader wiki v. 1.1 Hackaday EPub reader page | Project Chat-room