Initial framebuffer setup

This commit is contained in:
Lukas Höppner
2026-08-12 22:02:46 +02:00
parent 86981fc45a
commit 84ba0a609a
3 changed files with 143 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
#ifndef NOVA64_FRAMEBUFFER_H
#define NOVA64_FRAMEBUFFER_H
#include "nova64_core.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
// Display dimensions
#define NOVA64_DISPLAY_WIDTH 480
#define NOVA64_DISPLAY_HEIGHT 800
#define NOVA64_DISPLAY_PIXELS (NOVA64_DISPLAY_WIDTH * NOVA64_DISPLAY_HEIGHT)
// Pixel format: RGB565 (uint16_t)
typedef uint16_t pixel_t;
// Framebuffer size in bytes (768,000 bytes)
#define NOVA64_FRAMEBUFFER_SIZE_BYTES (NOVA64_DISPLAY_PIXELS * sizeof(pixel_t))
// Alignment requirement for PPU/DMA2D on ESP32-P4 (cache line alignment)
#define NOVA64_DMA_ALIGNMENT 64
typedef struct {
pixel_t *front_buffer; // Buffer currently being read by display/MIPI-DSI
pixel_t *back_buffer; // Buffer currently being written to by WASM/PPU
volatile bool vsync_pending; // True when a buffer swap has been requested
uint32_t frame_count; // Frame counter
} nova64_framebuffer_t;
// Global instance access
NOVA64_API nova64_framebuffer_t nova64_framebuffer;
// Function prototypes
bool nova64_framebuffer_init(void);
void nova64_framebuffer_destroy(void);
void nova64_framebuffer_swap(void);
void nova64_framebuffer_clear(pixel_t color);
#endif // NOVA64_FRAMEBUFFER_H
+9
View File
@@ -1,5 +1,6 @@
#include "nova64_core.h"
#include "FreeRTOS.h"
#include "nova64_framebuffer.h"
#include "nova64_internal.h"
#include "queue.h"
#include "task.h"
@@ -7,6 +8,7 @@
#include <stdarg.h>
#include <stdio.h>
#if defined(ESP_PLATFORM)
#include "esp_pm.h"
#include "esp_rom_sys.h"
@@ -152,6 +154,12 @@ NOVA64_API bool nova64_init(const nova64_io_interface_t *io_interface) {
}
nova64_log("Initializing...\n");
if (!nova64_framebuffer_init()) {
nova64_log("Framebuffer initialization failed.\n");
return false;
}
if (!initialize_wasm_runtime()) {
nova64_log("WASM runtime initialization failed.\n");
return false;
@@ -199,6 +207,7 @@ NOVA64_API bool nova64_shutdown(void) {
}
wasm_runner_terminate();
nova64_framebuffer_destroy();
nova64_host_sleep_ms(100); // Allow time for tasks to clean up
nova64_log_scheduler_state();
+94
View File
@@ -0,0 +1,94 @@
#include "nova64_framebuffer.h"
#include "nova64_internal.h"
#include <string.h>
// Framebuffer allocation
#if defined(ESP_PLATFORM)
// ESP-IDF heap-cap-APIs for PSRAM allocation
#include "esp_heap_caps.h"
#define ALLOC_FRAMEBUFFER(size) \
heap_caps_aligned_alloc(NOVA64_DMA_ALIGNMENT, size, \
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)
#define FREE_FRAMEBUFFER(ptr) heap_caps_free(ptr)
#else
#include <stdlib.h>
#define ALLOC_FRAMEBUFFER(size) malloc(size)
#define FREE_FRAMEBUFFER(ptr) free(ptr)
#endif
nova64_framebuffer_t nova64_framebuffer = {0};
bool nova64_framebuffer_init(void) {
nova64_log("Initializing Framebuffer (Resolution: %dx%d, RGB565)...\n");
nova64_framebuffer.front_buffer =
(pixel_t *)ALLOC_FRAMEBUFFER(NOVA64_FRAMEBUFFER_SIZE_BYTES);
if (!nova64_framebuffer.front_buffer) {
nova64_log("ERROR: Failed to allocate Front-Buffer (%d Bytes) in PSRAM!\n",
NOVA64_FRAMEBUFFER_SIZE_BYTES);
return false;
}
nova64_framebuffer.back_buffer =
(pixel_t *)ALLOC_FRAMEBUFFER(NOVA64_FRAMEBUFFER_SIZE_BYTES);
if (!nova64_framebuffer.back_buffer) {
nova64_log("ERROR: Failed to allocate Back-Buffer (%d Bytes) in PSRAM!\n",
NOVA64_FRAMEBUFFER_SIZE_BYTES);
FREE_FRAMEBUFFER(nova64_framebuffer.front_buffer);
return false;
}
// Initialize buffers
memset(nova64_framebuffer.front_buffer, 0, NOVA64_FRAMEBUFFER_SIZE_BYTES);
memset(nova64_framebuffer.back_buffer, 0, NOVA64_FRAMEBUFFER_SIZE_BYTES);
nova64_framebuffer.vsync_pending = false;
nova64_framebuffer.frame_count = 0;
nova64_log("Framebuffer initialized successfully in PSRAM. Address: "
"Front=%p, Back=%p\n",
(void *)nova64_framebuffer.front_buffer,
(void *)nova64_framebuffer.back_buffer);
return true;
}
void nova64_framebuffer_destroy(void) {
nova64_log("Destroying Framebuffer and freeing PSRAM...\n");
if (nova64_framebuffer.front_buffer) {
FREE_FRAMEBUFFER(nova64_framebuffer.front_buffer);
nova64_framebuffer.front_buffer = NULL;
}
if (nova64_framebuffer.back_buffer) {
FREE_FRAMEBUFFER(nova64_framebuffer.back_buffer);
nova64_framebuffer.back_buffer = NULL;
}
nova64_framebuffer.vsync_pending = false;
nova64_framebuffer.frame_count = 0;
nova64_log("Framebuffer successfully destroyed.\n");
}
void nova64_framebuffer_swap(void) {
pixel_t *temp = nova64_framebuffer.front_buffer;
nova64_framebuffer.front_buffer = nova64_framebuffer.back_buffer;
nova64_framebuffer.back_buffer = temp;
nova64_framebuffer.frame_count++;
nova64_framebuffer.vsync_pending = false;
}
void nova64_framebuffer_clear(pixel_t color) {
uint32_t *p32 = (uint32_t *)nova64_framebuffer.back_buffer;
uint32_t color32 = ((uint32_t)color << 16) | color;
size_t count32 = NOVA64_DISPLAY_PIXELS / 2;
for (size_t i = 0; i < count32; i++) {
p32[i] = color32;
}
}