---
title: 512 KB prototype e-reader
date: 2023-10-24
layout: post
project: true
thumbnail: thumb_sm.png
---
Been dabbling in microcontrollers—mostly Arduino Uno/ATmega328P. Math major, no
formal electronics training. This, however, is an ESP-32 project—first
resembling something practical.
ESP-WROOM-32, 7.5" Waveshare e-paper display, three-button interface
(prev/next/sleep).
Memory: 512 KB SRAM + 4 MB flash. Internal flash unsuitable for storing books
due to P/E cycle limit. Used HTTP Range requests to stream them on-demand.
Progress saved to RTC memory to survive deep sleep without flash wear.
PDFs are rasterized and stored as sequences of bitmaps on a server. 1 byte = 8
pixels, 1 page = 48 KB (display resolution), headerless. Optimized for Range
requests without server-side logic:
```
int r0 = ((page_n - 1) * PAGE_SIZE);
int rn = page_n * PAGE_SIZE - 1;
int n = snprintf(NULL, 0, "bytes=%d-%d", r0, rn) + 1;
char *buf = malloc(sizeof(char) * n);
snprintf(buf, n, "bytes=%d-%d", r0, rn);
esp_http_client_set_header(http_client, "Range", buf);
esp_http_client_perform(http_client);
```
Three pages (prev/current/next) stored in a circular buffer—max possible. Upon
request (via GPIO interrupts), application cycles buffer, updates screen,
prefetches next page.
```
c_page_num++;
pg.page_num = c_page_num + 2;
pg.page_buf = pages[(c_page_num + 1) % PAGE_LEN];
xSemaphoreGive(mutex);
xQueueSend(http_evt_queue, &pg, portMAX_DELAY);
epd_draw_async(pages[c_page_num % PAGE_LEN], PAGE_SIZE);
epd_draw_await();
```
System isn't as responsive as I'd hoped. Scheduling GPIO, SPI, and HTTP tasks
on a single thread causes input lag. Pinned GPIO/SPI tasks to one core and the
HTTP task to the other.
Better, but screen updates block user input.
Moved SPI buffers to DMA and made transfers async. Few more cycles saved.
Can't think of anything else.
Verdict: Functional but limited. Led to [Etlas](../etlas/).
Commit: 7f691c4.