New cases for the 9.7″ parallel displays and proposal for CLB Club

This might be a continuation from the Cinwrite DEXA epaper controller that we designed just after partnering with Freddie from
The idea is to prepare an open source Firmware that is ready to be used with different examples and two target controllers:

1 – DEXA-C097 from Good-Display needs additionally my Cinwrite ESP32-S3 SPI controller
Optionally any ESP32 board with an RTC connected via I2C

2 – EPDiy V5 codenamed “Inkster” that you can find in Tindie

Option 1: Fast update and proprietary Waveform

With this option we designed already some panels for stores but also a very fancy ebook reader with an extra SPI SD card from Adafruit.

We also sent proposals to make a Temperature / Humidity / CO2 level weather panel to Macba, CLB fight club Barcelona and others.
Sadly we hit the generic info email in Macba so no-one will reply to that when the proposal falls in the wrong hands.

Customizing of this Panels can be done with various sensors:

  • Environamental like SCD40 / 41 Temperature, humidity
  • Dust sensors
  • Many others you can find in Sensirion catalog

Basically anything that can be plugged per I2C or SPI can be read. And the data results retrieved and converted in a format you like, using the fonts you desire, and any PNG icons or images of your choice. The possibilities are endless!

For the CLB club we are using RTC at it’s best. The fight club has an schedule that we converted to Vectors using C++. Then having the great possibility to be aware of time with our on board RTC we can just display the current activity as you can see in the photos.
So it’s not only a weather panel. It’s also showing what class is being instructed in the Gym.

Challenges: You need 2 boards the Cinread board and our own Cinwrite SPI master controller. They can be used together as a HAT (No cables around) But if you need a flat design like the ePub reader you need to wire 4 SPI cables together plus VCC and GND.
Contraindications: VCOM is slow to regulate to your desired voltage. Probably some mistake by that is the factory for this controllers that are resold by GoodDisplay.

Our Cinwrite ESP32S3 PCB generates 5 Volts from the battery power (3.7 to 4.2 Volts when fully charged) so you have this issue already resolved if you use our controller and you also have RTC.

Option 2: EPDiy

EPDiy is our one board controller of choice since we discovered it 2 years ago. We collaborated in the repository adding “software Rotation” that is what Lilygo lacks in their own EPD47 repository since they are lazy enough not to use latest version of EPDiy.

We understand that because hardware sellers focus primarily in Harware but not specially in bringing dedicated Software support or answering every Issue in their repositories. But we are still very thankful that they got parallel communication working in ESP32S3 and that opens the path to EPDiy V7 with 16 data lines for more modern epaper displays.

We made already nice panels using EPDiy V5 called Inkster. Martin is a very cool maker from Czechia and he is also a very cool and handsome man ;)

Contraindications: The VCOM in this controllers needs to be regulated by hand using a Multimeter until you match the epaper Vcom voltage (If it’s somewhere on the display usually there is a small adhesive). This controller uses ESP32 and an open source Waveform and does not update as fast as Option 1.
Challenges: There are not more than 4 GPIOs available. You can’t just connect another SPI device if you use 1 for a button. You can connect an RTC killing 2 buttons and using them as I2C lines.

Grab the STL and Blender file to print this 1200*825 epaper case

Testing touch on small SPI epaper displays

Our now IDF ver. 5 compatible touch component FT6X36 is ready to be tested.

There are two affordable models that I would like to cover in this post. First one is the 400×300 FT6336 from Good Display, we can see this one in action (2nd video, 1st had still wrong Waveform)

I2C touch interface Focal Tech. Pin-out follows:
2 VDD -> 3.3V only, not 5V!
3 RST (Not used in this component)

It’s important to know that each different model uses a different pinup in the 6 pin FPC cable, so if you had the great idea to make an universal adapter, you will fail doing it (Guess who tried?)
Please note also that I do not use GoodDisplay touch adapter for this since I do not like the fact that you can use it only for touch or for SPI but not both, so I choose to use a simple 6 pin FPC adapter that you can find cheap in Aliexpress.

Note there is a small gotcha with this ones! Sometimes the FPC is bottom-contact only so make sure to plug it with the contacts facing down (Disregard this if it has double sided contacts)
Also we are using a very raw touch interface to MCU connection there are some technical things to keep in mind:

1. I2C is a bidirectional connection and needs pull-up resistors to 3.3V in both SDA and SCL lines (4.7K or even 6K Ω will work)
2. INT pin goes low when there is an event to read via I2C. Same as last case, you should not leave this pin floating and add also a pullup to 3.3V.

The 2.7″ smaller brother

The smaller 2.7″ has also an optional touch screen. This model called Gdey027T91T with 264*176 pixels resolution seems to be at the moment out of stock, but you can get the touch separately, and just stick it with care in the top of the epaper display.

In the video you can see how fast partial update works in this model, compared with my 4.2″ version
3 RST (Not used in this component)

Also if you want to use Espressif IDF framework to handle touch events plus epaper component with GFX, we highly recommend to try Cale-idf
Cale is a component that is already 2 years in development and has the most common epapers from Goodisplay / Waveshare, including this two touch models. It also has the interesting fact, and sometimes important, if you design something that is able to rotate screen of adapting touch to this rotation. Only on certain classes like the 2.7″ since we are no-one requested yet to add this feature to the 4.2″ display class.
On our example demo-keyboard.cpp on cale component you can clearly see how this is implemented:

// Include touch plus the right class for your display
#include "FT6X36.h"
#include "goodisplay/touch/gdey027T91T.h"

// INTGPIO is touch interrupt, goes low when it detects a touch, which coordinates are read by I2C
// Use an RTC IO if you need to wake-up with touch!
EpdSpi io;
// At this moment we insert touch into the display class!
Gdey027T91T display(io, ts);

uint8_t display_rotation = 3; // 1 or 3: Landscape mode
int t_counter = 0;

// This callback function will be fired on each touch event
void touchEvent(TPoint p, TEvent e)
    printf("X: %d Y: %d count:%d Ev:%d\n", p.x, p.y, t_counter, int(e));

// Entry point of our Firmware
void app_main()
   // Initialize display and SPI
   // When using the ClassT integrated with touch then rotating this
   // rotates touch X,Y coordinates too.
   // You could launch this also in a FreeRTOS task
   for (;;) {

Dust sensor data representation

The idea of using a HM3301 Laser dust sensor was to make a data representation that instead of boring numbers show a more visual appealing image representing particles and their size.
For that we though about making a read each 2 minutes and use a bi-stable display with 4 grays.
Components used:

The build work!
First you should measure the ESP32 board that you are going to use. Same we did with the HM3301 sensor 3D Model and we also uploaded it to Thingiverse.

That way it’s easier to place in the 3D design and move the small holders with 2mm holes (for the screws) to secure your board. You know, when you start using hot glue everywhere, is when it starts lookin’ bad :)
For that reason we provided the Blender file so you can use a free 3D modeling program to move things around as you like. Then you can simply switch to Wireframe view with key Z select with B (Bounding box) all what you want to export and export to STL.

This small article is focused on the build and Blender itself is a tool that is not for the faint of the heart, but is a nice and powerful 3D program, that in my case made sense to spend days learning how to tinker with it.

After 3D printing the bottom case you can start placing the parts. But it makes a lot of sense to test all this outside the box first, so first we need to connect the sensor that is easy since it’s 2 wire I2C (Plus power and SET pin, that on low makes the sensor sleep)

# Default I2C (No need for pull-ups are already in the sensor)
# Note we use 14 but could be any output PIN

With those in place we should be able to already flash a program and check the measurements. Please note that SET pin should be on HIGH in order for the sensor to be powered on (Bring the small fan close to your ear, you should hear it!)
For that we created our HM3301 component since there was no ESP32 IDF component, you can find it here:

You can already link this as a submodule in the components folder or for an easier test, just download our epaper-weather-station project and their linked components using the develop branch:

git clone –branch develop –recursive

–recursive will also pull linked submodules making it really easy to have everything available at once.
Updating the main/CMakeLists.txt you can point the build process to the file you want to build as your main entry point. And in the main/tests directory we left an hm3301 test program.

If that goes as expected then doing a: flash monitor
You should see sensor readings in the Serial output.
Congratulations, your Dust sensor seems to be measuring particles.

Now let’s go ahead and connect the epaper display!
Make sure that you connect the SPI adapter DESPI-CO3 and secure it to the epaper with some nice tape. I’ve used also here 2 small spots of hot glue but is not recommended, you might damage that nice display (Although I didn’t since I wait some seconds until is not super hot and I apply 2 small spots)
The idea is just to avoid making force over the sensible FPC flexible cable.
Once that is done you can start the SPI + power wiring to the ESP32 board:


That are IOs we used. For MOSI and CLOCK we usually use the ESP32 defaults. But you could of course use the GPIO matrix to route this signals to any output pins.
If all that is good connected and also the 3.3V and GND pins are perfectly connected, and tested with the multimeter that in fact are powering the epaper…then this should display something!
Just try our next example program:

With particle-draw.cpp you can test a program that reads from HM3301 and displays some random circles showing how many PM1, PM2.5 and PM10 particles are there.

Compiling an ARM Linux kernel with EBC eink interface

First of all the essentials which are clearly explained here:

Build your first Linux kernel and make sure you have at least 8 GB free disk space .
Please be aware that building your own Linux kernel needs to be done with care and it’s a risky operation where you might need to wipe everything if done incorrectly. This was done on a fresh installation of Manjaro in my PINE64 Model A board.
Since writing for the web they say you need to start with the solution, after building my kernel in the board, I forked Smaeul and updated my changes:

Branch: rk356x-ebc-compiled
Don’t use that yet: I took the wrong branch when doing this and used master. The right one is: rk356x-ebc-dev

Regulator kernel module needed for the high voltages
EBC module made by Samuel Holland

This is already compiled now and I’m currently checking that it works before pushing it again to the repository

If you choose to use this you can go directly to Step 2 since the make is already done.

Step1. Download the kernel and build it

I’ve used the link to the Linux kernel from Smaeul fork that is linked on the Pinebook Wiki page. Please note that our target PC is a Quartz model A board from Pine64

ZIP or compressed is highly recommended because it’s almost 4 GB

Build it using:

make -j$(nproc)

That will take a long while specially if your PC is slow

2. Backup and install the new kernel

sudo make modules_install
sudo make install

That will actually install the compiled modules in your /lib/modules directory and the kernel file and the

INSTALL /lib/modules/5.19.0-MANJARO-ARM-RC+

The make install will build a vmlinux file that is your new kernel. In my case it is 30 MB.

Now this is an important step:
Before installing our new kernel, let’s backup the /boot directory, just in case everything stops working, and you want to come back to the old stable kernel.

cp -r /boot/* /run/media/user/your_USB_SSD_name/old_boot/

3. Generate the intra RAM filesystem

Now we will need to generate initramfs

initramfs is a root filesystem that is embedded into the kernel and loaded at an early stage of the boot process. It is the successor of initrd. It provides early userspace which can do things the kernel can’t easily do by itself during the boot process. Using initramfs is optional.

So that is an essential part (I think) since Arch based distros use mkinitcpio which is a bash script to automate the generation of the initramfs.

Running: sudo mkinitcpio -p linux-rc

Now if you execute a: uname -a

And it returns the date where you compiled the kernel then congrats! You just build your own Linux kernel. What a monumenal work, all coded in beautiful .c, with Linus Torvalds and his long wipe correcting development mistakes and merging. You just made it.

fasani-pc 6.1.0-rc1-2-MANJARO-ARM-RC #1 SMP PREEMPT Mon Oct 17 16:43:21 UTC 2022 aarch64 GNU/Linux

4. Cross your fingers and reboot your PC

If nothing happens, you’ve been warned at the beginning, not my fault!

Now if you do a: modprobe -c | less
To display the comprehensive configuration of all the modules and you find something like:

alias of:N*T*Crockchip,rk3566_vop rockchipdrm probably we are fine. I’m really not sure of this point, of course the real test is to send a frame to the EBC, check if the high voltages are there and see the epaper refresh.
Mind that you have to also explore a second repository of Samuel: who did the reverse engineering of the EBC part since the original one came with the Eink drivers compiled (Thanks Eink .com to make our lives easier)

RK3566_Module from the Quartz A Schematics showing the DRM to the 16 data plus control lines for the epaper and PMIC

Making our own ESP32S3 BLE receive JPEG image Firmware

Since long I’ve been interested in using another means to receive binary data that are more low-consumption oriented than WiFi.
And there is a protocol for that, which should be the standard, when sending and receiving BLE files. It’s called L2CAP: Logical Link Control and Adaptation Protocol:

L2CAP permits higher-level protocols (such as GATT and SM) and applications to transmit and receive upper layer data packets

Texas Instruments BLE stack

What is the L2CAP status in ESP32 framework?
There is code and documentation to implement L2CAP in Classic Bluetooth:
This examples, Server and Client, can be built and flashed in ESP32. It allows to send and receive data using L2CAP. But you cannot just connect to the ESP32 and send a file.
Need to research more, but it seems something more needs to be implemented to act as a “Receive file” BT- server.
Note that this examples are not buildable in ESP32S3. Newer models of ESP32 like S3 have BLE on board, but not Bluetooth-classic.
I asked Espressif both per Twitter and also per email to see if there is any timeline to add L2CAP support in BLE. To the date of writing this line I still didn’t got any reply.

Will L2CAP be supported also in BLE, an hence, in newer MCU’s like ESP32S3 ?

UPDATE: When I wrote this article I was being focused in only one of the BLE stack: Bluedroid. But I researched more and discovered there is also NimBLE which has an existing L2CAP example that I still didn’t tried. Maybe is worth some tests and also NimBLE seems to be the recommended way if you just need BLE (Less code, less RAM usage)

So how do developers send data or images using BLE using Espressif MCU’s ?

Basically everyone implements their own protocol and App to send their data.
Since I didn’t want to be less of a fool than the others, I decided to implement my own example, that I will detail here below. If there is any interest, then I will add it some repository, so someone can benefit from it.
My example grown based on the GATT server. So it’s important to read and understand correctly the GATT server walk-through.

To start with first we kickstart a BLE service_id and publish it’s characteristics. The char_id’s are the “abilities” this services is offering. Like for example Receive file, Notifications etc.
So we start by publishing a service and one characteristic on our ESP32BLE Server instance.
In the Client side, using mainly Javascript and Chrome, we will connect to this BLE Service and grab it’s charasteristic, to be able to WRITE to it.
Note that both parts of this project are fully open-source

And then we need to add some additional hooks, since in my case I would like to know how long is the file we are going to receive (The old know content-length HTTP header, that we don’t have in BLE, so we will invent it)
And I also would like to receive an “end of file” signal or EOF, that will come after the byte-stream ends, and will be also the Firmware signal to say: Hey the JPG just finished to arrive, just decompress the receive buffer, and send it to the display.

This is what I though to be appropriate to implement those

  • 0x01 -> uint32 content length so the server will receive a 5 bytes message
    0x01 byte1 byte2 byte3 byte4 (MSB on the left) which can be decoded in the Firmware like: uint32_t received_length = param->write.value[1] + (param->write.value[2] << 8) +(param->write.value[3] << 16) + (param->write.value[4] << 24);
  • Byte stream. This is not prepended by any special command. Is just a continuous byte streams in chunks of about 448 bytes from the beginning till the end of our file
  • 0x09 end of file signal. Only 1 byte. Just decompress the JPEG using JPEGDEC from Larry bank, at the same time this will be our validation that it’s a valid JPEG.
    Render it to the epaper display.
First idea on how to implement this
BLE receive at work

As a resume this is doable. Is not a perfect way to receive a binary. It’s just not great to use Chrome since you force your users to use this browser which also needs a special “Bluetooth permission”. Probably would be better suited to make an Android app that is far away from the scope of this experiment.
And it’s just a very RAW sending that does not implement any way to recover lost packages. Walk away with your receiving client and your JPEG will never arrive in one piece.

Sending this using Chrome browser

The way we are currently sending this, is to open and read the JPG with any server backend language, we use PHP in

$jpg = file_get_contents($jpgUrl);

// Convert that bytes to HEXA
$hexStr = bin2hex($jpg);
// str_split — Convert a string to an array
foreach (str_split($hexStr,2) as $byte) {
            if ($count%16 === 0) {
          // Add newline every 16 bytes so is easy to compare
                $image_array[] = $byte."\n";
            } else {
                $image_array[] = $byte;
// Output image_array in your textarea

// Like this JS reads and converts to byte again
// A bit awkward but is easy to compare if the same bytes arrive
// to the ESP32 end. One wrong byte and JPG won't decompress

Probably there is an easier and cleaner way to do it. My way to show this is just a developer proof-of-concept example, but of course you could do it nicer. Or just pack all this in an Android App, which will be much more friendlier to use, just needs to open an image from your phone and resize it to your display width / height so you avoid sending a huge JPEG.
Other than this notes and some failed sendings, since Chrome BLE is also not enabled by default and considered to be experimental beta, this is a valid example and it’s working 99% of the time to receive images. In my Linux I often had to restart bluetooth since I’m getting some GATT is busy error messages in Chrome, that I don’t know where they come from and how to get rid of them.

If you feel that this can be helpful for you in an independent repository just let me know and I will tidy it up a bit.

New Cinwrite SPI HAT for IT8951 parallel epaper controllers

At the moment only available in Tindie Fasani Corporation store this PCB mission is to provide:

  • ESP32S3 Espressif MCU with 2MB of external RAM
  • WiFi
  • BLE
  • DS3231 real time clock and small CR1220 coin battery to keep time
  • Fast 40Mhz SPI
  • 3V to 5V step-up (And a way to enable this boost converter)
  • 3.7v LiPo battery charger

This Cinwrite PCB is open source Hardware that you can explore and even adapt to your needs.

The price is 45 USD since I only made 5 and otherwise it will be impossible to cover the costs. But it might go lower if we can make a budget version without Bluetooth, that is, provided there is some interested parties in using it.
This along with DEXA-C097 IT8951 controller sold by GoodDisplay, and fabricated by CINREAD, can be a very powerful option to use very fast 8-bit parallel displays, such as ED097OC4 or ED097TC2. There are many models available and all of them should work, they just have different contrast and VCOM voltage adjustments.
Making this board a very good option to control them and make a digital clock for a store, or add sensors in it’s dedicated I2C connector, such as Humidity, CO2 air quality or anything that can be plugged in this super fast MCU from Espressif.

Testing Pine64 Quartz model A board

The Quartz64 Model A is powered by a Rockchip RK3566 quad-core ARM Cortex A55 64-Bit Processor with a Mali G-52 GPU. It comes equipped with 2GB, 4GB or 8GB LPDDR4 system memory, and a 128Mb SPI boot flash. There is also an optional eMMC module (up to 128GB) and a microSD slot for booting.

Top side of the Quartz model A board. The SD card holder, that I broke accidentally, is on the bottom side of the PCB

So far I tried the following and worked out without issues:
– Installed Balena etcher in Ubuntu, a nice software to make bootable SD’s or eMMC
Downloaded last version of Manjaro-arm for this board (at this moment: 0220606 release)
– Connected an external monitor using HDMI, an external wireless logitech Keyboard/Mouse, all recognized automatically by Manjaro

Additionally I wrote a post in Pine64 forum, since I want to know how to go further and test the Eink interface.

This is the result:

Curious to connect a LAN cable afterwards since this does not have WiFi and also trying out a WLAN USB to see if I can also use external WiFi.

Moved to Barcelona

Well it was hard, frustrating and a very tiring experience to say the least. But after finally signing a one year Contract for the apartment, and many “Nos” for other’s we’d liked, but we didn’t qualify since we do not have any spanish work…we are settling down nicely and already got high speed internet installed.
Now is time to keep on developing working for future electronic projects and contributing to the open source community.

EPDiy developer updates is being posted regularly on my twitter timeline

EPDiy S2 PCB is still on development

High voltages are running already but there are still some minimal updates that are waiting for my interaction.

Goodisplay Tinypico ESP32 HAT

Is ready to be tested and results will be posted here soon.

Please follow @martinfasani to stay in touch.

LVGL to design UX interfaces on epaper

lv_port_esp32-epaper is the latest successful attempt to design UX in C using Espressif ESP32.
If you like the idea please hit the ★ in my repository fork.
What is LVGL?

LVGL stands for “Light and Versatile Graphics Library” and allows you to design an object oriented user interface in supported devices. So far it supports mostly TFT screens and only some slow SPI epapers where supported. My idea is to add driver support so it works also in fast parallel epapers.

That is Lilygo EPD47. Parallel epaper with ESP32 WROVER and I2C touch interface that can be found in Aliexpress

The main idea is to use a bridge driver that pushes the pixels to EPDiy component using the set_px_cb and the flush callbacks in order to render the layouts on the supported epapers. This will have a performance hit but it will also allow us to draw UX interfaces in parallel epapers that are quite fast flushing partial refresh.
The development took about one month of research and many iterations until it became usable. I started with an easy choice since Lilygo sent me an parallel epaper as a gift once and I bough the rest in their official store. The idea is that this acts as proof-of-concept to demostrate that is possible and that it’s working as expected. It’s possible to design an UX directly in C and then using a controller like ESP32 you can directly interact with Home appliances such as lights or other devices, to control them or to read information such as sensors that can respond with short JSON messages to inform your epaper control board about temperature or other matters that you choose.

LILYGO EPD47 T5-4.7 inch E-Paper (Link goes to Lilygo official store)
LILYGO T5-4.7 inch E-paper ESP32 V3 version Capacitive touch (IC driver is called L58)

More demos and videos

Recommended reads hits first 100 users

After almost one year on the run, my service to deliver images for epapers and TFT displays finally is starting to get some adoption. The idea was starting at the beginning of 2020 when the epapers and many great projects like EPDiy in hackaday started to be early adopted.

Our ESP32 Firmware does 3 things at the moment and is very easy to set up:

  1. It connects to and downloads a Screen bitmap.
  2. In “Streaming mode” it pushes the pixels to Adafruit GFX buffer and at the end renders it in your Epaper.
  3. It goes to sleep the amount of minutes you define

But then I needed to research more and a bigger idea was triggered: It was not enough to make an Arduino-esp32 firmware using GxEPD as a library. I wanted to learn more how epapers work and also to get out of Arduino-esp32 and get more into Espressif IDF framework. It was hard, I had some weeks where I achieved nothing, but after about one entire month of coding I finally saw the first small epaper refresh.
Soon there where 5 models more.

Today they are at least 20 models, including color ones, and getting back to EPDiy I added also support for parallel epapers being the new LILYGO T5S 960*540 the first fast paralell eink supported. And then come the touch part. First with Goodisplay FocalTech controller and last week with Chinese L58 controller for this new parallel epaper.

It was a long journey and time taking. But I think it was worth it and I see that at least 20% of the users are having their screens connected and enjoying a very low consumption calendars and photo-frames at home.
Very happy to make this possible and to bring something alternative to the usual arduino-esp32 Firmware. Something that you can hack, that is more understandable, and uses Espressif’s own framework. It might be not very well known for makers but is undoubtedly used in professional industry and it’s a very good alternative, with lots of examples and very well documented.

Next missions are to start making developer tools and examples to introduce uGFX interface design into ESP32 using epapers. There is a long journey ahead and we are very thankful for all the good feedback received so far.