Files
DigiRadio/Software/docs/adau1701-sigmastudio-analysis.md
micheleandClaude Sonnet 5 5d7d4919a0 Add live VU-meter readback via ADAU1701 Data Capture Register
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>
2026-08-25 22:33:09 +02:00

16 KiB
Raw Permalink Blame History

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):

  1. 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).
  2. 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