--- title: Prototype e-reader date: 2023-10-24 thumbnail: thumb.png layout: post --- This project features a prototype e-reader powered by an ESP-WROOM-32 development board and a 7.5-inch Waveshare e-paper display. ## Overview In 2017, I was tasked with installing some e-paper displays in a car park. Not knowing how they worked, I remember marveling at their sight like a Muggle witnessing magic. As someone who enjoys reading, I found e-paper to be a true innovation. This project was born out of that enduring curiosity and love of e-paper technology. The prototype, while far from ready for daily use, has some nifty features that fellow hobbyists and tinkerers may find interesting. The reader can display books of arbitrary sizes by streaming them over HTTP. It employs sleep modes to minimize power consumption when not in use and records the reading progress in the chip's RTC memory. The most formidable challenge when trying to build an e-reader with an ESP32 board is its limited memory and storage. My ESP-WROOM-32 board has 512 KB of SRAM and 4 MB 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 256 MB of memory and 8 GB of storage. Despite its size, as microcontrollers go, ESP32 is a powerful system-on-a-chip with a 160 MHz 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 48 KB 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, I first have to upload the EBM file I want to read to a web server. The `EBM_ARCH_URL` setting in the Kconfig.projbuild file points to the URL of the file. To read a different book, I create an EBM file with the same name and upload it to the original location. That way, I don't have to modify the `EBM_ARCH_URL` value, which requires recompiling 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, 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 use the ESP-IDF task API to distribute the two tasks between the available cores for maximum parallelism. 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. ## Reflections It's been six years since the car park and the displays. I began this project hoping to learn the low-level workings of e-paper displays. As a bonus, it led me to explore some of ESP32's most fascinating features: sleep modes, multicore processing, DMA, and RTC memory. Embedded systems are magical things: invisible particles swirl into form as the programmer whispers C. Files: [source.tar.gz](source.tar.gz)