Files
eink-dairy/DISPLAY_REFRESH.md
2025-12-09 11:18:44 -05:00

3.2 KiB

Display Refresh Mechanism

This document explains the dual-core architecture used to handle USB keyboard input and e-Paper display updates efficiently on the Raspberry Pi Pico.

Architecture Overview

The system utilizes both cores of the RP2040 to ensure that the slow refresh rate of the e-Paper display does not block or lag the USB keyboard input.

Core 0: Input Handling (Producer)

  • Role: Handles USB Host tasks, processes keyboard reports, and manages the text buffer.
  • Behavior:
    1. Receives key presses via TinyUSB callbacks.
    2. Updates the local text buffer (g_entry_list).
    3. Triggers a display update via send_display_update().
  • Non-Blocking Transmission:
    • When an update is needed, Core 0 allocates a DisplayMessage on the heap.
    • It attempts to push the message pointer to the Multicore FIFO.
    • Critical Optimization: It uses multicore_fifo_wready() to check if the FIFO has space.
      • If Ready: Pushes the message.
      • If Full: Immediately frees the message and skips the update. This ensures Core 0 never waits for Core 1, keeping typing responsive.

Core 1: Display Driver (Consumer)

  • Role: Manages the e-Paper hardware and performs the actual drawing operations.
  • Behavior:
    1. Initializes the e-Paper display.
    2. Waits for messages in the Multicore FIFO.
  • Smart Refresh (Accumulation):
    • When Core 1 wakes up to process a message, it first checks if more messages have arrived while it was sleeping or busy.
    • FIFO Draining: It loops through the FIFO, popping and freeing all intermediate messages, keeping only the latest one.
    • This ensures that if the user types "Hello World" quickly, Core 1 might skip rendering "Hello " and jump straight to rendering "Hello World", preventing a queue of obsolete updates from slowing down the display.

Data Flow Diagram

sequenceDiagram
    participant User
    participant Core0 as Core 0 (USB/Input)
    participant FIFO as Multicore FIFO
    participant Core1 as Core 1 (Display)

    User->>Core0: Types 'A'
    Core0->>FIFO: Push Msg('A')
    
    User->>Core0: Types 'B'
    Core0->>FIFO: Push Msg('AB')
    
    Note over Core1: Busy refreshing...
    
    User->>Core0: Types 'C'
    alt FIFO is Full
        Core0->>Core0: Drop Msg('ABC') (Free memory)
    else FIFO has space
        Core0->>FIFO: Push Msg('ABC')
    end

    Core1->>FIFO: Pop Msg('A')
    Note over Core1: Checks FIFO for newer msgs
    FIFO->>Core1: Msg('AB') exists
    Core1->>Core1: Free Msg('A'), use Msg('AB')
    
    FIFO->>Core1: Msg('ABC') exists
    Core1->>Core1: Free Msg('AB'), use Msg('ABC')
    
    Core1->>Display: Render('ABC')

Key Functions

  • send_display_update(const char *entry, bool finish_line):
    • Allocates memory.
    • Checks FIFO status.
    • Pushes or drops message.
  • core1_display_init():
    • Main loop for Core 1.
    • Drains FIFO to find the latest message.
    • Calls e-Paper drawing functions.

Memory Management

  • Messages are malloc'd by Core 0.
  • Messages are free'd by Core 1 (after processing or dropping).
  • If Core 0 drops a message because the FIFO is full, it frees it immediately.