Implements GET /api/audio/levels, reading all six 1×RTA level-detector cells on demand (no background polling, no caching -- only runs when called, per explicit request this session). The read mechanism is the ADAU1701's documented Data Capture Register (address 2074/0x081A, datasheet Rev.0 pp.30,36: write a (program-step, register-select) pair to configure what the register mirrors, then read back a 3-byte 5.19 twos-complement value). The per-meter program- step indices are taken verbatim from SigmaStudio's own compiler output (Firmware/ADAU1701-Firmware/IC 1_DigiRadioFinale/net_list_out2/ trap.dat), not invented -- the datasheet explicitly says these indices must come from that compiler-generated file. Confirmed live: all six points return distinct, plausible dBFS values, and the output meters track a master-volume change. Also folds two pieces of live user feedback into the app brief: the volume slider should reach +12 dB (the firmware's real ceiling), not stop at 0 dB, and the new levels endpoint is what a "VU meter" UI section should poll instead of faking one. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
16 KiB
ADAU1701 SigmaStudio firmware — analisi completa registri, funzioni e API
Analisi del programma compilato in Firmware/ADAU1701-Firmware/ (DigiRadio_IC_1.h,
DigiRadio_IC_1_PARAM.h, DigiRadio_IC_1_REG.h, DigiRadio_NetList.xml), incrociato
con il driver firmware (components/drivers/adau1701/) e le API HTTP
(components/net/src/SetupWebServer.cpp). Ogni valore di indirizzo/registro citato è
letto direttamente dai file di export SigmaStudio, non inventato.
Questo documento descrive la revisione "DigiRadioFinale" (2026-08-25), che sostituisce il programma DSP precedente (74 parametri, mixer additivo) con uno molto più ricco (224 parametri) basato su un selettore di sorgente esclusivo invece di un mixer. §5 raccoglie anche i bug storici della revisione precedente, per riferimento.
1. Catena del segnale (da DigiRadio_NetList.xml)
Input1 (Si4684 L/R, ESP32 L/R) ──┬─▶ DCB1 (L radio) ─┐
├─▶ DCB2 (R radio) ─┼─▶ Compressor1 ─▶ 1×RTA1 (L) ─┐
├─▶ DCB4 (L esp32) ─┤ (stereo RMS) 1×RTA2 (R) ─┤
└─▶ DCB3 (R esp32) ─┘ 1×RTA3 (L) ─┤ (readback,
1×RTA4 (R) ─┤ ingresso)
Beep1 ─▶ S Splitter1 (mono→stereo) ─────────────────────────────────────────────────┤
▼
┌──────────────────┐
│ MX1 (mux) │
│ select = DC1 │
│ 0=Radio 1=BT │
│ 2=Beep (raw int!) │
└──────────────────┘
│
▼
Param EQ1 (6 bande, addr 59-88)
│
▼
SPhat1 (Spatializer, addr 89-140)
│
▼
Gen Filter1 (Voice Clarifier,
addr 141-145 — non tarato)
│
▼
Multiple1 (Master Volume,
addr 146-147)
│
▼
Bass Boost1 (Dynamic Bass Boost,
addr 148-187)
│
┌──────────┴──────────┐
▼ ▼
1×RTA1_2 (readback) 1×RTA2_2 (readback)
│ │
▼ ▼
Limiter1 (L) Limiter2 (R)
addr 209-223 addr 194-208
│ │
▼ ▼
Output1 Output2
(→ BT1035 I2S, L) (→ BT1035 I2S, R)
Cambio architetturale rispetto alla revisione precedente: non esiste più un
mixer che combina Si4684 + ESP32 + Beep simultaneamente. MX1 è un selettore
esclusivo: passa UNA SOLA delle tre coppie stereo alla volta, scelta scrivendo
DC1 (indirizzo 3). Non esistono più gain pre-mixer per sorgente (SI4674/ESP32
sono spariti) — il livello si controlla solo con Master Volume ed EQ, a valle
della selezione.
Scoperta empirica cruciale (2026-08-25): DC1 è dichiarato
SIGMASTUDIOTYPE_FIXPOINT nell'export compilato (che farebbe pensare al formato
5.23 usato da tutte le altre celle), ma MX1 legge invece un intero a 32 bit
grezzo. Scrivere 0x00800000 (= 1.0 in 5.23) non cambia la sorgente; scrivere
0x00000001 sì. Confermato dal vivo: 0=Radio, 1=Bluetooth(ESP32), 2=Beep. Vedi
adau1701::paramSourceIndex() e Adau1701Driver::selectSource().
2. Mappa completa dei registri Parameter RAM (224 indirizzi, 0-223)
| Indirizzi | Blocco | Funzione | Controllo runtime |
|---|---|---|---|
| 0-2 | BEEP1_* |
Tono di test interno | setBeepEnabled() (live-only) |
| 3 | DC1 |
Selettore sorgente per MX1 — intero grezzo, non 5.23 | selectSource() |
| 4-7 | DCB1-4_POLE |
DC blocker, uno per canale (radio L/R, esp32 L/R) | Fisso (compilato) |
| 8 | SSPLITTER1 |
Fan-out mono→stereo per Beep | Fisso |
| 9-46 | COMPRESSOR1_* |
Compressore RMS stereo (curva a 34 punti) su radio L/R | Fisso |
| 47-58 | 1XRTA3,4,1,2 |
4 VU-meter in ingresso (radio L/R, esp32 L/R) | Lettura via indirizzo speciale 2074 — meccanismo non ancora implementato in firmware |
| 59-88 | PARAMEQ1_ST0..5_* |
EQ parametrico, 6 bande × 5 coefficienti (B0,B1,B2,A0,A1) | setEqBand()/applyEq() |
| 89-140 | SPHAT1_* |
Spatializer (SuperPhat) — solo SPREAD1/SPREAD2 (139,140) sono la manopola di intensità; il resto (filtro crossover, tabella compander) è tarato in SigmaStudio |
setStereoSpreadLevel() — scala SPREAD1/2 proporzionalmente (0=nessuno spread aggiunto, 100=pieno) |
| 141-145 | GENFILTER1_ST0_* |
Voice Clarifier — ancora piatto/identità in questo export (b0=1, resto 0), non tarato | Non ancora implementato |
| 146-147 | MULTIPLE1, MULTIPLE1_1 |
Master Volume L/R | setMasterVolume() |
| 148-187 | BASSBOOST1_* |
Dynamic Bass Boost — BASSFREQUENCY/TIMECONSTANT fissi; filtro crossover (B0,B1,B2,A1,A2) e tabella compander a 33 punti (TABLE0-32) sono la parte "intensità" |
setBassBoostLevel() — scala filtro+tabella verso l'identità/unità (0=bypass piatto, 100=pieno compilato) |
| 188-193 | 1XRTA2_2,1_2 |
2 VU-meter in uscita (post Bass Boost, pre limiter) | Stesso meccanismo di lettura non ancora implementato |
| 194-208 | LIMITER2_* |
Limiter canale R (soglia indirizzo 205) | Fisso |
| 209-223 | LIMITER1_* |
Limiter canale L (soglia indirizzo 220) | Fisso |
Formato dati: fixed-point 5.23 per quasi tutte le celle (28 bit significativi,
sign-extend da bit 27 — vedi core::floatToFixpoint823()), eccetto DC1 che è
un intero grezzo a 32 bit (vedi sopra).
3. API HTTP e corrispondenza con i registri
| Endpoint | Metodo | Corpo | Cosa tocca | Persistenza | Testato dal vivo |
|---|---|---|---|---|---|
/api/audio/profile |
GET/PUT | active_source, master, eq[6], enhancements |
DC1, EQ 59-88, Master 146-147, Bass Boost/Spatializer via enhancements |
✅ | ✅ |
/api/audio/reset |
POST | — | AudioProfile::factoryDefault() (Radio, EQ piatto, enhancements 0) |
✅ | — |
/api/audio/stereo-enhance |
POST | {"level":0-100} |
SPHAT1_SPREAD1/2 (scala proporzionale) |
✅ | ✅ (effetto soggettivo/sottile) |
/api/audio/bass-enhance |
POST | {"level":0-100} |
BASSBOOST1_* filtro+tabella (scala verso identità) |
✅ | ✅ (confermato su radio, non su tono fisso — l'algoritmo è dinamico, reagisce a contenuto con dinamica reale) |
/api/audio/beep |
POST | {"enabled":true/false} |
BEEP1_ENABLE/KICK |
❌ (live-only, per design) | ✅ |
/api/audio/levels |
GET | — | legge live i 6 VU-meter (Data Capture Register 2074) | — (nessuna cache/polling) | ✅ |
/api/dsp/params |
GET | — | elenco statico nome→indirizzo (230 celle, incluse le 6 speciali readback) | — | ✅ |
/api/dsp/param |
PUT | {"name":"...","value":<float>} |
qualunque cella per nome — eccetto DC1, che qui va scritto già come intero puro, non tramite selectSource() |
❌ (live-only) | ✅ (sweep completo di 223/224 celle scrivibili, 0 errori) |
active_source accetta "radio", "bluetooth", "beep". Il vecchio campo
"mixer" (con si4684_left_db/esp32_left_db/mix_left_db ecc.) non esiste
più — non ha più senso dato che non c'è più un mixer da bilanciare.
Il campo "locked" per banda EQ (introdotto il 24/08 quando bass/stereo enhance
sovrascrivevano le bande EQ) ora è sempre false tranne la banda 0 (passa-alto
fisso): bass/stereo enhance non toccano più l'EQ, guidano direttamente Bass
Boost1/SPhat1.
4. VU-meter (readback) — implementato 2026-08-25
Le 6 celle 1×RTA* sono veri VU-meter (level detector) posizionati in 4 punti
d'ingresso e 2 punti d'uscita. Il loro valore NON sta al normale indirizzo
Parameter RAM di ciascuna — usano il Data Capture Register dell'ADAU1701
(indirizzo 2074/0x081A, datasheet Rev.0 pag. 30 e 36, Table 28/29/32/44/45):
- Si scrive un word di 16 bit a 2074: bit[11:2] = indice del passo di
programma (
PC[9:0]) dove campionare, bit[1:0] = quale registro interno del core trasferire (RS[1:0];10=MAC_out). - Si rilegge lo stesso indirizzo 2074: risponde con 3 byte (24 bit, complemento a due, formato 5.19 — il 5.23 interno con i 4 LSB troncati).
Gli indici PC[9:0] per ciascuno dei 6 meter non sono stati inventati:
vengono letti testualmente dal file che il compilatore SigmaStudio genera
apposta per questo (IC 1_DigiRadioFinale/net_list_out2/trap.dat):
| Meter | Punto | Program-step (trap.dat) |
|---|---|---|
1×RTA1 |
Radio L, post-compressore | 221 |
1×RTA2 |
Radio R, post-compressore | 254 |
1×RTA3 |
ESP32 L | 155 |
1×RTA4 |
ESP32 R | 188 |
1×RTA1_2 |
Uscita L (post Bass Boost1) | 717 |
1×RTA2_2 |
Uscita R (post Bass Boost1) | 684 |
Il chip ha solo 2 registri di cattura hardware (2074, 2075); il firmware
ne usa uno solo, riconfigurandolo e rileggendolo in sequenza per i 6 punti —
solo quando arriva una richiesta GET /api/audio/levels, nessun polling
in background. Testato dal vivo: valori plausibili e distinti per ciascun
punto, e l'uscita scende coerentemente abbassando il master volume.
Vedi Adau1701Driver::readLevels()/readCaptureDb() per l'implementazione.
5. Bug trovati e stato (cronologia)
| # | Sintomo | Causa reale | Stato |
|---|---|---|---|
| 1 | Mixer/volume/EQ salvati non sopravvivono MAI a un riavvio (revisione precedente) | NVS inizializzato dopo AudioService::loadAndApply() in app_main() |
✅ risolto 2026-08-24 |
| 2 | Mixer e master tornavano al preset "radio" a ogni riavvio anche dopo il fix #1 | HardwareBootstrap::boot() chiamava applyRadioFirstMix() incondizionatamente |
✅ risolto 2026-08-24 |
| 3 | Qualsiasi modifica EQ/enhancement diversa da zero → silenzio totale (anche sul tono di test) | Segno mancante in core::designPeakingEq(): i coefficienti di retroazione RBJ (sottrattivi) venivano scritti tali e quali nei registri A0/A1 dell'ADAU1701 (additivi) — retroazione positiva invece che negativa, il filtro divergeva su un valore costante (DC, inaudibile) |
✅ risolto 2026-08-25 — vedi components/core/src/BiquadDesign.cpp, test di stabilità in biquad_design_test.cpp |
| 4 | Bridge TCP SigmaStudio (porta 8086): accept() in loop infinito su EBADF da ogni boot |
SigmaStudioTcpServer::stop() cancellava incondizionatamente il singleton del socket attivo, anche quando chiamato sull'oggetto move-from (ogni boot ne crea uno) |
✅ risolto 2026-08-25 |
| 5 | Nuovo netlist DigiRadioFinale: nessun mixer, solo MX1 a selezione esclusiva |
Non è un bug — cambio di design intenzionale, confermato dall'utente | Documentato, non un bug |
| 6 | Scrivere DC1 in formato 5.23 (es. 1.0 = 0x00800000) non cambia la sorgente selezionata |
MX1 legge DC1 come intero grezzo, non fixpoint, nonostante TYPE_DC1 compilato dica SIGMASTUDIOTYPE_FIXPOINT |
✅ risolto 2026-08-25 — confermato dal vivo (0/1/2 → Radio/BT/Beep) |
| 7 | Fruscio persistente su radio e streaming (multi-giorno, revisione precedente) | Override IBP=1 su SerialInputRegister (0x81F), mai validato in isolamento |
✅ risolto 2026-08-24 |
6. Come testare manualmente
# Stato attuale
curl http://192.168.1.62/api/audio/profile
# Cambia sorgente
curl -X PUT http://192.168.1.62/api/audio/profile -d '{
"active_source": "bluetooth",
"master": {"left_db": 0, "right_db": 0},
"eq": [
{"gain_db": 0, "center_hz": 20, "q": 1.414},
{"gain_db": 0, "center_hz": 100, "q": 1},
{"gain_db": 0, "center_hz": 400, "q": 1},
{"gain_db": 0, "center_hz": 1000, "q": 1},
{"gain_db": 0, "center_hz": 3000, "q": 1},
{"gain_db": 0, "center_hz": 8000, "q": 1}
],
"enhancements": {"stereo_level": 0, "bass_level": 0}
}'
# Bass Boost / Spatializer
curl -X POST http://192.168.1.62/api/audio/bass-enhance -d '{"level":100}'
curl -X POST http://192.168.1.62/api/audio/stereo-enhance -d '{"level":100}'
Per leggere/scrivere una singola cella arbitraria (debug avanzato, non
persistente — non usare per DC1, che ha una semantica intero-grezzo
diversa da tutte le altre celle):
curl http://192.168.1.62/api/dsp/params # elenco nome→indirizzo (230 celle)
curl -X PUT http://192.168.1.62/api/dsp/param -d '{"name":"SPHAT1_SPREAD1","value":0.0629}'
7. Riferimenti file
| File | Contenuto |
|---|---|
Firmware/ADAU1701-Firmware/DigiRadio_IC_1_PARAM.h |
Sorgente di verità per tutti gli indirizzi Parameter RAM (export DigiRadioFinale) |
Firmware/ADAU1701-Firmware/DigiRadio_NetList.xml |
Topologia del segnale (chi è collegato a chi) |
components/core/include/core/ActiveSource.hpp |
Enum Radio/Bluetooth/Beep + nota sulla semantica intero-grezzo di DC1 |
components/drivers/adau1701/include/adau1701/Adau1701ParamTable.hpp |
Tabella nome→indirizzo generata da PARAM.h (230 celle) |
components/drivers/adau1701/include/adau1701/Adau1701ParamMap.hpp |
paramAddrEqBandBase(), paramSourceIndex() |
components/drivers/adau1701/src/Adau1701Driver.cpp |
selectSource(), applyEq(), setMasterVolume(), setBassBoostLevel(), setStereoSpreadLevel(), setBeepEnabled() |
components/core/src/BiquadDesign.cpp |
designPeakingEq() — fix del segno A0/A1 (2026-08-25) |
components/services/audio/src/AudioService.cpp |
loadAndApply(), applyRadioFirstMix(), selectSource(), enhancement plumbing |
docs/manual/ch-sigmastudio.tex §"Next revision: DigiRadioFinale" |
Diagramma e tabella indirizzi per il manuale PDF |