summaryrefslogtreecommitdiff
path: root/_drafts/building-an-epaper-badge.md
blob: 8197d2558c9ad153b5cdfd3fc5483b655a017e83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
---
layout: post
title: Building an ePaper badge
date: 2025-08-06 19:53 +0200
lang: en
categories: tech
---

## Foreword

Two weeks before [{% post_url 2025-07-30-awoostria-con-report %}](Awoostria):

> Hey, I should build something for my Tinkering Projects Show And Tell panel!"

So it begins… The story how I build myself an ePaper badge.

Actually, the story begins way earlier, when I still had a physical Raspberry Pi
running stuff in my home network, and I wanted to tinker around a bit, and
bought myself a Waveshare ePaper. These simple black-and-white displays which
maintain their content when the power goes off, which is also inside eBook
readers.

Some years ago I wanted to build myself a doorsign for the EAST convention, and
I wanted to go "as minimal as possible". I wanted to use one of the MSP430
controllers I had laying around, and I wanted to switch motives via MiFare RFID
transponders (using an MFRC5xx reader).  Work on that development never really
took off.

## Requirements

So this time, I simply said "fuck it", and threw an ESP32 on the problem.
Also, I decided to use [PlatformIO](https://platformio.org/), a
toolchain/SDK/library manager. I started with the Arduino framework, which is…
pretty wasteful in terms of resources (Flash/RAM/…), but speeds up development
significantly.

I had a simple ESP32 devboard, and one of the Waveshare modules, and started
coding.

…

But wait, what to I even want to achieve? Well, I wanted to "mood badge", i.e.
show my current mood with funny pictures. I couldn't get one on previous
conventions, so I was just gonna build one myself.

This involves several sub-problems:

* Control the ePaper display
* Get the pictures on the display
* Set what is displayed
* Power-saving
* Attach the badge to myself

## Control the display

Usually, you never talk to the displays themselves, but to a display
controller. Usually, you talk to these via a digital interface, e.g.
SPI. There are different display controllers with different command sets.

But why bother with implementing this myself? There are ready-made libraries.
For myself, I decided to use [GxEPD2](https://github.com/ZinggJM/GxEPD2).
They support *some* Waveshare displays. The problem with Waveshare displays is,
they don't disclose which display controller they use. So it's kind of an
trial-or-error procedure. Or rather, you can look at their example code,
figure out which commands they are using, and compare what commands
GxEPD2 uses. That's a but cumbersome.

## Get the picture on the display

You can't just simply throw a jpeg onto the display.  a) The display doesn't
understand that. It only understands pixel data.  (the library doesn't,
either).  b) The display can only draw black and white pixels.

So, you definitely can't throw a color picture on the display, not a monochrome
one. There are displays which support a few gray-levels, though.

So. What to? The solution is "dithering". I.e. you trick your eye into
perceiving grey by having clusters of black and white pixels. There is some
background to dithering, but I simply used either GIMP, the Floyd-something
algorithm, or one of the "ordered" modes of ImageMagick.

This, then, looks like this:

<img
  src="data:image/jpeg;base64,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"
  alt="a dithered image of my fursona"
/>


TODO: XBM

## How to attach the badge to myself

This would be cumbersome. I had a Waveshare module/PiHat (to heavy), and a
simple "ePaper sheet" - which would be too cumbersome to attach to the
devboard. So, at this point, I decided to switch from the prototyping platform
onto something better.

Fortunately, Elecrow provides a
[CrowPanel](https://www.elecrow.com/crowpanel-esp32-2-9-e-paper-hmi-display-with-128-296-resolution-black-white-color-driven-by-spi-interface.html),
which is exactly what I need. It has a display, a built-in ESP32, a housing,
and even some switches! 

I decided to glue magnets onto the housing, and attach the display
via magnets on the inner side of my shirt - not ideal. I positioned the 
magnets in the (vertical) middle of the housing, so it wobbles and is not 
readable. Also, I accidentally washed the shirt after Awoostria with the magnets
still sticking inside - and now there's a hole in it. :(

## Set what is displayed

In addition to these controls, which allow choosing the motive, I wanted
something "more direct", so I added the
[NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino) library. With a bit
of coding, the available presets/motives could be read via BLE,
and also one could be selected via another characteristic.

Actually, the switch-selection was a but troublesome.
Redrawing the whole display takes around 2 seconds - but that is
not acceptable when navigating the presets one-by-one.
By looking at the API, I found out you can select a "partial region".

What I didn't mention yet, the text that shows the mood is drawn using
the API - not integrated into the picture. So, I simply update a
region in the vertical-center-right of the display with the mood text.
The selection is confirmed my pressing the rotary switch.

This is still not ideal. The first update must be a full-one,
and I don't save the selected preset in NVS - I don't want to destroy
the flash by hundreds/thousands of write cycles. I don't have a solution
to this, yet. Maybe I'm gonna integrate an microSD card (there's a slot for that!).
Gonna research a good wear-levelling file system for that. Probably not FAT. That doesn't
need to be readable on the PC. (And even if, simple stuff can be written in FUSE). 

## Power saving

I first measured the current and was shocked. The whole thing
draws around 80-100 mA. Not a big surprise, given that Arduino
basically calls `loop()` over and over again.

Using a bit of experimenting, and failing to cancel light sleep with
an GPIO interrupt, I  implemented power saving by using a timer-based
light sleep (10 ms, gives good user response) and reducing the CPU frquency to
TODO????? MHz.

And lo and behold, my USB current measuring equipment (resolution 10mA) showed 0 mA. Success.

Actually, reducing the CPU frequency was a requirement! If I didn't do that,
the CPU would constantly crash when entering or exiting light sleep. No idea why!

## Resources

bla on dithering bla.