diff --git a/.vscode/settings.json b/.vscode/settings.json index 61edc8e..7473550 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,9 @@ "svelte.plugin.svelte.format.config.printWidth": 300, "nrf-connect.applications": [ "${workspaceFolder}/firmware" - ] + ], + "nrf-connect.boardRoots": [ + "${workspaceFolder}/firmware" + ], + "cmake.sourceDirectory": "C:/Projekte/buzzer_2/firmware/libs/ble_mgmt" } \ No newline at end of file diff --git a/firmware/VERSION b/firmware/VERSION index 3bc071b..72bcbd0 100644 --- a/firmware/VERSION +++ b/firmware/VERSION @@ -1,6 +1,6 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 -PATCHLEVEL = 2 +PATCHLEVEL = 6 VERSION_TWEAK = 0 #if (IS_ENABLED(CONFIG_LOG)) EXTRAVERSION = debug diff --git a/firmware/boards/buzzy_nrf52840.conf b/firmware/boards/buzzy_nrf52840.conf new file mode 100644 index 0000000..6126862 --- /dev/null +++ b/firmware/boards/buzzy_nrf52840.conf @@ -0,0 +1,11 @@ +### Console / Logging: RTT +CONFIG_USE_SEGGER_RTT=y +CONFIG_CONSOLE=y +CONFIG_RTT_CONSOLE=y + +CONFIG_UART_CONSOLE=n +CONFIG_LOG_BACKEND_UART=n +CONFIG_LOG_BACKEND_RTT=y + +# Keep SPI NOR page layout aligned with generated LittleFS block size (4KB). +CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 diff --git a/firmware/boards/iten/buzzy/buzzy.dts b/firmware/boards/iten/buzzy/buzzy.dts index 98872ff..5446b5c 100644 --- a/firmware/boards/iten/buzzy/buzzy.dts +++ b/firmware/boards/iten/buzzy/buzzy.dts @@ -14,6 +14,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; + nordic,pm-ext-flash = &mx25r64; }; /* SD_MODE pin for MAX98357A power gating */ @@ -88,6 +89,7 @@ chg-status = &chg_status; chg-fast = &chg_fast; external-flash = &mx25r64; + i2s-audio = &i2s0; }; }; @@ -147,7 +149,7 @@ reg = <0>; spi-max-frequency = <8000000>; jedec-id = [c2 28 17]; - size = ; + size = ; has-dpd; t-enter-dpd = <10000>; t-exit-dpd = <35000>; @@ -181,7 +183,7 @@ // compatible = "nordic,qspi-nor"; // reg = <0>; // jedec-id = [c2 28 17]; -// size = ; +// size = ; // has-dpd; // t-enter-dpd = <10000>; // t-exit-dpd = <35000>; diff --git a/firmware/boards/iten/buzzy/buzzy_defconfig b/firmware/boards/iten/buzzy/buzzy_defconfig index 8f9f4e3..e323c36 100644 --- a/firmware/boards/iten/buzzy/buzzy_defconfig +++ b/firmware/boards/iten/buzzy/buzzy_defconfig @@ -2,4 +2,4 @@ CONFIG_ARM_MPU=y CONFIG_HW_STACK_PROTECTION=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y -CONFIG_CLOCK_CONTROL_NRF_K32SRC_20PPM=y \ No newline at end of file +CONFIG_CLOCK_CONTROL_NRF_K32SRC_20PPM=y diff --git a/firmware/boards/nrf52840dk_nrf52840.conf b/firmware/boards/nrf52840dk_nrf52840.conf new file mode 100644 index 0000000..f770b15 --- /dev/null +++ b/firmware/boards/nrf52840dk_nrf52840.conf @@ -0,0 +1,4 @@ +### Console / Logging: UART +CONFIG_UART_CONSOLE=y +CONFIG_LOG_BACKEND_UART=y +CONFIG_LOG_BACKEND_RTT=n diff --git a/firmware/boards/nrf52840dk_nrf52840.overlay b/firmware/boards/nrf52840dk_nrf52840.overlay index 7d5f608..d93ab0b 100644 --- a/firmware/boards/nrf52840dk_nrf52840.overlay +++ b/firmware/boards/nrf52840dk_nrf52840.overlay @@ -3,6 +3,7 @@ nordic,pm-ext-flash = &mx25r64; }; aliases { + external-flash = &mx25r64; qspi-flash = &mx25r64; i2s-audio = &i2s0; }; diff --git a/firmware/debug.conf b/firmware/debug.conf new file mode 100644 index 0000000..e3bb52c --- /dev/null +++ b/firmware/debug.conf @@ -0,0 +1,8 @@ +### Logging +CONFIG_LOG=y +CONFIG_AUDIO_LOG_LEVEL_DBG=y + +CONFIG_DEBUG_OPTIMIZATIONS=y + +CONFIG_INIT_STACKS=y +CONFIG_THREAD_STACK_INFO=y diff --git a/firmware/fs/.gitignore b/firmware/fs/.gitignore new file mode 100644 index 0000000..fb8101c --- /dev/null +++ b/firmware/fs/.gitignore @@ -0,0 +1,3 @@ +lfs_external_flash.hex +.tmp_lfs_build/ +*.wav diff --git a/firmware/fs/README.md b/firmware/fs/README.md new file mode 100644 index 0000000..49f3b66 --- /dev/null +++ b/firmware/fs/README.md @@ -0,0 +1,86 @@ +# FS Tooling + +This directory contains the tooling to build and flash the external LittleFS image used by the firmware. + +## Python Version + +Use Python 3.11. + +The filesystem/audio build tool is currently tested with Python 3.11. +Python 3.13 is not supported at the moment, especially on Windows, because some dependencies in the TTS toolchain may fall back to source builds and fail to install. + +In particular, the dependency chain around `kokoro`, `spacy`, `thinc`, and `blis` may fail to install on Windows when no compatible wheels are available. + +## Install Dependencies + +`ffmpeg` is required in addition to the Python packages. + +```sh +python3.11 -m venv venv +. venv/bin/activate +pip install -r requirements.txt +``` + +On Windows: + +```bat +py -3.11 -m venv venv +venv\Scripts\activate +pip install -r requirements.txt +``` + +## Build LittleFS Image + +```sh +./venv/bin/python build_lfs_audio.py +``` + +Example with imported WAV files and a custom system prompt YAML: + +```sh +./venv/bin/python build_lfs_audio.py \ + --wav-dir ./my_wavs \ + --sys-yaml ./sys_prompts.yaml +``` + +Notes: + +- `--wav-dir` imports all `.wav` files from the given directory into `/lfs/a` +- `--sys-yaml` overrides the default TTS prompt list for `/lfs/sys` +- generated audio is converted to mono 16 kHz PCM before it is written into the LittleFS image + +This generates: + +- `lfs_external_flash.hex` + +The default image layout is aligned to a 4 KiB flash page layout. + +After the build, the script also prints a usage summary for `/lfs/sys`, `/lfs/a`, and the combined image. + +Example: + +```text +Usage summary: + sys: files=4, raw=48.0 KiB, fs=56.0 KiB (14 blocks, standalone estimate) + audio: files=12, raw=224.0 KiB, fs=264.0 KiB (66 blocks, standalone estimate) + total: raw=272.0 KiB, fs=300.0 KiB (75 blocks in combined image) +``` + +`raw` is the sum of file sizes in the staging tree. +`fs` is the estimated or measured LittleFS space usage with the configured block size. + +## Flash Image + +On macOS/Linux: + +```sh +./program.sh +``` + +On Windows: + +```bat +program.bat +``` + +Both scripts use paths relative to their own location, so they can be started from any working directory. \ No newline at end of file diff --git a/firmware/fs/build_lfs_audio.py b/firmware/fs/build_lfs_audio.py new file mode 100644 index 0000000..4bd5f5c --- /dev/null +++ b/firmware/fs/build_lfs_audio.py @@ -0,0 +1,282 @@ +#!/usr/bin/env python3 +import argparse +import shutil +import subprocess +import tempfile +from pathlib import Path + +import soundfile as sf +import yaml +from intelhex import IntelHex +from kokoro import KPipeline +from littlefs import LittleFS + +DEFAULT_SAMPLE_RATE = 16000 +DEFAULT_VOICE = "af_bella" +DEFAULT_BLOCK_SIZE = 4096 +DEFAULT_BLOCK_COUNT = 2048 +DEFAULT_READ_SIZE = 512 +DEFAULT_LOOKAHEAD_SIZE = 256 +DEFAULT_FILTERS = [ + "highpass=f=120", + "lowpass=f=6000", + "acompressor=threshold=-18dB:ratio=3:attack=5:release=80", + "loudnorm=I=-16:TP=-1.0", +] + +DEFAULT_SYS_PROMPTS = [ + {"id": "404", "text": "No sound sample was found on the device."}, + {"id": "update", "text": "Firmware updated. Awaiting confirmation."}, + {"id": "confirm", "text": "State confirmed."}, + {"id": "voltest", "text": "Volume test. This is a sample of the current volume level."}, +] + + +def run_ffmpeg(cmd: list[str]) -> None: + subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + +def export_raw_pcm(input_path: Path, output_path: Path, sample_rate: int, filters: list[str]) -> None: + output_path.parent.mkdir(parents=True, exist_ok=True) + filter_str = ",".join(filters) + run_ffmpeg([ + "ffmpeg", + "-y", + "-i", + str(input_path), + "-af", + filter_str, + "-ar", + str(sample_rate), + "-ac", + "1", + "-f", + "s16le", + "-acodec", + "pcm_s16le", + str(output_path), + ]) + + +def load_sys_prompts(yaml_path: Path | None) -> list[dict]: + if yaml_path is None: + return DEFAULT_SYS_PROMPTS + + with open(yaml_path, "r", encoding="utf-8") as f: + data = yaml.safe_load(f) or [] + + prompts: list[dict] = [] + if isinstance(data, list): + for item in data: + if isinstance(item, dict) and item.get("id") and item.get("text"): + prompts.append({"id": item["id"], "text": item["text"]}) + elif isinstance(data, dict): + for item in data.get("assets", []): + if isinstance(item, dict) and item.get("id") and item.get("text"): + prompts.append({"id": item["id"], "text": item["text"]}) + + return prompts + + +def build_sys_tts(prompts: list[dict], out_sys_dir: Path, sample_rate: int) -> int: + pipeline = KPipeline(lang_code="a") + generated = 0 + + with tempfile.TemporaryDirectory(prefix="tts_tmp_") as tmp_dir_name: + tmp_dir = Path(tmp_dir_name) + + for prompt in prompts: + asset_id = prompt["id"] + text = prompt["text"] + + tmp_wav = tmp_dir / f"{asset_id}.wav" + generator = pipeline(text, voice=DEFAULT_VOICE, speed=1.0) + for _, _, audio in generator: + sf.write(tmp_wav, audio, 24000) + break + + out_file = out_sys_dir / asset_id + export_raw_pcm(tmp_wav, out_file, sample_rate=sample_rate, filters=DEFAULT_FILTERS) + generated += 1 + + return generated + + +def import_wavs_to_a(wav_dir: Path | None, out_a_dir: Path, sample_rate: int) -> int: + if wav_dir is None: + return 0 + if not wav_dir.exists() or not wav_dir.is_dir(): + raise FileNotFoundError(f"WAV directory not found: {wav_dir}") + + count = 0 + for wav_file in sorted(wav_dir.glob("*.wav")): + out_file = out_a_dir / wav_file.stem + export_raw_pcm(wav_file, out_file, sample_rate=sample_rate, filters=DEFAULT_FILTERS) + count += 1 + + return count + + +def add_files_recursive(fs: LittleFS, local_path: Path, lfs_path: str = "/") -> None: + if not local_path.exists(): + return + + for item in sorted(local_path.iterdir()): + target_path = f"{lfs_path.rstrip('/')}/{item.name}".replace("//", "/") + if item.is_file(): + with open(item, "rb") as f: + with fs.open(target_path, "wb") as lfs_file: + lfs_file.write(f.read()) + elif item.is_dir(): + fs.mkdir(target_path) + add_files_recursive(fs, item, target_path) + + +def build_littlefs_image(source_folder: Path, block_size: int, block_count: int) -> tuple[LittleFS, int]: + fs = LittleFS( + block_size=block_size, + block_count=block_count, + read_size=DEFAULT_READ_SIZE, + prog_size=256, + lookahead_size=DEFAULT_LOOKAHEAD_SIZE, + cache_size=4096, + ) + + add_files_recursive(fs, source_folder) + + used_blocks = 0 + lfs_buffer = fs.context.buffer + for idx in range(block_count): + offset = idx * block_size + block_data = lfs_buffer[offset : offset + block_size] + if any(byte != 0xFF for byte in block_data): + used_blocks += 1 + + return fs, used_blocks + + +def build_littlefs_hex(source_folder: Path, output_hex: Path, block_size: int, block_count: int, start_addr: int) -> int: + fs, used_blocks = build_littlefs_image(source_folder, block_size, block_count) + + ih = IntelHex() + lfs_buffer = fs.context.buffer + + for idx in range(block_count): + offset = idx * block_size + block_data = lfs_buffer[offset : offset + block_size] + if any(byte != 0xFF for byte in block_data): + ih.frombytes(block_data, offset=start_addr + offset) + + ih.tofile(str(output_hex), format="hex") + return used_blocks + + +def summarize_directory(directory: Path) -> tuple[int, int]: + if not directory.exists(): + return 0, 0 + + file_count = 0 + raw_bytes = 0 + for file_path in directory.rglob("*"): + if file_path.is_file(): + file_count += 1 + raw_bytes += file_path.stat().st_size + + return file_count, raw_bytes + + +def format_bytes(size: int) -> str: + units = ["B", "KiB", "MiB", "GiB"] + value = float(size) + for unit in units: + if value < 1024.0 or unit == units[-1]: + if unit == "B": + return f"{int(value)} {unit}" + return f"{value:.1f} {unit}" + value /= 1024.0 + + +def report_directory_usage(label: str, directory: Path, block_size: int, block_count: int) -> None: + file_count, raw_bytes = summarize_directory(directory) + _, used_blocks = build_littlefs_image(directory, block_size, block_count) + fs_bytes = used_blocks * block_size + print( + f" {label}: files={file_count}, raw={format_bytes(raw_bytes)}, " + f"fs={format_bytes(fs_bytes)} ({used_blocks} blocks, standalone estimate)" + ) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description=( + "Generate Bella-only TTS in /lfs/sys, optionally import WAVs into /lfs/a, " + "then create LittleFS HEX." + ) + ) + parser.add_argument("--wav-dir", default=None, help="Optional directory with WAV files for /lfs/a") + parser.add_argument("--sys-yaml", default=None, help="Optional YAML with system prompts (id/text)") + parser.add_argument("--sample-rate", type=int, default=DEFAULT_SAMPLE_RATE) + parser.add_argument("--block-size", type=int, default=DEFAULT_BLOCK_SIZE) + parser.add_argument("--block-count", type=int, default=DEFAULT_BLOCK_COUNT) + parser.add_argument("--start-addr", type=lambda x: int(x, 0), default=0x12000000) + parser.add_argument( + "--output-hex", + default=str(Path(__file__).resolve().parent / "lfs_external_flash.hex"), + help="Output path for generated HEX", + ) + parser.add_argument( + "--keep-staging", + action="store_true", + help="Keep temporary staging directory for inspection", + ) + return parser.parse_args() + + +def main() -> None: + args = parse_args() + + fs_dir = Path(__file__).resolve().parent + output_hex = Path(args.output_hex).resolve() + wav_dir = Path(args.wav_dir).resolve() if args.wav_dir else None + sys_yaml = Path(args.sys_yaml).resolve() if args.sys_yaml else None + + staging_root = fs_dir / ".tmp_lfs_build" + if staging_root.exists(): + shutil.rmtree(staging_root) + + out_sys = staging_root / "lfs" / "sys" + out_a = staging_root / "lfs" / "a" + out_sys.mkdir(parents=True, exist_ok=True) + out_a.mkdir(parents=True, exist_ok=True) + + prompts = load_sys_prompts(sys_yaml) + if not prompts: + raise RuntimeError("No system prompts available. Provide --sys-yaml or use defaults.") + + tts_count = build_sys_tts(prompts, out_sys, args.sample_rate) + wav_count = import_wavs_to_a(wav_dir, out_a, args.sample_rate) + + total_used_blocks = build_littlefs_hex( + source_folder=staging_root, + output_hex=output_hex, + block_size=args.block_size, + block_count=args.block_count, + start_addr=args.start_addr, + ) + + print(f"Done. TTS assets: {tts_count}, WAV imports: {wav_count}, HEX: {output_hex}") + print("Usage summary:") + report_directory_usage("sys", out_sys, args.block_size, args.block_count) + report_directory_usage("audio", out_a, args.block_size, args.block_count) + print( + f" total: raw={format_bytes(summarize_directory(staging_root)[1])}, " + f"fs={format_bytes(total_used_blocks * args.block_size)} " + f"({total_used_blocks} blocks in combined image)" + ) + + if not args.keep_staging and staging_root.exists(): + shutil.rmtree(staging_root) + + +if __name__ == "__main__": + main() diff --git a/firmware/fs/buzzy.json b/firmware/fs/buzzy.json new file mode 100644 index 0000000..67451e9 --- /dev/null +++ b/firmware/fs/buzzy.json @@ -0,0 +1,23 @@ +{ + "firmware_config": { + "peripheral": "QSPI", + "compress": true + }, + "pins": { + "sck": 2, + "csn": 5, + "io0": 29, + "io1": 30, + "io2": 31, + "io3": 45 + }, + "flash_size": 8388608, + "sck_frequency": 8000000, + "address_mode": "MODE24BIT", + "readoc": "READ4IO", + "writeoc": "PP4IO", + "pp_size": "PPSIZE256", + "sck_delay": 0, + "rx_delay": 2, + "page_size": 4096 +} diff --git a/firmware/fs/buzzy.toml b/firmware/fs/buzzy.toml new file mode 100644 index 0000000..b9d9cfb --- /dev/null +++ b/firmware/fs/buzzy.toml @@ -0,0 +1,46 @@ +[qspi] + mem_size = 0x800000 + read_mode = "READ4IO" + write_mode = "PP4IO" + address_mode = "BIT24" + frequency = "M16" + spi_mode = "MODE0" + rx_delay = 2 + wip_index = 0 + page_program_size = "PAGE256" + retain_ram = true + + # Pin-Zuweisungen (angepasst an die Netlist) + [qspi.sck] + delay = 0x80 + pin = 2 + port = 0 + + [qspi.csn] + pin = 5 + port = 0 + + [qspi.dio0] + pin = 29 + port = 0 + + [qspi.dio1] + pin = 30 + port = 0 + + [qspi.dio2] + pin = 31 + port = 0 + + [qspi.dio3] + pin = 13 + port = 1 + + [qspi.custom] + io2_level = "LEVEL_LOW" + io3_level = "LEVEL_HIGH" + # Aktiviert Quad-IO und High-Performance Mode für Macronix MX25R + instructions = [ + {command=0x06, data=[]}, + {command=0x01, data=[0x40, 0, 0x2]} + ] \ No newline at end of file diff --git a/firmware/fs/program.bat b/firmware/fs/program.bat new file mode 100644 index 0000000..99640ce --- /dev/null +++ b/firmware/fs/program.bat @@ -0,0 +1 @@ +nrfutil device --x-ext-mem-config-file "%~dp0buzzy.json" program --firmware "%~dp0lfs_external_flash.hex" --options verify=VERIFY_READ,reset=RESET_SYSTEM \ No newline at end of file diff --git a/firmware/fs/program.sh b/firmware/fs/program.sh new file mode 100755 index 0000000..0af3fb3 --- /dev/null +++ b/firmware/fs/program.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" + +nrfutil device --x-ext-mem-config-file "$SCRIPT_DIR/buzzy.json" program --firmware "$SCRIPT_DIR/lfs_external_flash.hex" --options verify=VERIFY_READ,reset=RESET_SYSTEM diff --git a/firmware/fs/requirements.txt b/firmware/fs/requirements.txt new file mode 100644 index 0000000..f543831 --- /dev/null +++ b/firmware/fs/requirements.txt @@ -0,0 +1,7 @@ +kokoro>=0.1.0 +soundfile +numpy +torch +PyYAML +littlefs-python +intelhex diff --git a/firmware/libs/audio/CMakeLists.txt b/firmware/libs/audio/CMakeLists.txt index dce6f25..9e0e7b5 100644 --- a/firmware/libs/audio/CMakeLists.txt +++ b/firmware/libs/audio/CMakeLists.txt @@ -1,4 +1,4 @@ -if(CONFIG_AUDIO) +if(CONFIG_BUZZ_AUDIO) zephyr_library() zephyr_library_sources(src/audio.c) zephyr_include_directories(include) diff --git a/firmware/libs/audio/Kconfig b/firmware/libs/audio/Kconfig index ed0fb48..4561047 100644 --- a/firmware/libs/audio/Kconfig +++ b/firmware/libs/audio/Kconfig @@ -1,10 +1,10 @@ -menuconfig AUDIO +menuconfig BUZZ_AUDIO bool "Audio handling" - default y + default n select I2S select POLL -if AUDIO +if BUZZ_AUDIO config AUDIO_NO_SAMPLES_SAMPLE string "Audio no samples sample" default "404" @@ -57,4 +57,4 @@ if AUDIO module = AUDIO module-str = audio source "subsys/logging/Kconfig.template.log_config" -endif # AUDIO \ No newline at end of file + endif # BUZZ_AUDIO \ No newline at end of file diff --git a/firmware/libs/audio/src/audio.c b/firmware/libs/audio/src/audio.c index 1b092f0..10652da 100644 --- a/firmware/libs/audio/src/audio.c +++ b/firmware/libs/audio/src/audio.c @@ -186,7 +186,8 @@ static int audio_select_random_to_buf(char *buf, size_t buf_size) { if (current_index == random_index) { - snprintf(buf, buf_size, "%s/%s", FS_AUDIO_PATH, entry.name); + snprintf(buf, buf_size, "%s/%.*s", FS_AUDIO_PATH, + (int)(buf_size - sizeof(FS_AUDIO_PATH) - 1U), entry.name); LOG_DBG("Selected random audio file: %s", buf); found = true; break; diff --git a/firmware/libs/ble_mgmt/src/ble_mgmt.c b/firmware/libs/ble_mgmt/src/ble_mgmt.c index 5208421..50edbdc 100644 --- a/firmware/libs/ble_mgmt/src/ble_mgmt.c +++ b/firmware/libs/ble_mgmt/src/ble_mgmt.c @@ -246,8 +246,10 @@ int ble_mgmt_init(ble_mgmt_rx_cb_t rx_cb, const char *device_name) } const char *name_to_use = (device_name != NULL) ? device_name : CONFIG_BLE_MGMT_DEFAULT_DEVICE_NAME; + LOG_INF("BLE init: set_device_name"); set_device_name(name_to_use); + LOG_INF("BLE init: bt_le_adv_start"); rc = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (rc) { diff --git a/firmware/libs/fs_mgmt/Kconfig b/firmware/libs/fs_mgmt/Kconfig index 6fb2efe..56d0dd2 100644 --- a/firmware/libs/fs_mgmt/Kconfig +++ b/firmware/libs/fs_mgmt/Kconfig @@ -7,7 +7,9 @@ menuconfig FS_MGMT select FILE_SYSTEM_LITTLEFS select FILE_SYSTEM_MKFS select FLASH_PAGE_LAYOUT - select NORDIC_QSPI_NOR if SOC_SERIES_NRF52X && (SOC_NRF52840_QIAA || SOC_NRF52833_QIAA) + select SPI_NOR if BOARD_BUZZY + select PM_OVERRIDE_EXTERNAL_DRIVER_CHECK if BOARD_BUZZY + select NORDIC_QSPI_NOR if BOARD_NRF52840DK_NRF52840 help Library for initializing and managing the file system. @@ -56,13 +58,13 @@ if FS_MGMT endif # SOC_SERIES_NRF52X config FS_LITTLEFS_READ_SIZE - default 256 + default 512 config FS_LITTLEFS_PROG_SIZE default 256 config FS_LITTLEFS_CACHE_SIZE default 4096 config FS_LITTLEFS_LOOKAHEAD_SIZE - default 512 + default 256 module = FS_MGMT module-str = fs_mgmt diff --git a/firmware/libs/fs_mgmt/src/fs_mgmt.c b/firmware/libs/fs_mgmt/src/fs_mgmt.c index 0be1317..ed9d333 100644 --- a/firmware/libs/fs_mgmt/src/fs_mgmt.c +++ b/firmware/libs/fs_mgmt/src/fs_mgmt.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -11,11 +12,18 @@ LOG_MODULE_REGISTER(fs_mgmt, CONFIG_FS_MGMT_LOG_LEVEL); -#define FS_PARTITION_ID FLASH_AREA_ID(littlefs_storage) +/* Prefer external LittleFS partition when present, otherwise internal storage partition. */ +#if DT_NODE_EXISTS(DT_NODELABEL(ext_flash_lfs)) +#define FS_PARTITION_ID FIXED_PARTITION_ID(ext_flash_lfs) +#elif DT_NODE_EXISTS(DT_NODELABEL(storage_partition)) +#define FS_PARTITION_ID FIXED_PARTITION_ID(storage_partition) +#else +#error "No compatible LittleFS partition node label found (expected ext_flash_lfs or storage_partition)" +#endif FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(fs_storage_data); -#define QSPI_FLASH_NODE DT_ALIAS(qspi_flash) -static const struct device *flash_dev = DEVICE_DT_GET(QSPI_FLASH_NODE); +#define EXTERNAL_FLASH_NODE DT_ALIAS(external_flash) +static const struct device *flash_dev = DEVICE_DT_GET(EXTERNAL_FLASH_NODE); #define TAG_MAGIC "TAG!" #define TAG_FORMAT_VERSION 1U diff --git a/firmware/pm_static.yml b/firmware/pm_static.yml new file mode 100644 index 0000000..908036e --- /dev/null +++ b/firmware/pm_static.yml @@ -0,0 +1,5 @@ +# External Flash +littlefs_storage: + address: 0x0 + size: 0x800000 + region: external_flash \ No newline at end of file diff --git a/firmware/prj.conf b/firmware/prj.conf index a0f3ab6..f539f05 100644 --- a/firmware/prj.conf +++ b/firmware/prj.conf @@ -1,7 +1,3 @@ -### Logging -CONFIG_LOG=y -CONFIG_AUDIO_LOG_LEVEL_DBG=y - ### Bluetooth CONFIG_BLE_MGMT=y @@ -14,6 +10,3 @@ CONFIG_PM_DEVICE=y ### Stack CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_INIT_STACKS=y -CONFIG_THREAD_STACK_INFO=y -CONFIG_STACK_SENTINEL=y diff --git a/firmware/src/main.c b/firmware/src/main.c index eab4cd5..a8a45bc 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -5,7 +5,7 @@ #include "fs_mgmt.h" #include "buzz_proto.h" #include "fw_mgmt.h" -#include "audio.h" +// #include "audio.h" LOG_MODULE_REGISTER(main); @@ -44,6 +44,7 @@ void ble_rx_cb(const uint8_t *data, uint16_t len) buzz_proto_buf_free(&buf); /* Speicher bei Fehler sofort wieder freigeben */ } } + #endif int main(void) @@ -55,13 +56,19 @@ int main(void) LOG_ERR("Failed to initialize BLE management: %d", rc); return rc; } + LOG_WRN("After BLE init"); +#else + LOG_WRN("BLE not enabled"); #endif - LOG_INF("Init complete."); + LOG_WRN("Main park loop active"); - k_sleep(K_MSEC(500)); - LOG_INF("Playing test audio files..."); - audio_queue_play("/lfs/sys/update", false); - audio_queue_play("/lfs/sys/confirm", false); - k_sleep(K_FOREVER); + // k_sleep(K_MSEC(500)); + // LOG_INF("Playing test audio files..."); + // audio_queue_play("/lfs/sys/update", false); + // audio_queue_play("/lfs/sys/confirm", false); + for (;;) { + int32_t rem_ms = k_sleep(K_FOREVER); + LOG_WRN("main woke unexpectedly (remaining=%d ms)", rem_ms); + } } \ No newline at end of file diff --git a/firmware/sysbuild/mcuboot.conf b/firmware/sysbuild/mcuboot.conf index 9ad5a36..6f0e9b9 100644 --- a/firmware/sysbuild/mcuboot.conf +++ b/firmware/sysbuild/mcuboot.conf @@ -1,6 +1,5 @@ CONFIG_LOG=y # CONFIG_MCUBOOT_SERIAL=y -CONFIG_UART_CONSOLE=y # CONFIG_SINGLE_APPLICATION_SLOT=n # CONFIG_MCUBOOT_INDICATION_LED=y # CONFIG_BOOT_SERIAL_CDC_ACM=y diff --git a/firmware/sysbuild/mcuboot.overlay b/firmware/sysbuild/mcuboot.overlay deleted file mode 100644 index 907ce4d..0000000 --- a/firmware/sysbuild/mcuboot.overlay +++ /dev/null @@ -1,13 +0,0 @@ -/ { - aliases { - mcuboot-button0 = &button0; - mcuboot-led0 = &led0; - }; -}; - -/* Step 2.1 - Configure CDC ACM */ -&zephyr_udc0 { - cdc_acm_uart0: cdc_acm_uart0 { - compatible = "zephyr,cdc-acm-uart"; - }; -}; \ No newline at end of file