Fix Si4684 I2S audio: PIN_CONFIG_ENABLE conflict + ADAU1701 BCLK polarity
Two independent bugs silenced the digital audio path from Si4684 into the ADAU1701 even after the FM/DAB tune fix produced a real RF lock: 1. Si4684Driver::configureAfterBoot() wrote PIN_CONFIG_ENABLE (0x0800) as 0x0003, enabling both I2SOUTEN and DACOUTEN. AN649: "only I2SOUTEN or DACOUTEN can be enabled at a time. If both enabled, only analog audio output is enabled" — the chip silently fell back to its unused analog DAC output on every boot. Fixed to 0x8002 (I2SOUTEN + INTBOUTEN), matching the value hitech95/si468x_dab_receiver's working ALSA codec driver uses (SI468X_PROP_I2S_ENABLED); I2SOUTEN alone (0x0002) was not sufficient on this hardware. Also fixed AUDIO_OUTPUT_CONFIG (0x0302), which was being written with a stray I2S-enable bit that property does not have (its only real field is bit0 MONO). 2. Even with the chip correctly outputting I2S, the ADAU1701 received only static. Traced with SIGMA_WRITE_REGISTER_BLOCK live overrides of SerialInputRegister (0x081F, baked into the compiled SigmaStudio export at ILP=0/IBP=0): IBP=1 (input data clocked on the opposite BCLK edge) produced real, recognizable music instead of static on a locked, strong FM signal — first confirmed end-to-end audio in this project's history. ILP=1 made it worse and was reverted; IBP=1 kept as a runtime override in Adau1701Driver::boot(). Remaining noise on top of the music is attributed to antenna quality (RSSI/SNR fluctuated significantly between retunes of the same station on the current improvised antenna) — not yet confirmed with a proper antenna. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0178rASQ6ZETPMUamvpoR2KR
This commit is contained in:
@@ -158,6 +158,21 @@ namespace adau1701
|
|||||||
return replay;
|
return replay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SerialInputRegister (0x081F) override: bit3 IBP=1, matching the
|
||||||
|
// BCLK edge the Si4684's I2S output actually changes data on
|
||||||
|
// (compiled DSP program default is 0x00 = IBP=0, which produced
|
||||||
|
// pure static on a strong locked signal). ILP=1 was also tried
|
||||||
|
// (0x18) and made it worse (pure white noise again) — IBP alone
|
||||||
|
// (0x08) is the correct override, confirmed live: real, recognizable
|
||||||
|
// music instead of static/noise on a locked FM station.
|
||||||
|
{
|
||||||
|
const unsigned char deviceAddr =
|
||||||
|
static_cast<unsigned char>(pins_.i2cAddr7 << 1);
|
||||||
|
ADI_REG_TYPE serialInFix = 0x08U;
|
||||||
|
SIGMA_WRITE_REGISTER_BLOCK(deviceAddr, 0x081FU, 1U,
|
||||||
|
&serialInFix);
|
||||||
|
}
|
||||||
|
|
||||||
booted_ = true;
|
booted_ = true;
|
||||||
ESP_LOGI(kTag, "SigmaStudio program loaded");
|
ESP_LOGI(kTag, "SigmaStudio program loaded");
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -56,8 +56,11 @@ constexpr std::uint16_t kPropPinConfigEnable = 0x0800U;
|
|||||||
constexpr std::uint16_t kPropAudioVolume = 0x0300U;
|
constexpr std::uint16_t kPropAudioVolume = 0x0300U;
|
||||||
constexpr std::uint16_t kPropAudioMute = 0x0301U;
|
constexpr std::uint16_t kPropAudioMute = 0x0301U;
|
||||||
constexpr std::uint16_t kPropAudioOutputConfig = 0x0302U;
|
constexpr std::uint16_t kPropAudioOutputConfig = 0x0302U;
|
||||||
/** AN649 AUDIO_OUTPUT_CONFIG bit1 I2SOUTEN — required for I2S to ADAU1701. */
|
/** AN649 PIN_CONFIG_ENABLE bit1 I2SOUTEN + bit15 INTBOUTEN — matches the
|
||||||
constexpr std::uint16_t kSi4684I2sOutEnable = 0x0002U;
|
* value used by hitech95/si468x_dab_receiver's working ALSA codec driver
|
||||||
|
* (SI468X_PROP_I2S_ENABLED = 0x8002); INTBOUTEN alone (0x0002) was not
|
||||||
|
* sufficient to produce audio on real hardware in this project. */
|
||||||
|
constexpr std::uint16_t kSi4684I2sOutEnable = 0x8002U;
|
||||||
/** Si4684 volume: 0=mute, 63=max (AN649 AUDIO_ANALOG_VOLUME). */
|
/** Si4684 volume: 0=mute, 63=max (AN649 AUDIO_ANALOG_VOLUME). */
|
||||||
constexpr std::uint8_t kSi4684VolumeMax = 63U;
|
constexpr std::uint8_t kSi4684VolumeMax = 63U;
|
||||||
constexpr std::uint16_t kPropFmRdsConfig = 0x3C02U;
|
constexpr std::uint16_t kPropFmRdsConfig = 0x3C02U;
|
||||||
@@ -560,14 +563,21 @@ std::expected<void, Si4684Error> Si4684Driver::configureAfterBoot(
|
|||||||
!rate) {
|
!rate) {
|
||||||
return rate;
|
return rate;
|
||||||
}
|
}
|
||||||
if (auto pins = setProperty(kPropPinConfigEnable, 0x0003U); !pins) {
|
// AN649 Property 0x0800 PIN_CONFIG_ENABLE bit1=I2SOUTEN, bit0=DACOUTEN:
|
||||||
|
// "only I2SOUTEN or DACOUTEN can be enabled at a time. If both enabled,
|
||||||
|
// only analog audio output is enabled." We only wire I2S to the
|
||||||
|
// ADAU1701 (no DAC pins connected), so DACOUTEN must stay 0 or the chip
|
||||||
|
// silently falls back to analog-only and the I2S bus carries silence.
|
||||||
|
if (auto pins = setProperty(kPropPinConfigEnable, kSi4684I2sOutEnable);
|
||||||
|
!pins) {
|
||||||
return pins;
|
return pins;
|
||||||
}
|
}
|
||||||
if (auto mute = setProperty(kPropAudioMute, 0x0000U); !mute) {
|
if (auto mute = setProperty(kPropAudioMute, 0x0000U); !mute) {
|
||||||
return mute;
|
return mute;
|
||||||
}
|
}
|
||||||
if (auto outCfg = setProperty(kPropAudioOutputConfig, kSi4684I2sOutEnable);
|
// AN649 Property 0x0302 AUDIO_OUTPUT_CONFIG bit0=MONO (all other bits
|
||||||
!outCfg) {
|
// reserved, must be 0). Not an I2S enable — that lives at 0x0800 above.
|
||||||
|
if (auto outCfg = setProperty(kPropAudioOutputConfig, 0x0000U); !outCfg) {
|
||||||
return outCfg;
|
return outCfg;
|
||||||
}
|
}
|
||||||
if (auto vol = setProperty(kPropAudioVolume, kSi4684VolumeMax); !vol) {
|
if (auto vol = setProperty(kPropAudioVolume, kSi4684VolumeMax); !vol) {
|
||||||
|
|||||||
@@ -491,6 +491,80 @@ particular indices. **Next step**: sweep the full DAB frequency table (not
|
|||||||
just 7 samples) with a real antenna and confirm a lock the same way FM was
|
just 7 samples) with a real antenna and confirm a lock the same way FM was
|
||||||
confirmed.
|
confirmed.
|
||||||
|
|
||||||
|
## 2026-08-16 update: first real audio from Si4684 — ADAU1701 SerialInputRegister IBP polarity
|
||||||
|
|
||||||
|
After the FM_TUNE_FREQ/DAB_TUNE_FREQ fix above produced a real lock
|
||||||
|
(`locked:true`, RSSI +12 dBuV, SNR +13 dB on 98.3 MHz), the speaker was still
|
||||||
|
silent. This section covers debugging that separate problem — not a Si4684
|
||||||
|
RF issue, but the digital audio link from Si4684 into the ADAU1701.
|
||||||
|
|
||||||
|
**Audit trail, each step verified against a primary source, not assumed:**
|
||||||
|
|
||||||
|
1. Re-verified every Si4684 audio property against the AN649 page text:
|
||||||
|
`DIGITAL_IO_OUTPUT_SELECT`, `_SAMPLE_RATE`, `_FORMAT` (24-bit sample in
|
||||||
|
32-bit I2S slots), `AUDIO_MUTE` (unmuted), `AUDIO_OUTPUT_CONFIG` (was
|
||||||
|
incorrectly written with a stray bit — 0x0302's only real field is bit0
|
||||||
|
MONO, not an I2S enable; fixed to 0x0000). All correct.
|
||||||
|
2. `PIN_CONFIG_ENABLE` (0x0800): bit1 I2SOUTEN, bit0 DACOUTEN — AN649 states
|
||||||
|
"only I2SOUTEN or DACOUTEN can be enabled at a time; if both enabled, only
|
||||||
|
analog output is enabled." The driver was writing `0x0003` (both bits) —
|
||||||
|
the chip was falling back to its unused analog DAC output on every boot.
|
||||||
|
Fixed to I2SOUTEN-only. Cross-checked against
|
||||||
|
`hitech95/si468x_dab_receiver`'s ALSA codec driver
|
||||||
|
(`sound/soc/codecs/si468x.c`): their working value is
|
||||||
|
`SI468X_PROP_I2S_ENABLED = 0x8002` (I2SOUTEN + INTBOUTEN, bit15) — not
|
||||||
|
just `0x0002`. Adopted `0x8002`.
|
||||||
|
3. Traced the full ADAU1701 SigmaStudio netlist
|
||||||
|
(`Firmware/ADAU1701-Firmware/DigiRadio_NetList.xml`, generated export, not
|
||||||
|
guessed): Si4674 gain cell → St Mixer1 → PEQ1 → Master gain → Limiter →
|
||||||
|
Output, confirmed reachable and correctly addressed (`ADDR_SI4674`/
|
||||||
|
`ADDR_SI4674_1` come from the generated `DigiRadio_IC_1_PARAM.h`, not
|
||||||
|
hand-typed). Confirmed this whole downstream chain works independently —
|
||||||
|
both the Beep1 test tone and the web radio (ESP32) path were audible
|
||||||
|
through it before any Si4684 fix.
|
||||||
|
4. Checked `MpCfg0`/`MpCfg1` (ADAU1701 pin-mux registers, `DigiRadio_IC_1_REG.h`)
|
||||||
|
against the ADAU1701 datasheet (`Hardware/DATASHEET/adau1701.pdf`): MP0,
|
||||||
|
MP1, MP4, MP5 (SDATA_IN0/1, INPUT_LRCLK, INPUT_BCLK) are correctly
|
||||||
|
configured as "Serial data port" function, not left as GPIO.
|
||||||
|
5. Found a PCB net-name vs. silicon pin-name mismatch while tracing the
|
||||||
|
Si4684→ADAU1701 connection in `DigiRadio.kicad_pcb`: Si4684 (U6 pin 33)
|
||||||
|
lands on ADAU1701 (U9) physical pin 11, which the datasheet identifies as
|
||||||
|
MP0 (silicon channel SDATA_IN1) — the PCB net is *labeled* "SDATA_IN0",
|
||||||
|
which does not match the silicon function at that pin. Tested by
|
||||||
|
unmuting both the "Si4684" and "ESP32" mixer gain legs simultaneously
|
||||||
|
(`Si4674`/`ESP32` cells in the netlist) — this did not by itself fix
|
||||||
|
the silence, so the SigmaStudio channel assignment for `Input1` was not
|
||||||
|
actually the blocking issue (kept both legs unmuted as a harmless no-op
|
||||||
|
change of practice, not reverted).
|
||||||
|
6. **Root cause**: `SerialInputRegister` (ADAU1701 register 0x081F,
|
||||||
|
`Table 49` in the datasheet), which controls the serial input port's
|
||||||
|
clock polarities — `ILP` (bit4, LRCLK polarity) and `IBP` (bit3, BCLK
|
||||||
|
edge the input data changes/is clocked on). This register is baked into
|
||||||
|
the compiled SigmaStudio DSP program export and is not something the
|
||||||
|
ESP32 firmware wrote at runtime before now; its compiled value is the
|
||||||
|
default `0x00` (ILP=0, IBP=0). Added a diagnostic runtime override in
|
||||||
|
`Adau1701Driver::boot()` (via `SIGMA_WRITE_REGISTER_BLOCK`, the same
|
||||||
|
primitive the DSP program loader itself uses) to test alternate
|
||||||
|
polarities live, without touching the SigmaStudio project:
|
||||||
|
- `IBP=1` alone (`0x08`): **real, recognizable music** instead of pure
|
||||||
|
static on a locked, strong FM signal — first time ever.
|
||||||
|
- `ILP=1` added on top (`0x18`): made it worse (pure white noise again).
|
||||||
|
- Back to `IBP=1` alone (`0x08`): music confirmed again, though
|
||||||
|
inconsistently — RSSI/SNR fluctuated significantly between otherwise
|
||||||
|
identical retunes (SNR seen anywhere from 2 to 14 dB on the same
|
||||||
|
station), consistent with a marginal/improvised antenna connection
|
||||||
|
rather than a firmware regression. Kept `IBP=1` as the fix.
|
||||||
|
|
||||||
|
Fixed in `components/drivers/adau1701/src/Adau1701Driver.cpp`
|
||||||
|
(`SerialInputRegister` override after DSP program load) and
|
||||||
|
`components/drivers/si4684/src/Si4684Driver.cpp` (`PIN_CONFIG_ENABLE` =
|
||||||
|
`0x8002`, `AUDIO_OUTPUT_CONFIG` = `0x0000`).
|
||||||
|
|
||||||
|
**Status**: first confirmed end-to-end audio path (Si4684 → ADAU1701 →
|
||||||
|
BT1035 → Bluetooth speaker) in this project's history. Remaining noise on
|
||||||
|
top of the music is attributed to antenna quality, not yet independently
|
||||||
|
confirmed with a proper antenna — flagged as follow-up, not closed.
|
||||||
|
|
||||||
**Unrelated finding from the same session, logged for completeness**: BT1035
|
**Unrelated finding from the same session, logged for completeness**: BT1035
|
||||||
began failing boot deterministically (`no spontaneous UART bytes after
|
began failing boot deterministically (`no spontaneous UART bytes after
|
||||||
hardware reset`, then `AT init failed`) starting from this session, on both
|
hardware reset`, then `AT init failed`) starting from this session, on both
|
||||||
|
|||||||
Reference in New Issue
Block a user