Merge buzzy_integration into main
This commit is contained in:
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -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"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
VERSION_MAJOR = 0
|
||||
VERSION_MINOR = 0
|
||||
PATCHLEVEL = 2
|
||||
PATCHLEVEL = 6
|
||||
VERSION_TWEAK = 0
|
||||
#if (IS_ENABLED(CONFIG_LOG))
|
||||
EXTRAVERSION = debug
|
||||
|
||||
11
firmware/boards/buzzy_nrf52840.conf
Normal file
11
firmware/boards/buzzy_nrf52840.conf
Normal file
@@ -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
|
||||
@@ -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 = <DT_SIZE_M(8)>;
|
||||
size = <DT_SIZE_M(64)>;
|
||||
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 = <DT_SIZE_M(8)>;
|
||||
// size = <DT_SIZE_M(64)>;
|
||||
// has-dpd;
|
||||
// t-enter-dpd = <10000>;
|
||||
// t-exit-dpd = <35000>;
|
||||
|
||||
4
firmware/boards/nrf52840dk_nrf52840.conf
Normal file
4
firmware/boards/nrf52840dk_nrf52840.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
### Console / Logging: UART
|
||||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_LOG_BACKEND_UART=y
|
||||
CONFIG_LOG_BACKEND_RTT=n
|
||||
@@ -3,6 +3,7 @@
|
||||
nordic,pm-ext-flash = &mx25r64;
|
||||
};
|
||||
aliases {
|
||||
external-flash = &mx25r64;
|
||||
qspi-flash = &mx25r64;
|
||||
i2s-audio = &i2s0;
|
||||
};
|
||||
|
||||
8
firmware/debug.conf
Normal file
8
firmware/debug.conf
Normal file
@@ -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
|
||||
3
firmware/fs/.gitignore
vendored
Normal file
3
firmware/fs/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
lfs_external_flash.hex
|
||||
.tmp_lfs_build/
|
||||
*.wav
|
||||
86
firmware/fs/README.md
Normal file
86
firmware/fs/README.md
Normal file
@@ -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.
|
||||
282
firmware/fs/build_lfs_audio.py
Normal file
282
firmware/fs/build_lfs_audio.py
Normal file
@@ -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()
|
||||
23
firmware/fs/buzzy.json
Normal file
23
firmware/fs/buzzy.json
Normal file
@@ -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
|
||||
}
|
||||
46
firmware/fs/buzzy.toml
Normal file
46
firmware/fs/buzzy.toml
Normal file
@@ -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]}
|
||||
]
|
||||
1
firmware/fs/program.bat
Normal file
1
firmware/fs/program.bat
Normal file
@@ -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
|
||||
4
firmware/fs/program.sh
Executable file
4
firmware/fs/program.sh
Executable file
@@ -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
|
||||
7
firmware/fs/requirements.txt
Normal file
7
firmware/fs/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
kokoro>=0.1.0
|
||||
soundfile
|
||||
numpy
|
||||
torch
|
||||
PyYAML
|
||||
littlefs-python
|
||||
intelhex
|
||||
@@ -1,4 +1,4 @@
|
||||
if(CONFIG_AUDIO)
|
||||
if(CONFIG_BUZZ_AUDIO)
|
||||
zephyr_library()
|
||||
zephyr_library_sources(src/audio.c)
|
||||
zephyr_include_directories(include)
|
||||
|
||||
@@ -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
|
||||
endif # BUZZ_AUDIO
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <zephyr/fs/littlefs.h>
|
||||
#include <zephyr/fs/fs.h>
|
||||
#include <zephyr/storage/flash_map.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
@@ -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
|
||||
|
||||
5
firmware/pm_static.yml
Normal file
5
firmware/pm_static.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
# External Flash
|
||||
littlefs_storage:
|
||||
address: 0x0
|
||||
size: 0x800000
|
||||
region: external_flash
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user