vibecoded gb emulator

This commit is contained in:
2025-10-08 22:19:21 +02:00
parent 9a9e25e124
commit 429d704c8c
12 changed files with 781 additions and 6 deletions

1
Firmware/.gitignore vendored
View File

@@ -2,3 +2,4 @@ build
cmake-build* cmake-build*
.idea .idea
.cache .cache
managed_components

View File

@@ -1,5 +1,20 @@
{ {
"idf.flashType": "JTAG", "idf.flashType": "JTAG",
"idf.port": "/dev/tty.usbmodem12401", "idf.port": "/dev/tty.usbmodem12401",
"C_Cpp.intelliSenseEngine": "default" "C_Cpp.intelliSenseEngine": "default",
"files.associations": {
"bitset": "cpp",
"chrono": "cpp",
"algorithm": "cpp",
"random": "cpp",
"fstream": "cpp",
"streambuf": "cpp",
"regex": "cpp",
"*.inc": "cpp",
"vector": "cpp",
"esp_partition.h": "c",
"cstring": "cpp",
"array": "cpp",
"string_view": "cpp"
}
} }

View File

@@ -0,0 +1,21 @@
dependencies:
idf:
source:
type: idf
version: 5.5.1
joltwallet/littlefs:
component_hash: 8e12955f47e27e6070b76715a96d6c75fc2b44f069e8c33679332d9bdd3120c4
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.20.1
direct_dependencies:
- idf
- joltwallet/littlefs
manifest_hash: 261ed140a57f28f061ce29bcf3ae4833c35c16fa5e15670490bf2aacedefa622
target: esp32h2
version: 2.0.0

View File

@@ -4,6 +4,7 @@ idf_component_register(SRCS
src/apps/menu_app.cpp src/apps/menu_app.cpp
src/apps/clock_app.cpp src/apps/clock_app.cpp
src/apps/tetris_app.cpp src/apps/tetris_app.cpp
src/apps/gameboy_app.cpp
src/display.cpp src/display.cpp
src/bat_mon.cpp src/bat_mon.cpp
src/spi_global.cpp src/spi_global.cpp
@@ -14,5 +15,8 @@ idf_component_register(SRCS
src/buttons.cpp src/buttons.cpp
src/power_helper.cpp src/power_helper.cpp
src/buzzer.cpp src/buzzer.cpp
PRIV_REQUIRES spi_flash esp_driver_i2c driver sdk-esp esp_timer nvs_flash src/fs_helper.cpp
INCLUDE_DIRS "include") PRIV_REQUIRES spi_flash esp_driver_i2c driver sdk-esp esp_timer nvs_flash littlefs
INCLUDE_DIRS "include" "Peanut-GB")
littlefs_create_partition_image(littlefs ../flash_data FLASH_IN_PROJECT)

View File

@@ -0,0 +1,17 @@
## IDF Component Manager Manifest File
dependencies:
## Required IDF version
idf:
version: '>=4.1.0'
# # Put list of dependencies here
# # For components maintained by Espressif:
# component: "~1.0.0"
# # For 3rd party components:
# username/component: ">=1.0.0,<2.0.0"
# username2/component2:
# version: "~1.0.0"
# # For transient dependencies `public` flag can be set.
# # `public` flag doesn't have an effect dependencies of the `main` component.
# # All dependencies of `main` are public by default.
# public: true
joltwallet/littlefs: ^1.20

View File

@@ -0,0 +1,15 @@
#pragma once
#include "app_framework.hpp"
#include <memory>
#include <string_view>
namespace apps {
inline constexpr char kGameboyAppName[] = "Game Boy";
inline constexpr std::string_view kGameboyAppNameView = kGameboyAppName;
std::unique_ptr<IAppFactory> createGameboyAppFactory();
} // namespace apps

View File

@@ -0,0 +1,26 @@
#pragma once
#include <esp_err.h>
#include <string_view>
class FsHelper {
public:
static FsHelper& get();
esp_err_t mount();
void unmount();
bool isMounted() const { return mounted; }
const char* basePath() const { return kBasePath; }
const char* partitionLabel() const { return kPartitionLabel; }
private:
FsHelper() = default;
static constexpr const char* kBasePath = "/lfs";
static constexpr const char* kPartitionLabel = "littlefs";
static constexpr const bool kFormatOnFailure = true;
bool mounted = false;
};

View File

@@ -4,6 +4,7 @@
#include "app_framework.hpp" #include "app_framework.hpp"
#include "apps/clock_app.hpp" #include "apps/clock_app.hpp"
#include "apps/gameboy_app.hpp"
#include "apps/menu_app.hpp" #include "apps/menu_app.hpp"
#include "apps/tetris_app.hpp" #include "apps/tetris_app.hpp"
#include "config.hpp" #include "config.hpp"
@@ -14,6 +15,7 @@
#include <disp_tools.hpp> #include <disp_tools.hpp>
#include <display.hpp> #include <display.hpp>
#include <i2c_global.hpp> #include <i2c_global.hpp>
#include <fs_helper.hpp>
#include <power_helper.hpp> #include <power_helper.hpp>
#include <shutdowner.hpp> #include <shutdowner.hpp>
#include <spi_global.hpp> #include <spi_global.hpp>
@@ -111,6 +113,8 @@ extern "C" void app_main() {
DispTools::clear(); DispTools::clear();
Buzzer::get().init(); Buzzer::get().init();
FsHelper::get().mount();
static PlatformFramebuffer framebuffer; static PlatformFramebuffer framebuffer;
static PlatformInput input; static PlatformInput input;
static PlatformClock clock; static PlatformClock clock;
@@ -122,6 +126,7 @@ extern "C" void app_main() {
system.registerApp(apps::createMenuAppFactory()); system.registerApp(apps::createMenuAppFactory());
system.registerApp(apps::createClockAppFactory()); system.registerApp(apps::createClockAppFactory());
system.registerApp(apps::createTetrisAppFactory()); system.registerApp(apps::createTetrisAppFactory());
system.registerApp(apps::createGameboyAppFactory());
system.run(); system.run();
} }

View File

@@ -0,0 +1,569 @@
#include "apps/gameboy_app.hpp"
#include "app_framework.hpp"
#include "font16x8.hpp"
#include <disp_tools.hpp>
#include <fs_helper.hpp>
#include <peanut_gb.h>
#include <algorithm>
#include <array>
#include <cctype>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <dirent.h>
#include <string>
#include <string_view>
#include <sys/stat.h>
#include <vector>
namespace apps {
namespace {
constexpr int kMenuStartY = 48;
constexpr int kMenuSpacing = font16x8::kGlyphHeight + 6;
constexpr std::array<std::string_view, 2> kRomExtensions = {".gb", ".gbc"};
struct RomEntry {
std::string name; // short display name
std::string fullPath; // absolute path on LittleFS
};
class GameboyApp final : public IApp {
public:
explicit GameboyApp(AppContext& ctx) : context(ctx), framebuffer(ctx.framebuffer) {}
void onStart() override {
prevInput = {};
statusMessage.clear();
ensureFilesystemReady();
refreshRomList();
mode = Mode::Browse;
browserDirty = true;
}
void onStop() override { unloadRom(); }
void step() override {
const InputState input = context.input.readState();
switch (mode) {
case Mode::Browse:
handleBrowserInput(input);
renderBrowser();
break;
case Mode::Running:
handleGameInput(input);
if (!gbReady) {
mode = Mode::Browse;
browserDirty = true;
break;
}
gb_run_frame(&gb);
renderGameFrame();
break;
}
prevInput = input;
}
AppSleepPlan sleepPlan(uint32_t /*now*/) const override {
if (mode == Mode::Running)
return {};
AppSleepPlan plan;
plan.slow_ms = 140;
plan.normal_ms = 50;
return plan;
}
private:
enum class Mode { Browse, Running };
AppContext& context;
IFramebuffer& framebuffer;
Mode mode = Mode::Browse;
std::vector<RomEntry> roms;
std::size_t selectedIndex = 0;
bool browserDirty = true;
std::string statusMessage;
InputState prevInput{};
// Emulator state
struct gb_s gb{};
bool gbReady = false;
std::vector<uint8_t> romData;
std::vector<uint8_t> cartRam;
std::array<uint8_t, LCD_WIDTH * LCD_HEIGHT> frameBuffer{};
bool frameDirty = false;
std::string activeRomName;
std::string activeRomSavePath;
bool ensureFilesystemReady() {
esp_err_t err = FsHelper::get().mount();
if (err != ESP_OK) {
setStatus("LittleFS mount failed");
return false;
}
const std::string romDir = romDirectory();
struct stat st{};
if (stat(romDir.c_str(), &st) == 0) {
if (S_ISDIR(st.st_mode))
return true;
setStatus("ROM path not dir");
return false;
}
if (mkdir(romDir.c_str(), 0775) == 0)
return true;
if (errno == EEXIST)
return true;
setStatus("ROM dir mkdir failed");
return false;
}
[[nodiscard]] std::string romDirectory() const {
std::string result(FsHelper::get().basePath());
if (!result.empty() && result.back() != '/')
result.push_back('/');
result.append("roms");
return result;
}
static bool hasRomExtension(std::string_view name) {
const auto dotPos = name.find_last_of('.');
if (dotPos == std::string_view::npos)
return false;
std::string ext(name.substr(dotPos));
std::transform(ext.begin(), ext.end(), ext.begin(),
[](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
return std::any_of(kRomExtensions.begin(), kRomExtensions.end(),
[&](std::string_view allowed) { return ext == allowed; });
}
void refreshRomList() {
roms.clear();
if (!FsHelper::get().isMounted() && !ensureFilesystemReady())
return;
const std::string dirPath = romDirectory();
DIR* dir = opendir(dirPath.c_str());
if (!dir) {
setStatus("No /lfs/roms directory");
return;
}
while (dirent* entry = readdir(dir)) {
const std::string_view name(entry->d_name);
if (name == "." || name == "..")
continue;
if (!hasRomExtension(name))
continue;
RomEntry rom;
rom.fullPath = dirPath;
if (!rom.fullPath.empty() && rom.fullPath.back() != '/')
rom.fullPath.push_back('/');
rom.fullPath.append(entry->d_name);
rom.name = std::string(name);
// Trim extension for display.
const auto dotPos = rom.name.find_last_of('.');
if (dotPos != std::string::npos)
rom.name.resize(dotPos);
roms.push_back(std::move(rom));
}
closedir(dir);
std::sort(roms.begin(), roms.end(), [](const RomEntry& a, const RomEntry& b) { return a.name < b.name; });
if (selectedIndex >= roms.size())
selectedIndex = roms.empty() ? 0 : roms.size() - 1;
browserDirty = true;
if (roms.empty())
setStatus("Copy .gb/.gbc to /lfs/roms");
else
statusMessage.clear();
}
void handleBrowserInput(const InputState& input) {
if (input.select && !prevInput.select) {
refreshRomList();
browserDirty = true;
if (roms.empty())
return;
}
if (roms.empty())
return;
const auto wrapDecrement = [&]() {
if (selectedIndex == 0)
selectedIndex = roms.size() - 1;
else
--selectedIndex;
browserDirty = true;
};
const auto wrapIncrement = [&]() {
selectedIndex = (selectedIndex + 1) % roms.size();
browserDirty = true;
};
if (input.up && !prevInput.up)
wrapDecrement();
else if (input.down && !prevInput.down)
wrapIncrement();
const bool launchRequested = (input.a && !prevInput.a) || (input.start && !prevInput.start);
if (launchRequested)
loadRom(selectedIndex);
}
void renderBrowser() {
if (!browserDirty)
return;
browserDirty = false;
DispTools::draw_to_display_async_wait();
framebuffer.clear(false);
const std::string_view title = "GAME BOY";
const int titleWidth = font16x8::measureText(title, 2, 1);
const int titleX = (framebuffer.width() - titleWidth) / 2;
font16x8::drawText(framebuffer, titleX, 12, title, 2, true, 1);
if (roms.empty()) {
font16x8::drawText(framebuffer, 24, kMenuStartY + 12, "NO ROMS FOUND", 1, true, 1);
font16x8::drawText(framebuffer, 24, kMenuStartY + kMenuSpacing + 12, "/LFS/ROMS", 1, true, 1);
} else {
const std::size_t visibleCount =
static_cast<std::size_t>(std::max(1, (framebuffer.height() - kMenuStartY - 64) / kMenuSpacing));
std::size_t first = 0;
if (roms.size() > visibleCount) {
if (selectedIndex >= visibleCount / 2)
first = selectedIndex - visibleCount / 2;
if (first + visibleCount > roms.size())
first = roms.size() - visibleCount;
}
for (std::size_t i = 0; i < visibleCount && (first + i) < roms.size(); ++i) {
const std::size_t idx = first + i;
const bool selected = (idx == selectedIndex);
const int y = kMenuStartY + static_cast<int>(i) * kMenuSpacing;
const std::string labelText = roms[idx].name.empty() ? "(unnamed)" : roms[idx].name;
if (selected)
font16x8::drawText(framebuffer, 16, y, ">", 1, true, 1);
font16x8::drawText(framebuffer, selected ? 32 : 40, y, labelText, 1, true, 1);
}
font16x8::drawText(framebuffer, 16, framebuffer.height() - 52, "A/START PLAY", 1, true, 1);
font16x8::drawText(framebuffer, 16, framebuffer.height() - 32, "SELECT RESCAN", 1, true, 1);
}
if (!statusMessage.empty()) {
const int textWidth = font16x8::measureText(statusMessage, 1, 1);
const int x = std::max(12, (framebuffer.width() - textWidth) / 2);
font16x8::drawText(framebuffer, x, framebuffer.height() - 16, statusMessage, 1, true, 1);
}
DispTools::draw_to_display_async_start();
}
bool loadRom(std::size_t index) {
if (index >= roms.size())
return false;
unloadRom();
const RomEntry& rom = roms[index];
FILE* file = std::fopen(rom.fullPath.c_str(), "rb");
if (!file) {
setStatus("Open ROM failed");
return false;
}
if (std::fseek(file, 0, SEEK_END) != 0) {
setStatus("ROM seek failed");
std::fclose(file);
return false;
}
const long size = std::ftell(file);
if (size <= 0) {
setStatus("ROM empty");
std::fclose(file);
return false;
}
std::rewind(file);
romData.resize(static_cast<std::size_t>(size));
const size_t readBytes = std::fread(romData.data(), 1, romData.size(), file);
std::fclose(file);
if (readBytes != romData.size()) {
setStatus("ROM read failed");
romData.clear();
return false;
}
std::memset(&gb, 0, sizeof(gb));
const auto initResult = gb_init(&gb, &GameboyApp::romRead, &GameboyApp::cartRamRead, &GameboyApp::cartRamWrite,
&GameboyApp::errorCallback, this);
if (initResult != GB_INIT_NO_ERROR) {
setStatus(initErrorToString(initResult));
romData.clear();
return false;
}
gb.direct.priv = this;
gb.direct.joypad = 0xFF;
gb.direct.interlace = false;
gb.direct.frame_skip = false;
gb_init_lcd(&gb, &GameboyApp::lcdDrawLine);
const uint_fast32_t saveSize = gb_get_save_size(&gb);
cartRam.assign(static_cast<std::size_t>(saveSize), 0);
activeRomSavePath = buildSavePath(rom.fullPath);
loadSaveFile();
gbReady = true;
mode = Mode::Running;
frameDirty = true;
activeRomName = rom.name.empty() ? "Game" : rom.name;
setStatus("Running " + activeRomName);
return true;
}
void unloadRom() {
if (!gbReady) {
romData.clear();
cartRam.clear();
activeRomName.clear();
activeRomSavePath.clear();
return;
}
maybeSaveRam();
gbReady = false;
romData.clear();
cartRam.clear();
activeRomName.clear();
activeRomSavePath.clear();
std::memset(&gb, 0, sizeof(gb));
mode = Mode::Browse;
browserDirty = true;
}
void handleGameInput(const InputState& input) {
if (!gbReady)
return;
uint8_t joypad = 0xFF;
if (input.a)
joypad &= ~JOYPAD_A;
if (input.b)
joypad &= ~JOYPAD_B;
if (input.select)
joypad &= ~JOYPAD_SELECT;
if (input.start)
joypad &= ~JOYPAD_START;
if (input.up)
joypad &= ~JOYPAD_UP;
if (input.down)
joypad &= ~JOYPAD_DOWN;
if (input.left)
joypad &= ~JOYPAD_LEFT;
if (input.right)
joypad &= ~JOYPAD_RIGHT;
gb.direct.joypad = joypad;
const bool exitComboPressed = input.start && input.select;
const bool exitComboJustPressed = exitComboPressed && !(prevInput.start && prevInput.select);
if (exitComboJustPressed) {
setStatus("Saved " + activeRomName);
unloadRom();
}
}
void renderGameFrame() {
if (!frameDirty)
return;
frameDirty = false;
DispTools::draw_to_display_async_wait();
framebuffer.clear(false);
const int offsetX = (framebuffer.width() - LCD_WIDTH) / 2;
const int offsetY = (framebuffer.height() - LCD_HEIGHT) / 2;
for (int y = 0; y < LCD_HEIGHT; ++y) {
const int dstY = offsetY + y;
if (dstY < 0 || dstY >= framebuffer.height())
continue;
for (int x = 0; x < LCD_WIDTH; ++x) {
const int dstX = offsetX + x;
if (dstX < 0 || dstX >= framebuffer.width())
continue;
const bool on = frameBuffer[static_cast<std::size_t>(y) * LCD_WIDTH + x] != 0;
framebuffer.drawPixel(dstX, dstY, on);
}
}
if (!activeRomName.empty())
font16x8::drawText(framebuffer, 16, 16, activeRomName, 1, true, 1);
font16x8::drawText(framebuffer, 16, framebuffer.height() - 24, "START+SELECT BACK", 1, true, 1);
DispTools::draw_to_display_async_start();
}
void maybeSaveRam() {
if (cartRam.empty() || activeRomSavePath.empty())
return;
FILE* file = std::fopen(activeRomSavePath.c_str(), "wb");
if (!file) {
setStatus("Save write failed");
return;
}
const size_t written = std::fwrite(cartRam.data(), 1, cartRam.size(), file);
std::fclose(file);
if (written != cartRam.size()) {
setStatus("Save short write");
}
}
void loadSaveFile() {
if (cartRam.empty() || activeRomSavePath.empty())
return;
FILE* file = std::fopen(activeRomSavePath.c_str(), "rb");
if (!file)
return;
const size_t read = std::fread(cartRam.data(), 1, cartRam.size(), file);
std::fclose(file);
if (read != cartRam.size()) {
// Ignore partial save files; keep data read so far.
setStatus("Partial save loaded");
}
}
void setStatus(std::string message) {
statusMessage = std::move(message);
browserDirty = true;
}
static std::string buildSavePath(const std::string& romPath) {
std::string result = romPath;
const auto dot = result.find_last_of('.');
if (dot != std::string::npos)
result.resize(dot);
result.append(".sav");
return result;
}
static GameboyApp* fromGb(struct gb_s* gb) {
if (!gb)
return nullptr;
return static_cast<GameboyApp*>(gb->direct.priv);
}
static uint8_t romRead(struct gb_s* gb, const uint_fast32_t addr) {
auto* self = fromGb(gb);
if (!self || addr >= self->romData.size())
return 0xFF;
return self->romData[static_cast<std::size_t>(addr)];
}
static uint8_t cartRamRead(struct gb_s* gb, const uint_fast32_t addr) {
auto* self = fromGb(gb);
if (!self || addr >= self->cartRam.size())
return 0xFF;
return self->cartRam[static_cast<std::size_t>(addr)];
}
static void cartRamWrite(struct gb_s* gb, const uint_fast32_t addr, const uint8_t value) {
auto* self = fromGb(gb);
if (!self || addr >= self->cartRam.size())
return;
self->cartRam[static_cast<std::size_t>(addr)] = value;
}
static void errorCallback(struct gb_s* gb, const enum gb_error_e err, const uint16_t val) {
auto* self = fromGb(gb);
if (!self)
return;
char buf[64];
std::snprintf(buf, sizeof(buf), "EMU %s %04X", errorToString(err), val);
self->setStatus(buf);
self->unloadRom();
}
static void lcdDrawLine(struct gb_s* gb, const uint8_t pixels[160], const uint_fast8_t line) {
auto* self = fromGb(gb);
if (!self || line >= LCD_HEIGHT)
return;
const std::size_t offset = static_cast<std::size_t>(line) * LCD_WIDTH;
for (int x = 0; x < LCD_WIDTH; ++x) {
// Collapse 2-bit colour into monochrome.
const uint8_t shade = pixels[x] & 0x03u;
self->frameBuffer[offset + static_cast<std::size_t>(x)] = (shade >= 2) ? 1 : 0;
}
self->frameDirty = true;
}
static const char* initErrorToString(enum gb_init_error_e err) {
switch (err) {
case GB_INIT_NO_ERROR:
return "OK";
case GB_INIT_CARTRIDGE_UNSUPPORTED:
return "Unsupported cart";
case GB_INIT_INVALID_CHECKSUM:
return "Bad checksum";
default:
return "Init failed";
}
}
static const char* errorToString(enum gb_error_e err) {
switch (err) {
case GB_UNKNOWN_ERROR:
return "Unknown";
case GB_INVALID_OPCODE:
return "Bad opcode";
case GB_INVALID_READ:
return "Bad read";
case GB_INVALID_WRITE:
return "Bad write";
case GB_HALT_FOREVER:
return "Halt";
default:
return "Error";
}
}
};
class GameboyAppFactory final : public IAppFactory {
public:
const char* name() const override { return kGameboyAppName; }
std::unique_ptr<IApp> create(AppContext& context) override { return std::make_unique<GameboyApp>(context); }
};
} // namespace
std::unique_ptr<IAppFactory> createGameboyAppFactory() { return std::make_unique<GameboyAppFactory>(); }
} // namespace apps

View File

@@ -0,0 +1,68 @@
#include "fs_helper.hpp"
#include <esp_idf_version.h>
#include <esp_littlefs.h>
#include <esp_log.h>
#include <cstring>
namespace {
constexpr const char* kTag = "FsHelper";
} // namespace
FsHelper& FsHelper::get() {
static FsHelper instance;
return instance;
}
esp_err_t FsHelper::mount() {
if (mounted)
return ESP_OK;
esp_vfs_littlefs_conf_t conf{};
conf.base_path = kBasePath;
conf.partition_label = kPartitionLabel;
conf.format_if_mount_failed = kFormatOnFailure;
conf.dont_mount = false;
#if ESP_IDF_VERSION_MAJOR >= 5
conf.read_only = false;
#endif
const esp_err_t err = esp_vfs_littlefs_register(&conf);
if (err != ESP_OK) {
if (err == ESP_ERR_NOT_FOUND) {
ESP_LOGE(kTag, "Failed to find LittleFS partition '%s'", kPartitionLabel);
} else if (err == ESP_FAIL) {
ESP_LOGE(kTag, "Failed to mount LittleFS at %s (consider enabling format)",
kBasePath);
} else {
ESP_LOGE(kTag, "esp_vfs_littlefs_register failed: %s", esp_err_to_name(err));
}
return err;
}
mounted = true;
size_t total = 0;
size_t used = 0;
const esp_err_t infoErr = esp_littlefs_info(kPartitionLabel, &total, &used);
if (infoErr == ESP_OK) {
ESP_LOGI(kTag, "LittleFS mounted at %s (%zu / %zu bytes used)", kBasePath, used, total);
} else {
ESP_LOGW(kTag, "LittleFS mounted but failed to query usage: %s", esp_err_to_name(infoErr));
}
return ESP_OK;
}
void FsHelper::unmount() {
if (!mounted)
return;
const esp_err_t err = esp_vfs_littlefs_unregister(kPartitionLabel);
if (err != ESP_OK) {
ESP_LOGW(kTag, "Failed to unmount LittleFS (%s)", esp_err_to_name(err));
return;
}
mounted = false;
ESP_LOGI(kTag, "LittleFS unmounted from %s", kBasePath);
}

6
Firmware/partitions.csv Normal file
View File

@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
phy_init, data, phy, 0x10000, 0x1000,
factory, app, factory, 0x20000, 0x150000,
littlefs, data, littlefs,, 0x290000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 phy_init data phy 0x10000 0x1000
5 factory app factory 0x20000 0x150000
6 littlefs data littlefs 0x290000

View File

@@ -599,13 +599,13 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
# #
# Partition Table # Partition Table
# #
CONFIG_PARTITION_TABLE_SINGLE_APP=y # CONFIG_PARTITION_TABLE_SINGLE_APP is not set
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set # CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
# CONFIG_PARTITION_TABLE_TWO_OTA is not set # CONFIG_PARTITION_TABLE_TWO_OTA is not set
# CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set # CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set
# CONFIG_PARTITION_TABLE_CUSTOM is not set CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000 CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table # end of Partition Table
@@ -2409,6 +2409,34 @@ CONFIG_WL_SECTOR_SIZE=4096
CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
CONFIG_WIFI_PROV_BLE_SEC_CONN=y CONFIG_WIFI_PROV_BLE_SEC_CONN=y
#
# LittleFS
#
# CONFIG_LITTLEFS_SDMMC_SUPPORT is not set
CONFIG_LITTLEFS_MAX_PARTITIONS=3
CONFIG_LITTLEFS_PAGE_SIZE=256
CONFIG_LITTLEFS_OBJ_NAME_LEN=64
CONFIG_LITTLEFS_READ_SIZE=128
CONFIG_LITTLEFS_WRITE_SIZE=128
CONFIG_LITTLEFS_LOOKAHEAD_SIZE=128
CONFIG_LITTLEFS_CACHE_SIZE=512
CONFIG_LITTLEFS_BLOCK_CYCLES=512
CONFIG_LITTLEFS_USE_MTIME=y
# CONFIG_LITTLEFS_USE_ONLY_HASH is not set
# CONFIG_LITTLEFS_HUMAN_READABLE is not set
CONFIG_LITTLEFS_MTIME_USE_SECONDS=y
# CONFIG_LITTLEFS_MTIME_USE_NONCE is not set
# CONFIG_LITTLEFS_SPIFFS_COMPAT is not set
# CONFIG_LITTLEFS_FLUSH_FILE_EVERY_WRITE is not set
# CONFIG_LITTLEFS_FCNTL_GET_PATH is not set
# CONFIG_LITTLEFS_MULTIVERSION is not set
# CONFIG_LITTLEFS_MALLOC_STRATEGY_DISABLE is not set
CONFIG_LITTLEFS_MALLOC_STRATEGY_DEFAULT=y
# CONFIG_LITTLEFS_MALLOC_STRATEGY_INTERNAL is not set
CONFIG_LITTLEFS_ASSERTS=y
# CONFIG_LITTLEFS_MMAP_PARTITION is not set
# end of LittleFS
# end of Component config # end of Component config
# CONFIG_IDF_EXPERIMENTAL_FEATURES is not set # CONFIG_IDF_EXPERIMENTAL_FEATURES is not set