--- title: ESP32 e-reader prototype date: 2023-10-24 layout: post project: true thumbnail: thumb_sm.png --- First project with e-paper displays and ESP32. System: ESP-WROOM-32, 7.5" Waveshare e-paper display, three buttons (prev/next/sleep). 2023-09-23: 512KB SRAM, 4MB flash (shared with FreeRTOS and ESP-IDF). Not enough storage for books. Using ESP32's built-in WiFi to stream them over HTTP. Recording the reading progress in RTC memory. Rasterized pages encoded as tightly packed bitmaps (1 byte => 8 pixels), no headers, arranged along 48 KB (480x800) boundaries; Reader can stream pages using HTTP Range requests with zero server-side logic. Keeps both ends lean. Page table stores 3 pages (prev/current/next) in a circular buffer. When the user requests a page, program cycles through the table, updates the screen, and downloads the next page. Responsiveness is inadequate. Scheduling GPIO (user input), SPI, and HTTP on one core causes input lag. Pinned the GPIO and SPI tasks to one core, the HTTP task to the other core. Better, but screen updates are blocking user input; Made SPI transfer async: ``` void epd_draw_async(const uint8_t *buf, size_t n) { static spi_transaction_t t[3]; memset(&t[0], 0, sizeof(t[0])); t[0].length = 8; t[0].tx_data[0] = 0x13; t[0].user = (void*) 0; t[0].flags = SPI_TRANS_USE_TXDATA; memset(&t[1], 0, sizeof(t[1])); t[1].length = 8 * n; t[1].tx_buffer = buf; t[1].user = (void*) 1; memset(&t[2], 0, sizeof(t[2])); t[2].length = 8; t[2].tx_data[0] = 0x12; t[2].user = (void*) 0; t[2].flags = SPI_TRANS_USE_TXDATA; for (int i = 0; i < 3; i++) spi_device_queue_trans(spi, &t[i], portMAX_DELAY); } ``` Much better. 2023-10-06: Moved the page table to DMA-capable memory; Reclaimed a few more CPU cycles from the SPI transfers. Can't think of anything else. Verdict: Works but limited. Led to [Etlas](../etlas/). Commit: [7f691c4](https://git.asciimx.com/esp32-e-reader/commit/?id=7f691c46093933b67aab466c0ca582ace8ab73d4)