Most makers treat the Raspberry Pi as a home server, a retro-gaming console, or an IoT gateway. But word processing on Raspberry Pi hardware is a sleeper use case that solves a modern problem: digital distraction. By pairing a lightweight Linux environment with an e-ink display and a custom hardware macro pad, you can build a dedicated, eye-friendly writing terminal that physically cannot browse the web or check social media.
This guide walks through building an e-ink typewriter terminal targeting the Raspberry Pi 5 (4GB variant). We will wire a SPI e-ink panel for the visual output and an I2C keypad to inject formatting macros directly into your word processor. As of 2026, the shift to Pi OS Bookworm and the lgpio backend means older GPIO libraries will fail; this build uses modern, stable I2C polling to ensure forward compatibility.
Choosing the Right Word Processing on Raspberry Pi Software
Before wiring a single pin, you need to select the software that will render your text. The Pi 5 has more than enough horsepower for any office suite, but for a dedicated writing terminal, resource efficiency and distraction-free UI are paramount. Below is a benchmark comparison of the top ARM64-native word processors running on a Pi 5 (4GB) under Wayland/X11.
| Software | Idle RAM (Pi 5) | Cold Load Time | ARM64 Native | Best Use Case |
|---|---|---|---|---|
| LibreOffice Writer | ~380 MB | 2.8s | Yes | Heavy formatting, .docx compatibility |
| AbiWord | ~85 MB | 0.9s | Yes | Low-resource environments, basic RTF |
| FocusWriter | ~110 MB | 1.2s | Yes | Distraction-free, full-screen drafting |
| Calligra Words | ~210 MB | 2.1s | Yes | KDE integration, vector graphics |
Parts List and Hardware Pin Mapping
This project bridges SPI (for the high-bandwidth display) and I2C (for the low-bandwidth input). Here is the exact bill of materials and the physical pin mapping.
Parts List:
- Compute: Raspberry Pi 5 (4GB) with active cooler (~$60)
- Display: Waveshare 7.5" E-Ink Display HAT (V2, 800x480, Black/White) (~$45)
- Input: PCF8574 I2C Keypad Breakout Board with 3x Cherry MX Brown switches (~$12)
- Wiring: Female-to-female jumper wires, 2x 4.7kΩ pull-up resistors (if breakout lacks them)
| Component | Protocol | Pi 5 GPIO / Pin | Function |
|---|---|---|---|
| E-Ink HAT | SPI0 | GPIO 10 (Pin 19) | MOSI (Data In) |
| E-Ink HAT | SPI0 | GPIO 11 (Pin 23) | SCLK (Clock) |
| E-Ink HAT | SPI0 | GPIO 8 (Pin 24) | CE0 (Chip Select) |
| E-Ink HAT | GPIO | GPIO 25 (Pin 22) | DC (Data/Command) |
| E-Ink HAT | GPIO | GPIO 17 (Pin 11) | RST (Reset) |
| E-Ink HAT | GPIO | GPIO 24 (Pin 18) | BUSY (Status) |
| PCF8574 Keypad | I2C1 | GPIO 2 (Pin 3) | SDA (Data) |
| PCF8574 Keypad | I2C1 | GPIO 3 (Pin 5) | SCL (Clock) |
| PCF8574 Keypad | Power | Pin 1 / Pin 6 | 3.3V VCC / GND |
Step-by-Step Assembly and OS Configuration
Follow these steps to prepare the Pi 5 environment. Note that Pi 5 defaults to I2C bus 1, but the baudrate sometimes needs manual adjustment for longer wire runs.
- Flash the OS: Use Raspberry Pi Imager to flash Raspberry Pi OS (64-bit, Bookworm) to a high-endurance microSD card or NVMe SSD. Set your username and enable SSH.
- Enable Interfaces: Boot the Pi, open a terminal, and run
sudo raspi-config. Navigate to Interface Options and enable both I2C and SPI. Reboot. - Verify I2C Bus: After reboot, run
i2cdetect -y 1. You should see your PCF8574 keypad at address0x20(or0x38depending on the breakout's jumper pads). - Install Dependencies: Install the Python I2C library and the keystroke injection tool:
sudo apt update sudo apt install python3-smbus2 python3-pynput xdotool pip3 install --break-system-packages pillow - Physical Assembly: Stack the Waveshare E-Ink HAT directly onto the Pi 5 GPIO header. Wire the PCF8574 breakout to the designated I2C pins using short (under 10cm) jumper wires to avoid capacitance issues.
Python Macro Controller Code
The following Python script targets the Raspberry Pi 5 (Bookworm). It polls the I2C PCF8574 chip for button presses and uses pynput to inject OS-level keystrokes into your active word processor. This avoids the deprecated RPi.GPIO library entirely, relying on the stable smbus2 package.
#!/usr/bin/env python3
"""
Raspberry Pi E-Ink Word Processor Macro Controller
Target Board: Raspberry Pi 5 (4GB) / Pi OS Bookworm
Hardware: PCF8574 I2C Keypad (Address 0x20)
"""
import time
import subprocess
from smbus2 import SMBus
from pynput.keyboard import Controller, Key
# --- PIN & BUS DEFINITIONS ---
I2C_BUS = 1
KEYPAD_ADDR = 0x20 # Verify with `i2cdetect -y 1`
# Button masks (active LOW on PCF8574)
# Assuming buttons are wired to P0, P1, P2
BTN_SAVE = 0xFE # 1111 1110
BTN_BOLD = 0xFD # 1111 1101
BTN_EXPORT = 0xFB # 1111 1011
keyboard = Controller()
def send_macro(action):
"""Injects keystrokes into the active word processing window."""
if action == 'save':
keyboard.press(Key.ctrl_l)
keyboard.press('s')
keyboard.release('s')
keyboard.release(Key.ctrl_l)
print('[Macro] Saved Document')
elif action == 'bold':
keyboard.press(Key.ctrl_l)
keyboard.press('b')
keyboard.release('b')
keyboard.release(Key.ctrl_l)
print('[Macro] Toggled Bold')
elif action == 'export':
# Uses xdotool for complex menu navigation if needed
subprocess.run(['xdotool', 'key', 'ctrl+shift+e'])
print('[Macro] Triggered Export')
def main():
print('Starting Macro Controller... Press Ctrl+C to exit.')
try:
with SMBus(I2C_BUS) as bus:
# Initialize PCF8574 pins as inputs (write 0xFF)
bus.write_byte(KEYPAD_ADDR, 0xFF)
while True:
try:
# Read current pin states
state = bus.read_byte(KEYPAD_ADDR)
if state == BTN_SAVE:
send_macro('save')
time.sleep(0.3) # Debounce
elif state == BTN_BOLD:
send_macro('bold')
time.sleep(0.3)
elif state == BTN_EXPORT:
send_macro('export')
time.sleep(0.3)
time.sleep(0.05) # Polling rate 20Hz
except OSError as e:
if e.errno == 121:
print('CRITICAL: I2C Remote I/O Error. Check wiring.')
time.sleep(2) # Prevent log spam
else:
raise e
except KeyboardInterrupt:
print('\nController stopped by user.')
except Exception as e:
print(f'Unexpected fatal error: {e}')
if __name__ == '__main__':
main()
Debugging: Fixing the I2C Remote I/O Error
When working with I2C on the Pi 5, the most common failure mode during initial boot is the script crashing immediately upon trying to read the keypad.
The Exact Error String:
OSError: [Errno 121] Remote I/O error
This error means the Pi's I2C controller sent a clock signal, but the PCF8574 chip did not acknowledge (ACK) it on the SDA line. Here are the ranked causes and fixes:
- Missing Pull-Up Resistors: The I2C protocol requires pull-up resistors on SDA and SCL. While the Pi has internal 1.8kΩ pull-ups, they are often too weak for the PCF8574 if your wires are longer than 5cm. Fix: Solder 4.7kΩ resistors between SDA/VCC and SCL/VCC on your breakout board.
- Address Mismatch: The PCF8574 comes in two variants: PCF8574 (base address 0x20) and PCF8574A (base address 0x38). Fix: Run
i2cdetect -y 1and update theKEYPAD_ADDRvariable in the Python script to match the hex value shown in the grid. - Logic Level Clash: The Pi 5 GPIO operates strictly at 3.3V. If you accidentally wired the PCF8574 VCC to the 5V pin (Pin 2), the chip will output 5V on the SDA line, which can back-feed the Pi and cause the I2C bus to lock up. Fix: Ensure VCC is wired to Pin 1 (3.3V).
- Run
i2cdetect -y 1. If the grid is empty, your hardware wiring or pull-ups are wrong. - Swap the SDA and SCL wires. They are easily reversed on custom breakouts, and the Pi will silently fail to handshake.
- Verify the word processor window is actually in focus.
pynputinjects keystrokes blindly; if the terminal is focused, you will just see 's' and 'b' printing in the console instead of saving or bolding text.
Extending and Simplifying the Build
Once the base macro pad and software stack are stable, you can adapt the hardware to fit your specific writing workflow.
How to Simplify:
If the Waveshare e-ink refresh rate (which takes ~2 seconds for a full screen clear) is too slow for your typing speed, drop the e-ink HAT entirely. Use a standard HDMI monitor and rely purely on the I2C macro pad. This cuts the build cost by $45 and removes the SPI configuration overhead, leaving you with a pure hardware macro injector that works with any Linux desktop environment.
How to Extend:
To turn this into a portable field terminal, swap the Pi 5 for a Raspberry Pi Zero 2 W. The Zero 2 W shares the same ARM architecture and runs the exact same Python code without modification. Pair it with a 4.2" Waveshare e-ink module and a 5000mAh LiPo UPS HAT. You will need to add a USB OTG hub to connect your standard USB keyboard, but the result is a distraction-free word processing on Raspberry Pi setup that runs for 12+ hours on a single charge.
For advanced makers, replace the 3-button PCF8574 pad with a rotary encoder (using the gpiozero library) mapped to scroll through document history, or integrate a real-time clock (RTC) module to automatically timestamp your daily word-count logs to a local SQLite database.






