diff --git a/DISPLAY_REFRESH.md b/DISPLAY_REFRESH.md new file mode 100644 index 0000000..ea03ec6 --- /dev/null +++ b/DISPLAY_REFRESH.md @@ -0,0 +1,84 @@ +# 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 + +```mermaid +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 `free`s it immediately. diff --git a/hello_usb.cpp b/hello_usb.cpp index 0103bc8..138beb2 100644 --- a/hello_usb.cpp +++ b/hello_usb.cpp @@ -144,14 +144,20 @@ void send_display_update(const char *entry, bool finish_line) { if (g_force_full_refresh) { printf("[Core 0] Forcing full refresh this update\n"); g_force_full_refresh = false; // Reset flag after setting it in message + + // Full text area refresh + msg->xstart = 0; + msg->ystart = 50; // Start below the header + msg->xend = 800; // Full width + msg->yend = 480; // Full height from header onwards + } else { + // Partial refresh of ONLY the current line + msg->xstart = 0; + msg->ystart = 50 + (g_entry_list.count * 25); + msg->xend = 800; + msg->yend = msg->ystart + 25; } - // Setup partial refresh region (text area at top of display) - msg->xstart = 0; - msg->ystart = 50; // Start below the header - msg->xend = 800; // Full width - msg->yend = 480; // Full height from header onwards - // Send message pointer to core 1 if FIFO has space if (multicore_fifo_wready()) { multicore_fifo_push_blocking((uint32_t)msg); @@ -207,11 +213,15 @@ void core1_display_init() { Paint_SelectImage(g_epd_image); Paint_Clear(WHITE); + + // Calculate offset for partial refresh + UBYTE *image_ptr = g_epd_image + (msg->ystart * (EPD_7IN5B_V2_WIDTH / 8)); + if(!msg->use_partial){ // for loop 5 times display white partial int i = 0; for(i = 0; i < 1; i++){ - EPD_7IN5B_V2_Display_Partial(g_epd_image, msg->xstart, msg->ystart, msg->xend, msg->yend); + EPD_7IN5B_V2_Display_Partial(image_ptr, msg->xstart, msg->ystart, msg->xend, msg->yend); } } @@ -221,7 +231,7 @@ void core1_display_init() { int start_index = msg->entries.count > 10 ? msg->entries.count - 10 : 0; for (int i = start_index; i < msg->entries.count; i++) { if (y_pos + 25 < 480) { //Don't draw beyond screen - Paint_DrawString_EN(20, i*25, msg->entries.entries[i], &Font16, WHITE, BLACK); + Paint_DrawString_EN(20, 50 + i*25, msg->entries.entries[i], &Font16, WHITE, BLACK); y_pos += 25; // Space between entries } else { printf("Skipping entry to avoid overflow\n"); @@ -229,7 +239,7 @@ void core1_display_init() { } // Use partial or full refresh printf("[Core 1] Using partial refresh\n"); - EPD_7IN5B_V2_Display_Partial(g_epd_image, msg->xstart, msg->ystart, msg->xend, msg->yend); + EPD_7IN5B_V2_Display_Partial(image_ptr, msg->xstart, msg->ystart, msg->xend, msg->yend); } // Free the message (it was allocated by core 0) @@ -418,10 +428,8 @@ static void process_kbd_report(hid_keyboard_report_t const *report) { // Update OLED if (g_display_manager) g_display_manager->refresh(g_input_buffer, g_last_echo); - // Update e-Paper ONLY if space (per user request) - if (ch == ' ') { - send_display_update(g_input_buffer, false); - } + // Update e-Paper on every keystroke + send_display_update(g_input_buffer, false); } } }