fix wifi & flash + eink screen on core 1, by using queue
This commit is contained in:
@@ -62,7 +62,7 @@ if (TARGET tinyusb_host)
|
|||||||
)
|
)
|
||||||
|
|
||||||
# pull in common dependencies
|
# 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
|
# enable usb output, disable uart output
|
||||||
pico_enable_stdio_usb(hello_usb 0)
|
pico_enable_stdio_usb(hello_usb 0)
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#include "wifi_manager.h"
|
#include "wifi_manager.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
|
#include "pico/flash.h"
|
||||||
|
#include "pico/util/queue.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -31,6 +33,10 @@ static bool g_force_full_refresh = false; // Flag to force full refresh when li
|
|||||||
// Synchronization flag for multicore initialization
|
// Synchronization flag for multicore initialization
|
||||||
static volatile bool g_display_ready = false;
|
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
|
// Display update message structure for inter-core communication
|
||||||
typedef struct {
|
typedef struct {
|
||||||
EntryList entries;
|
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);
|
||||||
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);
|
Paint_SelectImage(g_epd_red);
|
||||||
printf("Drawing header\r\n");
|
printf("Drawing header\r\n");
|
||||||
|
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);
|
Paint_DrawString_EN(10, 10, "What's new today:", &Font24, WHITE, RED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Display the image with both black and red buffers
|
// 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);
|
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
|
* Core 1 function: Runs display initialization and update handling
|
||||||
*/
|
*/
|
||||||
static void core1_display_init() {
|
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
|
// Initialize WiFi on Core 1 so IRQs are handled here
|
||||||
wifi_init();
|
wifi_init();
|
||||||
|
|
||||||
@@ -109,20 +127,18 @@ static void core1_display_init() {
|
|||||||
// Initialize for partial refresh on second call
|
// Initialize for partial refresh on second call
|
||||||
EPD_7IN5B_V2_Init_Part();
|
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) {
|
while (true) {
|
||||||
// Check if there's a message from core 0
|
DisplayMessage *msg;
|
||||||
if (multicore_fifo_rvalid()) {
|
// Check if there's a message in the queue
|
||||||
// Read the message pointer
|
if (queue_try_remove(&g_display_queue, &msg)) {
|
||||||
uint32_t msg_addr = multicore_fifo_pop_blocking();
|
|
||||||
DisplayMessage *msg = (DisplayMessage *)msg_addr;
|
|
||||||
|
|
||||||
// Drain FIFO to get the latest message
|
// Drain Queue to get the latest message
|
||||||
while (multicore_fifo_rvalid()) {
|
DisplayMessage *next_msg;
|
||||||
|
while (queue_try_remove(&g_display_queue, &next_msg)) {
|
||||||
printf("[Core 1] Skipping intermediate update\n");
|
printf("[Core 1] Skipping intermediate update\n");
|
||||||
free(msg); // Free the stale message
|
free(msg); // Free the stale message
|
||||||
msg_addr = multicore_fifo_pop_blocking();
|
msg = next_msg;
|
||||||
msg = (DisplayMessage *)msg_addr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("[Core 1] Updating display with %d entries\n", msg->entries.count);
|
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() {
|
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");
|
printf("Launching e-Paper display init on core 1...\n");
|
||||||
multicore_launch_core1(core1_display_init);
|
multicore_launch_core1(core1_display_init);
|
||||||
}
|
}
|
||||||
|
|
||||||
void epaper_send_update(const char *entry, bool finish_line) {
|
void epaper_send_update(const char *entry, bool finish_line) {
|
||||||
if (!g_display_ready) return; // Don't send if display isn't ready
|
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
|
// Check if list is at capacity
|
||||||
if (g_entry_list.count >= MAX_ENTRIES) {
|
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;
|
msg->yend = msg->ystart + 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send message pointer to core 1 if FIFO has space
|
// Send message pointer to core 1 via Queue
|
||||||
if (multicore_fifo_wready()) {
|
if (queue_try_add(&g_display_queue, &msg)) {
|
||||||
multicore_fifo_push_blocking((uint32_t)msg);
|
// printf("[Core 0] Display update sent to core 1\n");
|
||||||
} else {
|
} else {
|
||||||
printf("[Core 0] FIFO full, skipping display update\n");
|
printf("[Core 0] Queue full, skipping display update\n");
|
||||||
free(msg);
|
free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ static bool execute_command(CommandAction action, const char* input) {
|
|||||||
if (parsed < 2) {
|
if (parsed < 2) {
|
||||||
printf("Usage: /connect <ssid> <password>\n");
|
printf("Usage: /connect <ssid> <password>\n");
|
||||||
if (g_display_manager) g_display_manager->refresh("Usage: /connect <ssid> <pass>", nullptr);
|
if (g_display_manager) g_display_manager->refresh("Usage: /connect <ssid> <pass>", nullptr);
|
||||||
// epaper_send_update("Usage: /connect <ssid> <pass>", true);
|
epaper_send_update("Usage: /connect <ssid> <pass>", true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,11 +67,18 @@ static bool execute_command(CommandAction action, const char* input) {
|
|||||||
|
|
||||||
if (wifi_connect(ssid, password)) {
|
if (wifi_connect(ssid, password)) {
|
||||||
if (g_display_manager) g_display_manager->refresh("Connected!", ssid);
|
if (g_display_manager) g_display_manager->refresh("Connected!", ssid);
|
||||||
// epaper_send_update("Connected!", true);
|
int rc = wifi_save_credentials(ssid, password);
|
||||||
// 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 {
|
} else {
|
||||||
if (g_display_manager) g_display_manager->refresh("Connection Failed", nullptr);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -219,20 +226,13 @@ int main() {
|
|||||||
sleep_ms(3000); // Give time for power to settle and serial to connect
|
sleep_ms(3000); // Give time for power to settle and serial to connect
|
||||||
printf("System Booting...\n");
|
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();
|
epaper_start_background_thread();
|
||||||
|
|
||||||
DisplayManager display;
|
DisplayManager display;
|
||||||
display.init();
|
display.init();
|
||||||
g_display_manager = &display;
|
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");
|
printf("Initializing TinyUSB Host...\n");
|
||||||
tuh_init(BOARD_TUH_RHPORT);
|
tuh_init(BOARD_TUH_RHPORT);
|
||||||
printf("TinyUSB Host Initialized.\n");
|
printf("TinyUSB Host Initialized.\n");
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "wifi_manager.h"
|
#include "wifi_manager.h"
|
||||||
#include "pico/cyw43_arch.h"
|
#include "pico/cyw43_arch.h"
|
||||||
|
#include "pico/multicore.h"
|
||||||
|
#include "pico/flash.h"
|
||||||
#include "hardware/flash.h"
|
#include "hardware/flash.h"
|
||||||
#include "hardware/sync.h"
|
#include "hardware/sync.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -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;
|
WifiCreds creds;
|
||||||
creds.magic = WIFI_CREDS_MAGIC;
|
creds.magic = WIFI_CREDS_MAGIC;
|
||||||
strncpy(creds.ssid, ssid, sizeof(creds.ssid) - 1);
|
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);
|
strncpy(creds.password, password, sizeof(creds.password) - 1);
|
||||||
creds.password[sizeof(creds.password) - 1] = '\0';
|
creds.password[sizeof(creds.password) - 1] = '\0';
|
||||||
|
|
||||||
uint32_t ints = save_and_disable_interrupts();
|
FlashWriteParams params = { (const uint8_t*)&creds, sizeof(creds) };
|
||||||
flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE);
|
int rc = flash_safe_execute(do_flash_write, ¶ms, 1000);
|
||||||
flash_range_program(FLASH_TARGET_OFFSET, (const uint8_t*)&creds, sizeof(creds));
|
|
||||||
restore_interrupts(ints);
|
|
||||||
|
|
||||||
|
if (rc == PICO_OK) {
|
||||||
printf("WiFi credentials saved to flash.\n");
|
printf("WiFi credentials saved to flash.\n");
|
||||||
|
} else {
|
||||||
|
printf("Failed to save WiFi credentials: %d\n", rc);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wifi_try_auto_connect() {
|
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);
|
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) {
|
if (creds->magic != WIFI_CREDS_MAGIC) {
|
||||||
printf("No saved WiFi credentials found.\n");
|
printf("No saved WiFi credentials found.\n");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ bool wifi_connect(const char* ssid, const char* password);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the WiFi credentials to flash memory for auto-connect.
|
* 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.
|
* Attempts to connect using saved credentials.
|
||||||
|
|||||||
Reference in New Issue
Block a user