EXPERIMENTAL E-READER

24 OCTOBER 2023

This project features an experimental e-reader powered by an ESP-WROOM-32 development board and a 7.5-inch Waveshare e-paper display built with the intention of learning about e-paper displays.

Introduction

The prototype e-reader comprises an ESP32 microcontroller, an e-paper display HAT, and three buttons: yellow, blue, and white for turning the page backwards, forwards, and putting the device to sleep, respectively. The prototype does not store books on the microcontroller. It streams books from a server over HTTP. The e-reader employs RTC memory to record the reading progress between sessions.

The most formidable challenge when trying to build an e-reader with an ESP32 is its limited memory and storage. My ESP-WROOM-32 has a total of 512KB of SRAM and 4MB of flash memory, which the freeRTOS, ESP-IDF, and the e-reader application must share. To put things into perspective, a Kindle Paperwhite has at least 256MB of memory and 8GB of storage. That is 500x more memory than what I’d have to work with.

Despite its size, as microcontrollers go, ESP32 is a powerful system-on-a-chip with a 160MHz dual-core processor and integrated WiFi. So, I thought it’d be amusing to embrace the constraints and build my e-reader using a $5 MCU and the power of C programming.

The file format

The file format dictates the complexity of the embedded software. So, I’ll begin there. The e-reader works by downloading and rendering a rasterized monochrome image of a page (a .ebm file).

The EBM file contains a series of bitmaps, one for each page of the book. The dimensions of each bitmap are equal to the size of the display. Each byte of the bitmap encodes information for rendering eight pixels. For my display, which has a resolution of 480x800, the bitmaps are laid out along 48KB boundaries. This simple file format lends well to HTTP streaming, which is its main advantage, as we will soon see.

The pdftoebm.py script enclosed in the tarball at the end of the page converts PDF documents to EBM files.

How does it work?

As the e-reader has no storage, it can’t store books locally. Instead, it downloads pages of the EBM file over HTTP from the location pointed to by the EBM_ARCH_URL setting in the Kconfig.projbuild file on demand. To read a different book, we have to replace the old file with the new one or change the EBM_ARCH_URL value. The latter requires us to recompile the embedded software.

Upon powering up, the e-reader checks the reading progress stored in the RTC memory. It then downloads three pages (current, previous, and next) to a circular buffer in DMA-capable memory. When the user turns a page by pressing a button, one of the microprocessor’s two cores transfers it from the buffer to the display over a Serial Peripheral Interface (SPI). The other downloads a new page in the background. I used the ESP-IDF task API to schedule the two tasks on different cores of the multicore processor to make the reader more responsive.

I designed the EBM format with HTTP streaming in mind. Since the pages are laid out in the EBM file along predictable boundaries, the e-reader can request pages by specifying the offset and the chunk size in the HTTP Range header. Any web server will process this request without custom logic.

Epilogue

My fascination with e-paper began back in 2017, when I was tasked with installing a few displays in a car park. Having no idea how they worked, I remember watching the languid screens refresh like a Muggle witnessing magic. This project was born out of that enduring curiosity and love of e-paper technology.

Why did I go to the trouble of building a rudimentary e-reader when I could easily buy a more capable commercial e-reader? First of all, it’s to prove to myself that I can. More importantly, there’s a quiet satisfaction to reading on hardware you built yourself. You are no longer the powerless observer watching the magic happen from the sidelines. You become the wizard who makes the invisible particles swirl into form by whispering C to them. There’s only one way to experience that.

Files: source.tar.gz