Release fw 0.8.5: BT1035 I2S boot init and hardware doc alignment.

Switch BT1035 bring-up from Line-In to I2S slave (AT+AUXCFG=3, AT+I2SCFG=67) to match the ADAU1701 PCM routing, confirm 2 kΩ I2C pull-ups on R1/R16, and sync firmware docs, AGENTS rules, and the DATASHEET bundle.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-08 14:41:31 +02:00
co-authored by Cursor
parent 3e46b06d4b
commit 0a1188ad66
22 changed files with 244 additions and 125 deletions
+22
View File
@@ -0,0 +1,22 @@
# Component datasheets (DigiRadio hardware)
Authoritative vendor PDFs used for schematic/PCB design review and firmware
bring-up. Paths are relative to this repository root (`DigiRadio/`).
| File | Component | Use in DigiRadio |
|------|-----------|------------------|
| `SI4684-A10.pdf` | Silicon Labs Si4684-A10 | RSTB power sequencing, SPI framing, supply levels, SMODE |
| `adau1701.pdf` | Analog Devices ADAU1701 | I²C pull-ups (2 kΩ R1/R16 on PCB; datasheet 2.2 kΩ), MCLK = 256×fS, serial-port master/slave loopback (MP10→MP4, MP11→MP5) |
| `AN851.pdf` | Silicon Labs AN851 | Si4684 bypass capacitors, antenna layout, schematic guidance |
| `FSC-BT1035_Datasheet_EN.pdf` | Feasycom FSC-BT1035 | Module pinout, electrical and mechanical specs (v1.0) |
| `FSC-BT1035_programming_user_guide_1.1.1.pdf` | Feasycom FSC-BT1035 | **AT command reference** — firmware `core::Bt1035At*` maps to §5/§6 |
## Firmware cross-reference
| Manual section | Primary datasheet |
|----------------|-------------------|
| `ch-hardware.tex` §validation | `SI4684-A10.pdf`, `AN851.pdf`, `adau1701.pdf`, BT1035 datasheets |
| `ch-bt1035.tex` §AT commands | `FSC-BT1035_programming_user_guide_1.1.1.pdf` §5 |
When extending BT1035 commands, cite the programming guide section in code comments
and add a host test in `Software/components/core/test/bt1035_at_test.cpp`.
Binary file not shown.
+13 -8
View File
@@ -7,7 +7,7 @@
**Open-source digital radio — Si4684 tuner · ADAU1701 SigmaDSP · Bluetooth aptX Adaptive · ESP32-S3** **Open-source digital radio — Si4684 tuner · ADAU1701 SigmaDSP · Bluetooth aptX Adaptive · ESP32-S3**
![Status](https://img.shields.io/badge/hardware-verified-brightgreen) ![Status](https://img.shields.io/badge/hardware-verified-brightgreen)
![Firmware](https://img.shields.io/badge/firmware-0.8.3-blue) ![Firmware](https://img.shields.io/badge/firmware-0.8.5-blue)
![CI](https://github.com/manvalan/DigiRadio/actions/workflows/ci.yml/badge.svg) ![CI](https://github.com/manvalan/DigiRadio/actions/workflows/ci.yml/badge.svg)
![PCB](https://img.shields.io/badge/PCB-6--layer-blue) ![PCB](https://img.shields.io/badge/PCB-6--layer-blue)
![Hardware License](https://img.shields.io/badge/hardware-CERN--OHL--S-lightgrey) ![Hardware License](https://img.shields.io/badge/hardware-CERN--OHL--S-lightgrey)
@@ -57,11 +57,11 @@ no analogue conversions are introduced between the tuner and the wireless link.
- **6-layer impedance-controlled PCB**, 50 × 90 mm, two ground planes - **6-layer impedance-controlled PCB**, 50 × 90 mm, two ground planes
- Three antennas (ESP32 2.4 GHz, BT1035 2.4 GHz, FM/DAB SMA) with proper keep-outs - Three antennas (ESP32 2.4 GHz, BT1035 2.4 GHz, FM/DAB SMA) with proper keep-outs
### Firmware (ESP-IDF, C++23 — fw **0.8.3**) ### Firmware (ESP-IDF, C++23 — fw **0.8.5**)
| Area | Capability | | Area | Capability |
|------|------------| |------|------------|
| **Boot & chips** | Si4684 DAB+FM firmware load (HOST_LOAD blobs), ADAU1701 RAM program at every boot, BT1035 UART init | | **Boot & chips** | Si4684 DAB+FM firmware load (HOST_LOAD blobs), ADAU1701 RAM program at every boot, BT1035 I2S slave init (`AT+AUXCFG=3`, `AT+I2SCFG=67`) |
| **Tuner** | FM tune/seek, DAB ensemble tune, service scan & play, RSQ/RDS, DAB event status | | **Tuner** | FM tune/seek, DAB ensemble tune, service scan & play, RSQ/RDS, DAB event status |
| **Now playing** | FM RDS (PS, RadioText, PI, PTY) and DAB Dynamic Label (DLS) in status JSON and web UI | | **Now playing** | FM RDS (PS, RadioText, PI, PTY) and DAB Dynamic Label (DLS) in status JSON and web UI |
| **Audio** | 6-band EQ, input mixer, stereo/bass enhancement overlays, profile persist in encrypted NVS | | **Audio** | 6-band EQ, input mixer, stereo/bass enhancement overlays, profile persist in encrypted NVS |
@@ -83,6 +83,8 @@ Vertical slices landed on `main` (newest first):
| Version | Highlights | | Version | Highlights |
|---------|------------| |---------|------------|
| **0.8.5** | BT1035 I2S slave boot init (schematic-aligned); I2C pull-ups R1/R16 confirmed 2 kΩ; `Hardware/DATASHEET/` bundle |
| **0.8.4** | Dual OTA + DSP blob updates, EEPROM identity, System tab OTA/DSP upload |
| **0.8.3** | NVS + flash encryption (development mode), `initEncryptedStorage`, security docs | | **0.8.3** | NVS + flash encryption (development mode), `initEncryptedStorage`, security docs |
| **0.8.2** | Tabbed Web UI (now-playing, 6-band EQ, all REST); Si4684 blob CI policy | | **0.8.2** | Tabbed Web UI (now-playing, 6-band EQ, all REST); Si4684 blob CI policy |
| **0.8.1** | `IntegrationService` — boot preset recall, tune orchestration (tuner + audio + NVS `last_preset`); services stub removed | | **0.8.1** | `IntegrationService` — boot preset recall, tune orchestration (tuner + audio + NVS `last_preset`); services stub removed |
@@ -228,10 +230,10 @@ Generated C++ API reference: run `doxygen Doxyfile` → `Software/docs/api/html/
| **PCB layout** | 6-layer, DRC clean, plane continuity verified | | **PCB layout** | 6-layer, DRC clean, plane continuity verified |
| **BOM** | Finalised (manufacturable / sourced) | | **BOM** | Finalised (manufacturable / sourced) |
| **Prototype** | In fabrication (PCBWay) | | **Prototype** | In fabrication (PCBWay) |
| **Firmware** | **0.8.3** on `main` — encrypted NVS, full Web UI, integration, RDS/DLS | | **Firmware** | **0.8.5** on `main` BT1035 I2S boot init, dual OTA, encrypted NVS, full Web UI |
| **Web UI** | Tabbed SPA covering every REST endpoint | | **Web UI** | Tabbed SPA covering every REST endpoint |
| **HIL** | Device validation pending PCB (`Software/docs/security-flash-nvs.md`) | | **HIL** | Device validation pending PCB (`Software/docs/security-flash-nvs.md`) |
| **Agent backlog** | Feature-complete on `main` (fw 0.8.3); see [`Software/docs/TODO.md`](Software/docs/TODO.md) | | **Agent backlog** | Feature-complete on `main` (fw 0.8.5); see [`Software/docs/TODO.md`](Software/docs/TODO.md) |
--- ---
@@ -239,9 +241,12 @@ Generated C++ API reference: run `doxygen Doxyfile` → `Software/docs/api/html/
The board is manufactured with **PCBWay** as a 6-layer, impedance-controlled PCB The board is manufactured with **PCBWay** as a 6-layer, impedance-controlled PCB
with turnkey assembly. The FSC-BT1035 Bluetooth module is sourced from Feasycom with turnkey assembly. The FSC-BT1035 Bluetooth module is sourced from Feasycom
(the footprint uses a BT806-compatible, pin-identical land pattern). See the (the footprint uses a BT806-compatible, pin-identical land pattern). Component
[Technical Manual](Software/docs/manual/manual.tex) hardware chapter and manufacturing datasheets for design review live in
notes for fabrication settings and MSL-3 handling of the BT module. [`Hardware/DATASHEET/`](Hardware/DATASHEET/) (Si4684-A10, AN851, ADAU1701, FSC-BT1035).
See the [Technical Manual](Software/docs/manual/manual.tex) hardware chapter
and manufacturing notes for fabrication settings and MSL-3 handling of the BT
module.
--- ---
+3 -3
View File
@@ -29,6 +29,6 @@ Full spec: @AGENTS.md §7.17.3.
## FSC-BT1035 (QCC3056, AT over UART) ## FSC-BT1035 (QCC3056, AT over UART)
- Typed command builder; explicit OK/ERROR/timeout parsing. - Typed command builder; explicit OK/ERROR/timeout parsing.
- AT+AUXCFG=1 (Line-In) is mandatory in the init sequence and covered by - AT+AUXCFG=3 and AT+I2SCFG=67 (I2S slave 48 kHz) are mandatory in the
a test on the command string. Unknown responses are an error, not init sequence and covered by host tests. Unknown responses are an error,
ignored. not ignored.
+5 -3
View File
@@ -397,9 +397,11 @@ Layered, dependencies point inward only:
- Controlled by AT commands over UART. Build commands with a typed - Controlled by AT commands over UART. Build commands with a typed
builder; parse responses with explicit `OK`/`ERROR`/timeout handling. builder; parse responses with explicit `OK`/`ERROR`/timeout handling.
- **Line-In mode is mandatory:** the `AT+AUXCFG=1` step must be part of - **I\textsuperscript{2}S slave mode is mandatory:** `AT+AUXCFG=3` and
the documented init sequence and covered by a test on the command `AT+I2SCFG=67` (Feasycom programming guide §5.1.25 / §5.1.4) must be part
string. Losing it silently breaks the audio path. of the documented init sequence and covered by host tests. The PCB routes
ADAU I\textsuperscript{2}S to the module; `AT+AUXCFG=1` (Line-In) does not
match the schematic.
- The AT subset in use is enumerated and documented; unknown responses - The AT subset in use is enumerated and documented; unknown responses
are an error value, not ignored. are an error value, not ignored.
+4 -4
View File
@@ -2,14 +2,14 @@
Open-source Hi-Fi DAB+/FM receiver firmware for the ESP32-S3. Open-source Hi-Fi DAB+/FM receiver firmware for the ESP32-S3.
**Status:** fw **0.8.4** on `main` — dual OTA + DSP blob updates, EEPROM identity, **Status:** fw **0.8.5** on `main` BT1035 I2S slave boot init, dual OTA + DSP blob updates, EEPROM identity,
NVS + flash encryption (development mode), tabbed Web UI with **System** uploads, NVS + flash encryption (development mode), tabbed Web UI with **System** uploads,
**15** host tests, **4** CI jobs. Agent tasks T1T12 complete; device HIL pending **15** host tests, **4** CI jobs. Agent tasks T1T12 complete; device HIL pending
first PCB. first PCB.
| Area | Shipped in 0.8.4 | | Area | Shipped in 0.8.5 |
|------|------------------| |------|------------------|
| Boot | Si4684 HOST_LOAD, ADAU1701 RAM program, BT1035 Line-In init | | Boot | Si4684 HOST_LOAD, ADAU1701 RAM program, BT1035 I2S slave init (`AUXCFG=3`, `I2SCFG=67`) |
| Tuner | FM/DAB tune, seek up/down, RSQ, RDS, DAB services + DLS | | Tuner | FM/DAB tune, seek up/down, RSQ, RDS, DAB services + DLS |
| Audio | 6-band EQ, mixer, stereo/bass enhance, NVS profile | | Audio | 6-band EQ, mixer, stereo/bass enhance, NVS profile |
| Updates | ESP32 dual-OTA, ADAU1701 `dsp` partition blob replay | | Updates | ESP32 dual-OTA, ADAU1701 `dsp` partition blob replay |
@@ -85,7 +85,7 @@ Header shows EEPROM serial from `/api/health`. Source:
`components/net/www/index.html` · regenerate embed: `components/net/www/index.html` · regenerate embed:
`tools/gzip-www.sh`. `tools/gzip-www.sh`.
## HTTP API (fw 0.8.4) ## HTTP API (fw 0.8.5)
| Method | Path | Purpose | | Method | Path | Purpose |
|--------|------|---------| |--------|------|---------|
@@ -37,7 +37,8 @@ namespace core {
*/ */
enum class Bt1035AtCommand { enum class Bt1035AtCommand {
Ping, ///< AT — link check. Ping, ///< AT — link check.
AuxLineIn, ///< AT+AUXCFG=1wired Line-In from ADAU1701 (mandatory). I2sMode, ///< AT+AUXCFG=3I2S input from ADAU1701 (mandatory).
I2sSlave48k32, ///< AT+I2SCFG=67 — I2S slave 48 kHz 32-bit (§5.1.4).
PairDiscoverable, ///< AT+PAIR=1 — enter BR/EDR/BLE discoverable mode. PairDiscoverable, ///< AT+PAIR=1 — enter BR/EDR/BLE discoverable mode.
PairHidden, ///< AT+PAIR=0 — leave discoverable mode. PairHidden, ///< AT+PAIR=0 — leave discoverable mode.
A2dpStat, ///< AT+A2DPSTAT — read A2DP link state. A2dpStat, ///< AT+A2DPSTAT — read A2DP link state.
@@ -83,7 +84,10 @@ enum class Bt1035AtResponseKind {
}; };
/** Number of commands in bootInitSequence(). */ /** Number of commands in bootInitSequence(). */
inline constexpr std::size_t kBt1035BootInitCommandCount = 2U; inline constexpr std::size_t kBt1035BootInitCommandCount = 3U;
/** Feasycom programming guide §5.1.4: I2S slave, 48 kHz, 32-bit. */
inline constexpr std::uint8_t kBt1035I2sSlave48k32Param = 67U;
/** /**
* @brief buildBt1035AtLine — serialise a command with CRLF terminator. * @brief buildBt1035AtLine — serialise a command with CRLF terminator.
@@ -102,7 +106,7 @@ inline constexpr std::size_t kBt1035BootInitCommandCount = 2U;
* @brief bootInitSequence — mandatory bring-up commands in order. * @brief bootInitSequence — mandatory bring-up commands in order.
* *
* @dname bootInitSequence * @dname bootInitSequence
* @return Ping then AuxLineIn (AT+AUXCFG=1). * @return Ping, I2sMode (AUXCFG=3), I2sSlave48k32 (I2SCFG=67).
* @pubstate none * @pubstate none
* *
* @author Michele Bigi * @author Michele Bigi
@@ -165,6 +169,21 @@ parseBt1035A2dpStatResponse(std::string_view response);
*/ */
[[nodiscard]] std::string buildBt1035SetAutoConnLine(std::uint8_t times); [[nodiscard]] std::string buildBt1035SetAutoConnLine(std::uint8_t times);
/**
* @brief buildBt1035SetNameLine — AT+NAME with optional MAC suffix flag.
*
* @dname buildBt1035SetNameLine
* @param name BR/EDR local name (1--31 ASCII bytes per Feasycom §5.1.16).
* @param enableMacSuffix false sends Param2=0 (disable module suffix).
* @return Full AT line including CRLF.
* @pubstate none
*
* @author Michele Bigi
* @date 2026-07-08
*/
[[nodiscard]] std::string buildBt1035SetNameLine(std::string_view name,
bool enableMacSuffix = false);
/** /**
* @brief parseBt1035NameResponse — extract +NAME= value. * @brief parseBt1035NameResponse — extract +NAME= value.
* *
@@ -27,7 +27,7 @@ namespace core {
struct CompanionChipStatus { struct CompanionChipStatus {
bool si4684Ready; ///< Si4684 HOST_LOAD completed. bool si4684Ready; ///< Si4684 HOST_LOAD completed.
bool adau1701Ready; ///< ADAU1701 SigmaStudio download completed. bool adau1701Ready; ///< ADAU1701 SigmaStudio download completed.
bool bt1035Ready; ///< BT1035 Line-In init (AT+AUXCFG=1) completed. bool bt1035Ready; ///< BT1035 I2S init (AUXCFG=3 + I2SCFG=67) completed.
}; };
} // namespace core } // namespace core
+15 -3
View File
@@ -101,8 +101,10 @@ std::string buildBt1035AtLine(Bt1035AtCommand command)
switch (command) { switch (command) {
case Bt1035AtCommand::Ping: case Bt1035AtCommand::Ping:
return "AT\r\n"; return "AT\r\n";
case Bt1035AtCommand::AuxLineIn: case Bt1035AtCommand::I2sMode:
return "AT+AUXCFG=1\r\n"; return "AT+AUXCFG=3\r\n";
case Bt1035AtCommand::I2sSlave48k32:
return "AT+I2SCFG=67\r\n";
case Bt1035AtCommand::PairDiscoverable: case Bt1035AtCommand::PairDiscoverable:
return "AT+PAIR=1\r\n"; return "AT+PAIR=1\r\n";
case Bt1035AtCommand::PairHidden: case Bt1035AtCommand::PairHidden:
@@ -129,11 +131,21 @@ std::string buildBt1035SetAutoConnLine(std::uint8_t times)
return "AT+AUTOCONN=" + std::to_string(times) + "\r\n"; return "AT+AUTOCONN=" + std::to_string(times) + "\r\n";
} }
std::string buildBt1035SetNameLine(std::string_view name, bool enableMacSuffix)
{
if (name.empty() || name.size() > 31U) {
return {};
}
return std::string("AT+NAME=") + std::string(name) + ","
+ (enableMacSuffix ? "1" : "0") + "\r\n";
}
std::array<Bt1035AtCommand, kBt1035BootInitCommandCount> bootInitSequence() noexcept std::array<Bt1035AtCommand, kBt1035BootInitCommandCount> bootInitSequence() noexcept
{ {
return std::array<Bt1035AtCommand, kBt1035BootInitCommandCount>{ return std::array<Bt1035AtCommand, kBt1035BootInitCommandCount>{
Bt1035AtCommand::Ping, Bt1035AtCommand::Ping,
Bt1035AtCommand::AuxLineIn, Bt1035AtCommand::I2sMode,
Bt1035AtCommand::I2sSlave48k32,
}; };
} }
@@ -28,13 +28,24 @@ namespace {
std::cerr << "init sequence size mismatch\n"; std::cerr << "init sequence size mismatch\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (sequence[1U] != core::Bt1035AtCommand::AuxLineIn) { if (sequence[1U] != core::Bt1035AtCommand::I2sMode) {
std::cerr << "AUXCFG=1 must be in init sequence\n"; std::cerr << "I2S mode must be in init sequence\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
const std::string aux = core::buildBt1035AtLine(core::Bt1035AtCommand::AuxLineIn); if (sequence[2U] != core::Bt1035AtCommand::I2sSlave48k32) {
if (aux != "AT+AUXCFG=1\r\n") { std::cerr << "I2SCFG must be in init sequence\n";
std::cerr << "AUXCFG command line mismatch\n"; return EXIT_FAILURE;
}
const std::string i2sMode =
core::buildBt1035AtLine(core::Bt1035AtCommand::I2sMode);
if (i2sMode != "AT+AUXCFG=3\r\n") {
std::cerr << "AUXCFG=3 command line mismatch\n";
return EXIT_FAILURE;
}
const std::string i2sCfg =
core::buildBt1035AtLine(core::Bt1035AtCommand::I2sSlave48k32);
if (i2sCfg != "AT+I2SCFG=67\r\n") {
std::cerr << "I2SCFG=67 command line mismatch\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
@@ -117,6 +128,11 @@ namespace {
std::cerr << "AUTOCONN command line mismatch\n"; std::cerr << "AUTOCONN command line mismatch\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (core::buildBt1035SetNameLine("DigiRadio-A1B2", false)
!= "AT+NAME=DigiRadio-A1B2,0\r\n") {
std::cerr << "NAME set command line mismatch\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@@ -48,7 +48,7 @@ struct Bt1035Pins {
* @dname Bt1035Driver * @dname Bt1035Driver
* @return n/a (type) * @return n/a (type)
* @pubstate Owns UART port after boot(). booted_ true after init sequence * @pubstate Owns UART port after boot(). booted_ true after init sequence
* including AT+AUXCFG=1 (Line-In from ADAU1701). * including AT+AUXCFG=3 and AT+I2SCFG=67 (I2S slave from ADAU1701).
* *
* @author Michele Bigi * @author Michele Bigi
* @date 2026-07-06 * @date 2026-07-06
@@ -86,7 +86,7 @@ public:
* *
* @dname boot * @dname boot
* @return Ok on success, or Bt1035Error. * @return Ok on success, or Bt1035Error.
* @pubstate sets booted_ after Ping + AT+AUXCFG=1 both return OK. * @pubstate sets booted_ after Ping + I2S init both return OK.
* *
* Sequence: hardware reset, UART @ 115200 with RTS/CTS, then * Sequence: hardware reset, UART @ 115200 with RTS/CTS, then
* core::bootInitSequence() (see manual chapter bt1035). * core::bootInitSequence() (see manual chapter bt1035).
@@ -97,7 +97,7 @@ public:
[[nodiscard]] std::expected<void, Bt1035Error> boot(); [[nodiscard]] std::expected<void, Bt1035Error> boot();
/** /**
* @brief isBooted — query whether Line-In init succeeded. * @brief isBooted — query whether I2S init succeeded.
* *
* @dname isBooted * @dname isBooted
* @return true after successful boot(). * @return true after successful boot().
@@ -177,7 +177,7 @@ public:
* @dname setDeviceName * @dname setDeviceName
* @param name Bluetooth name (Feasycom FSC-BT1035 AT+NAME command). * @param name Bluetooth name (Feasycom FSC-BT1035 AT+NAME command).
* @return Ok on success, or Bt1035Error. * @return Ok on success, or Bt1035Error.
* @pubstate sends AT+NAME after boot; does not alter AT+AUXCFG=1 init. * @pubstate sends AT+NAME after boot; does not alter I2S init sequence.
* *
* @author Michele Bigi * @author Michele Bigi
* @date 2026-07-07 * @date 2026-07-07
@@ -169,10 +169,14 @@ std::expected<void, Bt1035Error> Bt1035Driver::setDeviceName(
if (auto ready = ensureBooted(); !ready) { if (auto ready = ensureBooted(); !ready) {
return ready; return ready;
} }
if (name.empty() || name.size() > 32U) { if (name.empty() || name.size() > 31U) {
return std::unexpected(Bt1035Error::UnexpectedResponse);
}
const std::string line =
core::buildBt1035SetNameLine(name, false);
if (line.empty()) {
return std::unexpected(Bt1035Error::UnexpectedResponse); return std::unexpected(Bt1035Error::UnexpectedResponse);
} }
std::string line = std::string("AT+NAME=") + std::string(name) + "\r\n";
return transmitAndExpectOk(line); return transmitAndExpectOk(line);
} }
@@ -315,7 +319,7 @@ std::expected<void, Bt1035Error> Bt1035Driver::boot()
} }
booted_ = true; booted_ = true;
ESP_LOGI(kTag, "Line-In mode enabled (AT+AUXCFG=1)"); ESP_LOGI(kTag, "I2S slave mode enabled (AT+AUXCFG=3, AT+I2SCFG=67)");
return {}; return {};
} }
@@ -60,7 +60,7 @@ namespace net {
namespace { namespace {
constexpr char kTag[] = "SetupWebServer"; constexpr char kTag[] = "SetupWebServer";
constexpr char kFirmwareVersion[] = "0.8.4"; constexpr char kFirmwareVersion[] = "0.8.5";
constexpr unsigned kRebootDelaySec = 3; constexpr unsigned kRebootDelaySec = 3;
extern const uint8_t www_index_html_gz_start[] asm( extern const uint8_t www_index_html_gz_start[] asm(
+11 -6
View File
@@ -3,7 +3,7 @@
Agent task list and hardware-in-the-loop backlog. Working directory for all Agent task list and hardware-in-the-loop backlog. Working directory for all
commands is `Software/`. commands is `Software/`.
**Current firmware:** `0.8.4` — dual OTA + DSP blob updates, EEPROM identity, **Current firmware:** `0.8.5` BT1035 I2S slave boot init, dual OTA + DSP blob updates, EEPROM identity,
NVS + flash encryption (dev mode), tabbed Web UI with System uploads, CI gate NVS + flash encryption (dev mode), tabbed Web UI with System uploads, CI gate
(4 jobs). (4 jobs).
@@ -14,7 +14,7 @@ NVS + flash encryption (dev mode), tabbed Web UI with System uploads, CI gate
--- ---
## Completed agent tasks (T1T12, fw 0.7.10.8.4) ## Completed agent tasks (T1T12, fw 0.7.10.8.5)
| Task | Version | Summary | | Task | Version | Summary |
|------|---------|---------| |------|---------|---------|
@@ -31,6 +31,10 @@ NVS + flash encryption (dev mode), tabbed Web UI with System uploads, CI gate
| **T11** | 0.8.4 | Updatable ADAU1701 program — `POST /api/dsp/program`, DRAD blob | | **T11** | 0.8.4 | Updatable ADAU1701 program — `POST /api/dsp/program`, DRAD blob |
| **T12** | 0.8.4 | ESP32 OTA — `POST /api/system/ota`, rollback confirm on boot | | **T12** | 0.8.4 | ESP32 OTA — `POST /api/system/ota`, rollback confirm on boot |
**0.8.5** (hardware/doc alignment): BT1035 boot uses `AT+AUXCFG=3` +
`AT+I2SCFG=67` (I2S from ADAU1701, not Line-In); I2C pull-ups R1/R16
confirmed 2\,kΩ; `Hardware/DATASHEET/` bundle + manual cross-refs.
Also landed (not numbered): BT1035 pairing (`BluetoothService`), station presets Also landed (not numbered): BT1035 pairing (`BluetoothService`), station presets
(fw 0.7.0), companion-chip boot (Slice 3), ADAU1701 runtime (Slice 5). (fw 0.7.0), companion-chip boot (Slice 3), ADAU1701 runtime (Slice 5).
@@ -62,13 +66,14 @@ a sacrificial unit; confirm RELEASE mode policy before shipping.
## Open firmware polish (non-blocking) ## Open firmware polish (non-blocking)
Done in fw 0.8.4 unless noted: Done in fw 0.8.5 unless noted:
- FM seek down — `POST /api/tuner/seek` with `{"direction":"down"}`. - BT1035 boot — I2S slave init (`AT+AUXCFG=3`, `AT+I2SCFG=67`) per PCB routing (0.8.5).
- FM seek down — `POST /api/tuner/seek` with `{"direction":"down"}` (0.8.4).
- BT1035 — query/set name, paired list (`AT+PLIST`), auto-reconnect - BT1035 — query/set name, paired list (`AT+PLIST`), auto-reconnect
(`AT+AUTOCONN`) per Feasycom BT1035 manual. (`AT+AUTOCONN`) per Feasycom BT1035 manual (0.8.4).
- Si4684 — `STOP_DIGITAL_SERVICE` (0x82) before FM band switch when DAB - Si4684 — `STOP_DIGITAL_SERVICE` (0x82) before FM band switch when DAB
audio is active; ensemble metrics remain via `DAB_DIGRAD_STATUS` in status. audio is active; ensemble metrics remain via `DAB_DIGRAD_STATUS` in status (0.8.4).
--- ---
+2 -2
View File
@@ -6,7 +6,7 @@ implemented in \texttt{SetupWebServer}. Request bodies are parsed into
domain types in the pure core (\texttt{components/core}) before any domain types in the pure core (\texttt{components/core}) before any
persistence or driver call. Exact C++ signatures live in the generated persistence or driver call. Exact C++ signatures live in the generated
Doxygen output under \texttt{docs/api/}; this chapter documents the Doxygen output under \texttt{docs/api/}; this chapter documents the
wire protocol and behaviour as shipped in firmware~0.8.4. wire protocol and behaviour as shipped in firmware~0.8.5.
\section{Transport and reachability} \section{Transport and reachability}
@@ -36,7 +36,7 @@ Returns a health-check DTO serialised by
\begin{drnote}[Response schema] \begin{drnote}[Response schema]
\begin{drcode}[JSON] \begin{drcode}[JSON]
{"status":"ok","fw":"0.8.4","serialNumber":"0004A3123456", {"status":"ok","fw":"0.8.5","serialNumber":"0004A3123456",
"chips":{"si4684":true,"adau1701":true,"bt1035":true}} "chips":{"si4684":true,"adau1701":true,"bt1035":true}}
\end{drcode} \end{drcode}
\begin{itemize} \begin{itemize}
+59 -40
View File
@@ -9,8 +9,8 @@ The Feasycom FSC-BT1035 (Qualcomm QCC3056) is the wireless output stage of
DigiRadio: it receives PCM from the ADAU1701 over I\textsuperscript{2}S and DigiRadio: it receives PCM from the ADAU1701 over I\textsuperscript{2}S and
streams Bluetooth audio with aptX, aptX~HD, and aptX~Adaptive. This chapter streams Bluetooth audio with aptX, aptX~HD, and aptX~Adaptive. This chapter
documents how the ESP32-S3 controls the module over UART (AT commands with documents how the ESP32-S3 controls the module over UART (AT commands with
RTS/CTS), why Line-In mode is mandatory, and how \texttt{bt1035::Bt1035Driver} RTS/CTS), why I\textsuperscript{2}S slave mode is mandatory, and how
implements the bring-up sequence. \texttt{bt1035::Bt1035Driver} implements the bring-up sequence.
\begin{drref}[Hardware context] \begin{drref}[Hardware context]
Board wiring (UART pins, I\textsuperscript{2}S to the module, flow control) Board wiring (UART pins, I\textsuperscript{2}S to the module, flow control)
@@ -29,9 +29,10 @@ samples for Bluetooth; it only configures the module so the wired path is
accepted and encoded for transmission. accepted and encoded for transmission.
Without firmware init the module may stay in a default mode that ignores the Without firmware init the module may stay in a default mode that ignores the
Line-In from the DSP. The mandatory \texttt{AT+AUXCFG=1} command selects I\textsuperscript{2}S bus from the ADAU1701. The mandatory
auxiliary/Line-In input --- omitting it silently breaks the entire wireless \texttt{AT+AUXCFG=3} and \texttt{AT+I2SCFG=67} commands select I\textsuperscript{2}S
output (Section~\ref{sec:bt1035-linein}). slave input at 48\,kHz --- omitting them silently breaks the entire wireless
output (Section~\ref{sec:bt1035-i2s}).
\section{Control interface} \section{Control interface}
\label{sec:bt1035-uart} \label{sec:bt1035-uart}
@@ -67,17 +68,19 @@ Every command expects a module reply containing \texttt{OK} or
\end{itemize} \end{itemize}
Host tests in \texttt{components/core/test/bt1035\_at\_test.cpp} lock the Host tests in \texttt{components/core/test/bt1035\_at\_test.cpp} lock the
init sequence (including \texttt{AT+AUXCFG=1}) and the parser. init sequence (\texttt{AT+AUXCFG=3}, \texttt{AT+I2SCFG=67}) and the parser.
\section{Mandatory Line-In mode} \section{Mandatory I\textsuperscript{2}S slave mode}
\label{sec:bt1035-linein} \label{sec:bt1035-i2s}
\begin{drcaution}[AT+AUXCFG=1 is not optional] \begin{drcaution}[I\textsuperscript{2}S init is not optional]
The documented init sequence must include \texttt{AT+AUXCFG=1} after a The board routes ADAU1701 \texttt{SDATA\_OUT0} (MP6) to the module PCM input
successful \texttt{AT} ping. This tells the QCC3056 firmware to take audio with shared BCLK/LRCLK (see Chapter~\ref{ch:hardware}). The init sequence
from the wired I\textsuperscript{2}S/Line-In port (the ADAU1701 output) must therefore use \texttt{AT+AUXCFG=3} (I\textsuperscript{2}S mode per
rather than an internal source. AGENTS.md and the hardware manual both treat programming guide §5.1.25) followed by \texttt{AT+I2SCFG=67} (I\textsuperscript{2}S
skipping this step as a production bug. slave, 48\,kHz, 32-bit per §5.1.4). \texttt{AT+AUXCFG=1} (Line-In) does
\textbf{not} match the schematic. AGENTS.md treats skipping I\textsuperscript{2}S
init as a production bug.
\end{drcaution} \end{drcaution}
\section{Boot sequence} \section{Boot sequence}
@@ -85,7 +88,7 @@ skipping this step as a production bug.
At power-up \texttt{HardwareBootstrap::boot()} runs the Si4684 and ADAU1701 At power-up \texttt{HardwareBootstrap::boot()} runs the Si4684 and ADAU1701
first, applies the saved audio profile, then initialises the BT1035 so the first, applies the saved audio profile, then initialises the BT1035 so the
Line-In path is ready before Wi-Fi starts. I\textsuperscript{2}S path is ready before Wi-Fi starts.
\begin{figure}[htbp] \begin{figure}[htbp]
\centering \centering
@@ -99,10 +102,12 @@ Line-In path is ready before Wi-Fi starts.
\node[drstep, fill=black!8, below=of uart] (at) \node[drstep, fill=black!8, below=of uart] (at)
{Send \texttt{AT} --- expect OK}; {Send \texttt{AT} --- expect OK};
\node[drstep, fill=black!10, below=of at] (aux) \node[drstep, fill=black!10, below=of at] (aux)
{Send \texttt{AT+AUXCFG=1} --- expect OK (Line-In)}; {Send \texttt{AT+AUXCFG=3} --- expect OK (I\textsuperscript{2}S)};
\node[drstep, fill=black!6, below=of aux] (done) \node[drstep, fill=black!10, below=of aux] (i2s)
{Send \texttt{AT+I2SCFG=67} --- expect OK (slave 48\,kHz)};
\node[drstep, fill=black!6, below=of i2s] (done)
{\texttt{Bt1035Driver::isBooted()} = true}; {\texttt{Bt1035Driver::isBooted()} = true};
\foreach \a/\b in {sys/uart, uart/at, at/aux, aux/done} { \foreach \a/\b in {sys/uart, uart/at, at/aux, aux/i2s, i2s/done} {
\draw[->] (\a) -- (\b); \draw[->] (\a) -- (\b);
} }
\end{tikzpicture} \end{tikzpicture}
@@ -112,7 +117,7 @@ Line-In path is ready before Wi-Fi starts.
Pairing, codec selection, and volume over Bluetooth are handled by the Pairing, codec selection, and volume over Bluetooth are handled by the
module's own firmware and NVS; DigiRadio firmware currently implements module's own firmware and NVS; DigiRadio firmware currently implements
only the Line-In bring-up required for the wired audio path. only the I\textsuperscript{2}S bring-up required for the wired audio path.
\section{Software architecture} \section{Software architecture}
\label{sec:bt1035-stack} \label{sec:bt1035-stack}
@@ -139,30 +144,38 @@ only the Line-In bring-up required for the wired audio path.
\section{Supported AT command subset} \section{Supported AT command subset}
\label{sec:bt1035-at} \label{sec:bt1035-at}
The firmware enumerates every command it sends. Extending the subset requires The firmware enumerates every command it sends. Wire formats follow
updating \texttt{core::Bt1035AtCommand}, the manual, and a host test. \texttt{Hardware/DATASHEET/FSC-BT1035\_programming\_user\_guide\_1.1.1.pdf}
(§5 commands, §6 events). Extending the subset requires updating
\texttt{core::Bt1035AtCommand}, the manual, and a host test.
\begin{table}[htbp] \begin{table}[htbp]
\centering \centering
\begin{tabular}{@{}lll@{}} \small
\drhead Enum & Line sent & Purpose \\ \begin{tabular}{@{}llp{5.2cm}@{}}
\drhead Enum & Line sent & Programming guide \\
\midrule \midrule
\texttt{Ping} & \texttt{AT} & Verify UART link \\ \texttt{Ping} & \texttt{AT} & link check \\
\texttt{AuxLineIn} & \texttt{AT+AUXCFG=1} & Enable Line-In from ADAU \\ \texttt{I2sMode} & \texttt{AT+AUXCFG=3} & §5.1.25 Param=3 I2S \\
\texttt{PairDiscoverable} & \texttt{AT+PAIR=1} & Enter discoverable mode \\ \texttt{I2sSlave48k32} & \texttt{AT+I2SCFG=67} & §5.1.4 slave 48\,kHz 32-bit \\
\texttt{PairHidden} & \texttt{AT+PAIR=0} & Leave discoverable mode \\ \texttt{PairDiscoverable} & \texttt{AT+PAIR=1} & §5.1.20 enter discoverable \\
\texttt{A2dpStat} & \texttt{AT+A2DPSTAT} & Read link state \\ \texttt{PairHidden} & \texttt{AT+PAIR=0} & §5.1.20 leave discoverable \\
\texttt{A2dpDisconnect} & \texttt{AT+A2DPDISC} & Release A2DP session \\ \texttt{A2dpStat} & \texttt{AT+A2DPSTAT} & §5.3.1; states 1--5 \\
\texttt{QueryName} & \texttt{AT+NAME} & Read module friendly name \\ \texttt{A2dpDisconnect} & \texttt{AT+A2DPDISC} & §5.3.3 \\
\texttt{QueryAutoConn} & \texttt{AT+AUTOCONN} & Read auto-reconnect count \\ \texttt{QueryName} & \texttt{AT+NAME} & §5.1.16 read \texttt{+NAME=} \\
\texttt{QueryPairedList} & \texttt{AT+PLIST} & List paired remotes \\ \texttt{QueryAutoConn} & \texttt{AT+AUTOCONN} & §5.1.11 read \texttt{+AUTOCONN=} \\
\texttt{QueryPairedList} & \texttt{AT+PLIST} & §5.1.22; ends with \texttt{+PLIST=E} \\
\bottomrule \bottomrule
\end{tabular} \end{tabular}
\caption{Enumerated AT commands (\texttt{core::Bt1035AtCommand}). Boot \caption{Enumerated AT commands (\texttt{core::Bt1035AtCommand}). Boot
uses Ping + AuxLineIn only; pairing commands are runtime.} uses Ping + I2sMode + I2sSlave48k32; pairing commands are runtime.}
\label{tab:bt1035-at} \label{tab:bt1035-at}
\end{table} \end{table}
Boot also calls \texttt{AT+NAME=<identity>,0} and \texttt{AT+AUTOCONN=3}
from \texttt{hardware\_bootstrap.cpp} (§5.1.16 suffix disabled, §5.1.11
reconnect count).
\section{Bt1035Driver API} \section{Bt1035Driver API}
\label{sec:bt1035-driver} \label{sec:bt1035-driver}
@@ -176,7 +189,7 @@ updating \texttt{core::Bt1035AtCommand}, the manual, and a host test.
\textbf{Method} & \textbf{Purpose} \\ \textbf{Method} & \textbf{Purpose} \\
\midrule \midrule
\texttt{boot()} & Reset, UART init, run \texttt{bootInitSequence()} \\ \texttt{boot()} & Reset, UART init, run \texttt{bootInitSequence()} \\
\texttt{isBooted()} & \texttt{true} after Line-In init succeeded \\ \texttt{isBooted()} & \texttt{true} after I\textsuperscript{2}S init succeeded \\
\texttt{sendCommand(cmd)} & Send one typed command, expect OK \\ \texttt{sendCommand(cmd)} & Send one typed command, expect OK \\
\texttt{enterPairingMode()} & \texttt{AT+PAIR=1} \\ \texttt{enterPairingMode()} & \texttt{AT+PAIR=1} \\
\texttt{leavePairingMode()} & \texttt{AT+PAIR=0} \\ \texttt{leavePairingMode()} & \texttt{AT+PAIR=0} \\
@@ -226,19 +239,22 @@ Boot order:
\item Si4684 \texttt{boot(Dab)} --- tuner image in RAM. \item Si4684 \texttt{boot(Dab)} --- tuner image in RAM.
\item ADAU1701 \texttt{boot()} --- SigmaStudio program in RAM. \item ADAU1701 \texttt{boot()} --- SigmaStudio program in RAM.
\item \texttt{AudioService::loadAndApply()} --- user mixer/EQ profile. \item \texttt{AudioService::loadAndApply()} --- user mixer/EQ profile.
\item BT1035 \texttt{boot()} --- Line-In enabled for wireless output. \item BT1035 \texttt{boot()} --- I\textsuperscript{2}S slave enabled for wireless output.
\end{enumerate} \end{enumerate}
\section{Typical usage (firmware developer)} \section{Typical usage (firmware developer)}
\label{sec:bt1035-usage} \label{sec:bt1035-usage}
After a successful \texttt{HardwareBootstrap::boot()}, the module is ready; After a successful \texttt{HardwareBootstrap::boot()}, the module is ready;
no further calls are required for basic listening. To re-send Line-In config no further calls are required for basic listening. To re-send I\textsuperscript{2}S config
after a module reset: after a module reset:
\begin{verbatim} \begin{verbatim}
bt1035::Bt1035Driver& bt = ...; bt1035::Bt1035Driver& bt = ...;
if (auto r = bt.sendCommand(core::Bt1035AtCommand::AuxLineIn); !r) { if (auto r = bt.sendCommand(core::Bt1035AtCommand::I2sMode); !r) {
// handle Bt1035Error
}
if (auto r = bt.sendCommand(core::Bt1035AtCommand::I2sSlave48k32); !r) {
// handle Bt1035Error // handle Bt1035Error
} }
\end{verbatim} \end{verbatim}
@@ -247,9 +263,12 @@ if (auto r = bt.sendCommand(core::Bt1035AtCommand::AuxLineIn); !r) {
\label{sec:bt1035-reading} \label{sec:bt1035-reading}
\begin{itemize} \begin{itemize}
\item Feasycom FSC-BT1035 AT command manual (vendor) --- full command set; \item \texttt{Hardware/DATASHEET/FSC-BT1035\_programming\_user\_guide\_1.1.1.pdf}
firmware wraps name, paired list, and auto-reconnect for the Web UI. --- authoritative AT command and event reference (§5--§6).
\item \texttt{Hardware/DATASHEET/FSC-BT1035\_Datasheet\_EN.pdf} --- module
electrical and pinout specification.
\item Chapter~\ref{ch:hardware} --- pin map and I\textsuperscript{2}S routing. \item Chapter~\ref{ch:hardware} --- pin map and I\textsuperscript{2}S routing.
\item Chapter~\ref{ch:adau1701} --- DSP output that feeds the module. \item Chapter~\ref{ch:adau1701} --- DSP output that feeds the module.
\item \texttt{components/core/test/bt1035\_at\_test.cpp} --- init sequence test. \item \texttt{components/core/test/bt1035\_at\_test.cpp} --- init sequence
and parser host tests.
\end{itemize} \end{itemize}
+3 -2
View File
@@ -16,7 +16,7 @@ added in the same change that introduces the class. A tooling check keeps
this chapter in step with the code, so it is always current. this chapter in step with the code, so it is always current.
\end{drnote} \end{drnote}
The class reference tracks firmware~0.8.4 on \texttt{main}. Public classes The class reference tracks firmware~0.8.5 on \texttt{main}. Public classes
are grouped by layer: domain core, application services, and hardware drivers. are grouped by layer: domain core, application services, and hardware drivers.
% ------------------------------------------------------------------ % ------------------------------------------------------------------
@@ -163,7 +163,8 @@ index (1--8), 12-digit MAC, and optional friendly name. Parsed by
\section{Bt1035Driver}\label{cls:Bt1035Driver} \section{Bt1035Driver}\label{cls:Bt1035Driver}
UART driver for the FSC-BT1035 (Chapter~\ref{ch:bt1035}). \texttt{boot()} UART driver for the FSC-BT1035 (Chapter~\ref{ch:bt1035}). \texttt{boot()}
pulses RESET\#, opens UART2 with RTS/CTS, and runs pulses RESET\#, opens UART2 with RTS/CTS, and runs
\texttt{core::bootInitSequence()} (Ping + \texttt{AT+AUXCFG=1}). Returns \texttt{core::bootInitSequence()} (Ping + \texttt{AT+AUXCFG=3} +
\texttt{AT+I2SCFG=67}). Returns
\texttt{Bt1035Error} on timeout, ERROR response, or UART failure. \texttt{Bt1035Error} on timeout, ERROR response, or UART failure.
\section{Adau1701Driver}\label{cls:Adau1701Driver} \section{Adau1701Driver}\label{cls:Adau1701Driver}
+6 -4
View File
@@ -150,9 +150,10 @@ safeload registers.
\paragraph{FSC-BT1035 (Bluetooth).} \paragraph{FSC-BT1035 (Bluetooth).}
The module is controlled by AT commands over UART with hardware flow control. The module is controlled by AT commands over UART with hardware flow control.
The initialisation sequence includes enabling Line-In mode The initialisation sequence includes enabling I\textsuperscript{2}S slave mode
(\texttt{AT+AUXCFG=1}), which is required for the wired audio path from the (\texttt{AT+AUXCFG=3} and \texttt{AT+I2SCFG=67}), which is required for the
DSP; command responses are parsed explicitly, with timeouts treated as errors. wired digital audio path from the ADAU1701 to the module.
Command responses are parsed explicitly, with timeouts treated as errors.
Full driver API, boot flow, and error codes are in Chapter~\ref{ch:bt1035}. Full driver API, boot flow, and error codes are in Chapter~\ref{ch:bt1035}.
\section{Configuration, storage, and user interface} \section{Configuration, storage, and user interface}
@@ -216,7 +217,8 @@ bring-up:
restores the saved \texttt{core::AudioProfile} from NVS (or factory restores the saved \texttt{core::AudioProfile} from NVS (or factory
defaults) via ADAU1701 safeload before network bring-up. defaults) via ADAU1701 safeload before network bring-up.
\item \textbf{FSC-BT1035} (UART): \texttt{bt1035::Bt1035Driver::boot()} \item \textbf{FSC-BT1035} (UART): \texttt{bt1035::Bt1035Driver::boot()}
enables Line-In (\texttt{AT+AUXCFG=1}) after the DSP path is configured enables I\textsuperscript{2}S slave mode (\texttt{AT+AUXCFG=3},
\texttt{AT+I2SCFG=67}) after the DSP path is configured
(Chapter~\ref{ch:bt1035}). (Chapter~\ref{ch:bt1035}).
\end{enumerate} \end{enumerate}
+40 -29
View File
@@ -128,11 +128,11 @@ control (RTS/CTS). The host sends commands and parses the module's
responses explicitly, treating timeouts as errors. Some settings are held responses explicitly, treating timeouts as errors. Some settings are held
in the module's own non-volatile memory. in the module's own non-volatile memory.
\begin{drcaution}[Line-In mode] \begin{drcaution}[I\textsuperscript{2}S slave mode]
The initialisation sequence must enable Line-In mode (\texttt{AT+AUXCFG=1}) The PCB routes ADAU1701 \texttt{SDATA\_OUT0} to the module over
so the module accepts the wired audio coming from the DSP. Omitting it I\textsuperscript{2}S (BCLK, LRCLK, PCM data). Firmware must initialise
silently breaks the audio path. Driver boot flow and AT subset are documented \texttt{AT+AUXCFG=3} and \texttt{AT+I2SCFG=67}, not Line-In
in Chapter~\ref{ch:bt1035}. (\texttt{AT+AUXCFG=1}). See Chapter~\ref{ch:bt1035}, Section~\ref{sec:bt1035-i2s}.
\end{drcaution} \end{drcaution}
\section{The host: ESP32-S3} \section{The host: ESP32-S3}
@@ -379,16 +379,19 @@ satisfying the +10\,\textmu s requirement in practice.
INTB & interrupt line, external pull-up (GPIO39) & verified \\ INTB & interrupt line, external pull-up (GPIO39) & verified \\
\bottomrule \bottomrule
\end{tabular} \end{tabular}
\caption{Si4684 design checks. References: Si4684-A10 datasheet \caption{Si4684 design checks. References:
(power sequencing, SPI, supply levels) and AN851 (bypass and layout).} \texttt{Hardware/DATASHEET/SI4684-A10.pdf} (power sequencing, SPI,
supply levels) and \texttt{Hardware/DATASHEET/AN851.pdf} (bypass and layout).}
\label{tab:hw-val-si4684} \label{tab:hw-val-si4684}
\end{table} \end{table}
\begin{drref}[Datasheet] \begin{drref}[Datasheet]
Power sequencing and SPI framing: Si4684-A10 data sheet. The user must not Power sequencing and SPI framing:
pulse SSB high between bytes; SSB frames the whole command/reply. \texttt{Hardware/DATASHEET/SI4684-A10.pdf}. The user must not pulse SSB high
Bypass-capacitor values and placement: AN851, \emph{Si468x Schematic and between bytes; SSB frames the whole command/reply.
Layout Guide}. Boot and command protocol: AN649. Bypass-capacitor values and placement: \texttt{Hardware/DATASHEET/AN851.pdf},
\emph{Si468x Schematic and Layout Guide}. Boot and command protocol: AN649.
Local copies: \texttt{Hardware/DATASHEET/} (see \texttt{README.md}).
\end{drref} \end{drref}
The core, memory, and analogue rails run at 1.8\,V; only VIO is at 3.3\,V The core, memory, and analogue rails run at 1.8\,V; only VIO is at 3.3\,V
@@ -419,7 +422,7 @@ locks up when input data arrives.
Output master & serial output port in Master Mode & verified \\ Output master & serial output port in Master Mode & verified \\
MCLK ratio & exactly 256\,$\times$\,f\textsubscript{S} & verified \\ MCLK ratio & exactly 256\,$\times$\,f\textsubscript{S} & verified \\
MCLK value & 12.288\,MHz oscillator (256\,$\times$\,48\,kHz) & verified \\ MCLK value & 12.288\,MHz oscillator (256\,$\times$\,48\,kHz) & verified \\
I\textsuperscript{2}C pull-ups & 2.2\,k\(\Omega\) on SDA and SCL & to verify \\ I\textsuperscript{2}C pull-ups & 2\,k\(\Omega\) on SDA/SCL (R16/R1) & verified \\
I\textsuperscript{2}C address & 0x34 (ADDR0 = ADDR1 = GND) & verified \\ I\textsuperscript{2}C address & 0x34 (ADDR0 = ADDR1 = GND) & verified \\
Self-boot & disabled (host RAM load) & verified \\ Self-boot & disabled (host RAM load) & verified \\
\bottomrule \bottomrule
@@ -430,17 +433,18 @@ locks up when input data arrives.
\end{table} \end{table}
\begin{drref}[Datasheet] \begin{drref}[Datasheet]
Master-clock loopback and serial-port modes: ADAU1701 data sheet, Rev.~C, Master-clock loopback and serial-port modes:
Table~63 and the serial-port section. The master clock must be exactly \texttt{Hardware/DATASHEET/adau1701.pdf}, Rev.~C, Table~63 and the serial-port
256\,$\times$\,f\textsubscript{S}. I\textsuperscript{2}C lines require section. The master clock must be exactly 256\,$\times$\,f\textsubscript{S}.
2.2\,k\(\Omega\) pull-ups. I\textsuperscript{2}C lines require pull-up resistors on SDA and SCL.
DigiRadio uses \textbf{2\,k\(\Omega\)} (schematic R1/R16; ADAU1701 datasheet
recommends 2.2\,k\(\Omega\) --- acceptable at 3.3\,V).
\end{drref} \end{drref}
\begin{drcaution}[Open item --- I\textsuperscript{2}C pull-ups] \begin{drnote}[I\textsuperscript{2}C pull-ups confirmed]
The ADAU1701 datasheet requires 2.2\,k\(\Omega\) pull-up resistors on SDA Schematic \texttt{DigitalRadio.pdf} and BOM list R1 (SCL) and R16 (SDA) as
and SCL. Confirm these are present on the board (shared bus with the 2\,k\(\Omega\) to 3V3 on the shared ADAU1701/EEPROM bus.
EEPROM); this is the one ADAU check still to close. \end{drnote}
\end{drcaution}
\subsection{FSC-BT1035 (QCC3056)} \subsection{FSC-BT1035 (QCC3056)}
\label{sec:hw-val-bt1035} \label{sec:hw-val-bt1035}
@@ -452,17 +456,24 @@ EEPROM); this is the one ADAU check still to close.
\drhead Check & Requirement & Status \\ \drhead Check & Requirement & Status \\
\midrule \midrule
UART with flow control & TX/RX + RTS/CTS wired & verified \\ UART with flow control & TX/RX + RTS/CTS wired & verified \\
Line-In enable (firmware) & \texttt{AT+AUXCFG=1} in init & driver rule \\ I\textsuperscript{2}S init (firmware) & \texttt{AT+AUXCFG=3}, \texttt{AT+I2SCFG=67} & driver rule \\
I\textsuperscript{2}S input & receives clocks from ADAU master (slave) & verified \\ I\textsuperscript{2}S input & receives clocks from ADAU master (slave) & verified \\
Reset line & RESET (GPIO17) driven by ESP32 & verified \\ Reset line & RESET (GPIO17) driven by ESP32 & verified \\
\bottomrule \bottomrule
\end{tabular} \end{tabular}
\caption{FSC-BT1035 design checks. The module is an I\textsuperscript{2}S \caption{FSC-BT1035 design checks. Datasheet:
slave fed by the ADAU master; audio arrives on its I\textsuperscript{2}S \texttt{Hardware/DATASHEET/FSC-BT1035\_Datasheet\_EN.pdf}; AT commands:
input pins.} \texttt{FSC-BT1035\_programming\_user\_guide\_1.1.1.pdf} §5.}
\label{tab:hw-val-bt1035} \label{tab:hw-val-bt1035}
\end{table} \end{table}
\begin{drref}[Programming guide defaults]
Module defaults (Feasycom release 1.1.1): BR/EDR name \texttt{FSC-BT1035},
UART 115200/8/N/1, SSP on, auto-reconnect configurable via
\texttt{AT+AUTOCONN=0..15}. DigiRadio overrides the name from EEPROM identity
(\texttt{AT+NAME=<name>,0} disables the module MAC suffix).
\end{drref}
\subsection{System-level summary} \subsection{System-level summary}
\label{sec:hw-val-summary} \label{sec:hw-val-summary}
@@ -474,7 +485,7 @@ EEPROM); this is the one ADAU check still to close.
Si4684 & RSTB pull-down, 1.8\,V rails, bypass caps, SPI & verified \\ Si4684 & RSTB pull-down, 1.8\,V rails, bypass caps, SPI & verified \\
Si4684 & RSTB release only in \texttt{Si4684Driver::boot()} & verified \\ Si4684 & RSTB release only in \texttt{Si4684Driver::boot()} & verified \\
ADAU1701 & clock loopback, master mode, 256$\times$f\textsubscript{S} & verified \\ ADAU1701 & clock loopback, master mode, 256$\times$f\textsubscript{S} & verified \\
ADAU1701 & I\textsuperscript{2}C 2.2\,k\(\Omega\) pull-ups & to verify \\ ADAU1701 & I\textsuperscript{2}C 2\,k\(\Omega\) pull-ups (R1/R16) & verified \\
FSC-BT1035 & UART + flow control, I\textsuperscript{2}S slave & verified \\ FSC-BT1035 & UART + flow control, I\textsuperscript{2}S slave & verified \\
Clocking & single 48\,kHz domain, ADAU master & verified \\ Clocking & single 48\,kHz domain, ADAU master & verified \\
\bottomrule \bottomrule
@@ -483,6 +494,6 @@ EEPROM); this is the one ADAU check still to close.
\label{tab:hw-val-summary} \label{tab:hw-val-summary}
\end{table} \end{table}
The only open hardware check is the presence of the 2.2\,k\(\Omega\) The consolidated pre-fabrication validation is complete for all
I\textsuperscript{2}C pull-ups on the ADAU/EEPROM bus. All damage-class damage-class items (Si4684 power sequencing and supply levels) and the
items (Si4684 power sequencing and supply levels) are verified. shared I\textsuperscript{2}C bus.
+1 -1
View File
@@ -4,7 +4,7 @@
DigiRadio is an open-source, high-fidelity digital radio receiver. It DigiRadio is an open-source, high-fidelity digital radio receiver. It
receives DAB+ and FM broadcasts, processes the audio through a dedicated receives DAB+ and FM broadcasts, processes the audio through a dedicated
signal processor, and streams the result over Bluetooth using a signal processor, and streams the result over Bluetooth using a
high-resolution codec. Firmware~0.8.4 on \texttt{main} provides encrypted high-resolution codec. Firmware~0.8.5 on \texttt{main} provides encrypted
storage, a tabbed configuration web UI, and the full REST API documented storage, a tabbed configuration web UI, and the full REST API documented
in Chapter~\ref{ch:api}. The whole project --- hardware and firmware --- is in Chapter~\ref{ch:api}. The whole project --- hardware and firmware --- is
released as open source for the maker and audio community to study, released as open source for the maker and audio community to study,
+1 -1
View File
@@ -30,7 +30,7 @@
\vfill \vfill
{\color{drInk}\large Michele Bigi\par} {\color{drInk}\large Michele Bigi\par}
\vspace{2mm} \vspace{2mm}
{\color{drGray}Firmware 0.8.4 \quad\textbullet\quad 2026\par} {\color{drGray}Firmware 0.8.5 \quad\textbullet\quad 2026\par}
\vspace{2mm} \vspace{2mm}
{\color{drGray}Hardware: CERN-OHL-S v2 \quad\textbullet\quad Firmware: Apache-2.0\par} {\color{drGray}Hardware: CERN-OHL-S v2 \quad\textbullet\quad Firmware: Apache-2.0\par}
\vspace{2mm} \vspace{2mm}
+3 -2
View File
@@ -4,7 +4,7 @@ Read this together with `AGENTS.md` and everything under
`.cursor/rules/`. Those define *how* to write code; this file defines `.cursor/rules/`. Those define *how* to write code; this file defines
*what we are building* and the current state on `main`. *what we are building* and the current state on `main`.
**Firmware on `main`:** **0.8.4** — agent tasks T1T12 complete; device HIL **Firmware on `main`:** **0.8.5** — agent tasks T1T12 complete; device HIL
pending PCB arrival. pending PCB arrival.
## What DigiRadio is ## What DigiRadio is
@@ -66,7 +66,8 @@ unless the user requests them.
- ESP-IDF `esp32s3`, C++23, `components/core` host-testable. - ESP-IDF `esp32s3`, C++23, `components/core` host-testable.
- SoftAP `DigiRadio-<suffix>` (or setup fallback), gzipped page, `GET /api/health`. - SoftAP `DigiRadio-<suffix>` (or setup fallback), gzipped page, `GET /api/health`.
- Health JSON includes `fw` (today **0.8.4**), `serialNumber`, companion-chip flags. - Health JSON includes `fw` (today **0.8.5**), `serialNumber`, companion-chip flags.
- BT1035 boot must send `AT+AUXCFG=3` and `AT+I2SCFG=67` (I2S from ADAU1701).
## Slice 2 — Secure store + Wi-Fi STA (complete) ## Slice 2 — Secure store + Wi-Fi STA (complete)