From f197b9c1f42dbb45fa486f5a3df0a87a9d176aee Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Wed, 10 Dec 2025 13:38:04 -0500 Subject: [PATCH] fix wifi & flash + eink screen on core 1, by using queue --- CMakeLists.txt | 2 +- epaper_manager.cpp | 52 ++++++++++++++++++++++++++++++++-------------- hello_usb.cpp | 24 ++++++++++----------- wifi_manager.cpp | 35 +++++++++++++++++++++++++------ wifi_manager.h | 3 ++- 5 files changed, 80 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aaf8579..acd0ea6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ if (TARGET tinyusb_host) ) # pull in common dependencies - target_link_libraries(hello_usb pico_stdlib pico_ssd1306 hardware_i2c Config ePaper GUI Fonts hardware_spi pico_multicore tinyusb_host tinyusb_board pico_cyw43_arch_lwip_threadsafe_background) + target_link_libraries(hello_usb pico_stdlib pico_ssd1306 hardware_i2c Config ePaper GUI Fonts hardware_spi pico_multicore pico_flash tinyusb_host tinyusb_board pico_cyw43_arch_lwip_threadsafe_background) # enable usb output, disable uart output pico_enable_stdio_usb(hello_usb 0) diff --git a/epaper_manager.cpp b/epaper_manager.cpp index 1ca52f3..037508e 100644 --- a/epaper_manager.cpp +++ b/epaper_manager.cpp @@ -2,6 +2,8 @@ #include "wifi_manager.h" #include "pico/stdlib.h" #include "pico/multicore.h" +#include "pico/flash.h" +#include "pico/util/queue.h" #include #include #include @@ -31,6 +33,10 @@ static bool g_force_full_refresh = false; // Flag to force full refresh when li // Synchronization flag for multicore initialization static volatile bool g_display_ready = false; +// Queue for display messages (replacing raw FIFO to avoid conflict with flash_safe_execute) +static queue_t g_display_queue; +#define QUEUE_LENGTH 8 + // Display update message structure for inter-core communication typedef struct { EntryList entries; @@ -84,9 +90,18 @@ static void init_epaper_display() { EPD_7IN5B_V2_Display_Partial(g_epd_image, 0, 0, EPD_7IN5B_V2_WIDTH, EPD_7IN5B_V2_HEIGHT); EPD_7IN5B_V2_Display_Partial(g_epd_image, 0, 0, EPD_7IN5B_V2_WIDTH, EPD_7IN5B_V2_HEIGHT); + printf("Trying to connect to wifi\r\n"); + bool connected = wifi_try_auto_connect(); + + Paint_SelectImage(g_epd_red); printf("Drawing header\r\n"); - Paint_DrawString_EN(10, 10, "What's new today:", &Font24, WHITE, RED); + if (connected) { + Paint_DrawString_EN(10, 10, "What's new today: ...", &Font24, WHITE, RED); + } else { + Paint_DrawString_EN(10, 10, "What's new today:", &Font24, WHITE, RED); + } + // Display the image with both black and red buffers EPD_7IN5B_V2_Display_Partial(g_epd_red, 0, 0, EPD_7IN5B_V2_WIDTH, EPD_7IN5B_V2_HEIGHT); @@ -98,6 +113,9 @@ static void init_epaper_display() { * Core 1 function: Runs display initialization and update handling */ static void core1_display_init() { + // Initialize flash safe execute support for this core + flash_safe_execute_core_init(); + // Initialize WiFi on Core 1 so IRQs are handled here wifi_init(); @@ -109,20 +127,18 @@ static void core1_display_init() { // Initialize for partial refresh on second call EPD_7IN5B_V2_Init_Part(); - // Core 1 main loop: handle display updates via FIFO + // Core 1 main loop: handle display updates via Queue while (true) { - // Check if there's a message from core 0 - if (multicore_fifo_rvalid()) { - // Read the message pointer - uint32_t msg_addr = multicore_fifo_pop_blocking(); - DisplayMessage *msg = (DisplayMessage *)msg_addr; - - // Drain FIFO to get the latest message - while (multicore_fifo_rvalid()) { + DisplayMessage *msg; + // Check if there's a message in the queue + if (queue_try_remove(&g_display_queue, &msg)) { + + // Drain Queue to get the latest message + DisplayMessage *next_msg; + while (queue_try_remove(&g_display_queue, &next_msg)) { printf("[Core 1] Skipping intermediate update\n"); free(msg); // Free the stale message - msg_addr = multicore_fifo_pop_blocking(); - msg = (DisplayMessage *)msg_addr; + msg = next_msg; } printf("[Core 1] Updating display with %d entries\n", msg->entries.count); @@ -173,12 +189,16 @@ static void core1_display_init() { } void epaper_start_background_thread() { + // Initialize the queue before starting the thread + queue_init(&g_display_queue, sizeof(DisplayMessage*), QUEUE_LENGTH); + printf("Launching e-Paper display init on core 1...\n"); multicore_launch_core1(core1_display_init); } void epaper_send_update(const char *entry, bool finish_line) { if (!g_display_ready) return; // Don't send if display isn't ready + // printf("[Core 0] Preparing display update: '%s' (finish_line=%d)\n", entry, finish_line); // Check if list is at capacity if (g_entry_list.count >= MAX_ENTRIES) { @@ -224,11 +244,11 @@ void epaper_send_update(const char *entry, bool finish_line) { msg->yend = msg->ystart + 25; } - // Send message pointer to core 1 if FIFO has space - if (multicore_fifo_wready()) { - multicore_fifo_push_blocking((uint32_t)msg); + // Send message pointer to core 1 via Queue + if (queue_try_add(&g_display_queue, &msg)) { + // printf("[Core 0] Display update sent to core 1\n"); } else { - printf("[Core 0] FIFO full, skipping display update\n"); + printf("[Core 0] Queue full, skipping display update\n"); free(msg); } diff --git a/hello_usb.cpp b/hello_usb.cpp index 8233623..1cd4893 100644 --- a/hello_usb.cpp +++ b/hello_usb.cpp @@ -58,7 +58,7 @@ static bool execute_command(CommandAction action, const char* input) { if (parsed < 2) { printf("Usage: /connect \n"); if (g_display_manager) g_display_manager->refresh("Usage: /connect ", nullptr); - // epaper_send_update("Usage: /connect ", true); + epaper_send_update("Usage: /connect ", true); return true; } @@ -67,11 +67,18 @@ static bool execute_command(CommandAction action, const char* input) { if (wifi_connect(ssid, password)) { if (g_display_manager) g_display_manager->refresh("Connected!", ssid); - // epaper_send_update("Connected!", true); - // wifi_save_credentials(ssid, password); + int rc = wifi_save_credentials(ssid, password); + if (rc != 0) { + char err_msg[32]; + snprintf(err_msg, sizeof(err_msg), "Flash Error: %d", rc); + if (g_display_manager) g_display_manager->refresh(err_msg, nullptr); + epaper_send_update(err_msg, true); + } else { + epaper_send_update("Connected!", true); + } } else { if (g_display_manager) g_display_manager->refresh("Connection Failed", nullptr); - // epaper_send_update("Connection Failed", true); + epaper_send_update("Connection Failed", true); } return true; } @@ -219,20 +226,13 @@ int main() { sleep_ms(3000); // Give time for power to settle and serial to connect printf("System Booting...\n"); - // Launch display initialization on core 1 + // Launch display initialization on core 1, WIFI and Flash safe execute epaper_start_background_thread(); DisplayManager display; display.init(); g_display_manager = &display; - if (wifi_try_auto_connect()) { - display.refresh("WiFi Auto-Connected", nullptr); - epaper_send_update("WiFi Auto-Connected", true); - } else { - display.refresh("Waiting for Keyboard", nullptr); - } - printf("Initializing TinyUSB Host...\n"); tuh_init(BOARD_TUH_RHPORT); printf("TinyUSB Host Initialized.\n"); diff --git a/wifi_manager.cpp b/wifi_manager.cpp index 6fb60e5..68f70dc 100644 --- a/wifi_manager.cpp +++ b/wifi_manager.cpp @@ -1,5 +1,7 @@ #include "wifi_manager.h" #include "pico/cyw43_arch.h" +#include "pico/multicore.h" +#include "pico/flash.h" #include "hardware/flash.h" #include "hardware/sync.h" #include @@ -60,7 +62,20 @@ void wifi_scan() { } } -void wifi_save_credentials(const char* ssid, const char* password) { +// Helper struct for flash operations +struct FlashWriteParams { + const uint8_t* data; + size_t size; +}; + +// Actual flash operation to be executed safely +static void do_flash_write(void *param) { + FlashWriteParams *p = (FlashWriteParams*)param; + flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE); + flash_range_program(FLASH_TARGET_OFFSET, p->data, p->size); +} + +int wifi_save_credentials(const char* ssid, const char* password) { WifiCreds creds; creds.magic = WIFI_CREDS_MAGIC; strncpy(creds.ssid, ssid, sizeof(creds.ssid) - 1); @@ -68,17 +83,25 @@ void wifi_save_credentials(const char* ssid, const char* password) { strncpy(creds.password, password, sizeof(creds.password) - 1); creds.password[sizeof(creds.password) - 1] = '\0'; - uint32_t ints = save_and_disable_interrupts(); - flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE); - flash_range_program(FLASH_TARGET_OFFSET, (const uint8_t*)&creds, sizeof(creds)); - restore_interrupts(ints); + FlashWriteParams params = { (const uint8_t*)&creds, sizeof(creds) }; + int rc = flash_safe_execute(do_flash_write, ¶ms, 1000); - printf("WiFi credentials saved to flash.\n"); + if (rc == PICO_OK) { + printf("WiFi credentials saved to flash.\n"); + } else { + printf("Failed to save WiFi credentials: %d\n", rc); + } + return rc; } bool wifi_try_auto_connect() { + // On RP2040/RP2350, flash is memory-mapped at XIP_BASE (0x10000000). + // We can read from it directly like a normal pointer without special API calls. + // The hardware XIP controller handles fetching data from the flash chip. const WifiCreds* creds = (const WifiCreds*)(XIP_BASE + FLASH_TARGET_OFFSET); + // Check for the magic number to verify valid data exists. + // Erased flash reads as 0xFFFFFFFF, so this check fails if no data was saved. if (creds->magic != WIFI_CREDS_MAGIC) { printf("No saved WiFi credentials found.\n"); return false; diff --git a/wifi_manager.h b/wifi_manager.h index 625a1fe..7c3ee13 100644 --- a/wifi_manager.h +++ b/wifi_manager.h @@ -22,8 +22,9 @@ bool wifi_connect(const char* ssid, const char* password); /** * Saves the WiFi credentials to flash memory for auto-connect. + * Returns 0 (PICO_OK) on success, or an error code on failure. */ -void wifi_save_credentials(const char* ssid, const char* password); +int wifi_save_credentials(const char* ssid, const char* password); /** * Attempts to connect using saved credentials.