Si4684 RF investigation report; fix ADAU1701 I2C reliability under long safeload bursts
- Add docs/si4684-rf-investigation-report.md: full record of the FM/DAB no-lock investigation (crystal, front-end matching, ANTCAP sweep, continuity, leading EP solder-defect hypothesis, PCBWay report sent) plus the separate audio profile NVS bug found and partially fixed this session. - Fix sigma_i2c_write() (SigmaStudioFW.c): no retry on I2C failure meant a single transient NACK anywhere in a long safeload burst (EQ apply = ~55 sequential transactions) aborted the whole sequence. Added a 3-attempt retry. - Add granular failure logging (AudioService::applyProfileToDsp/persistProfile, Adau1701Driver::applyMixer/applyEq, NvsAudioProfileStore::saveProfile error codes) to isolate the remaining NVS-side audio profile save failure. - Si4684Driver::tuneFm gains an optional ANTCAP argument (default 0 = unchanged auto-tune behavior) used during this session's front-end matching sweep. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -241,12 +241,14 @@ namespace adau1701
|
||||
mixer.si4684Right);
|
||||
!result)
|
||||
{
|
||||
ESP_LOGW(kTag, "applyMixer: si4684 input safeload failed");
|
||||
return result;
|
||||
}
|
||||
if (auto result = setInputVolume(core::MixSource::Esp32, mixer.esp32Left,
|
||||
mixer.esp32Right);
|
||||
!result)
|
||||
{
|
||||
ESP_LOGW(kTag, "applyMixer: esp32 input safeload failed");
|
||||
return result;
|
||||
}
|
||||
if (auto result =
|
||||
@@ -254,10 +256,17 @@ namespace adau1701
|
||||
mixer.mixLeft);
|
||||
!result)
|
||||
{
|
||||
ESP_LOGW(kTag, "applyMixer: st0 safeload failed");
|
||||
return result;
|
||||
}
|
||||
return safeloadGain(static_cast<unsigned>(ADDR_STMIXER1_ST1_VOLUME),
|
||||
mixer.mixRight);
|
||||
if (auto result = safeloadGain(
|
||||
static_cast<unsigned>(ADDR_STMIXER1_ST1_VOLUME), mixer.mixRight);
|
||||
!result)
|
||||
{
|
||||
ESP_LOGW(kTag, "applyMixer: st1 safeload failed");
|
||||
return result;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::expected<void, Adau1701Error> Adau1701Driver::setEqBand(
|
||||
@@ -344,6 +353,8 @@ namespace adau1701
|
||||
if (auto result = setEqBand(*index, band.gain, band.center, band.q);
|
||||
!result)
|
||||
{
|
||||
ESP_LOGW(kTag, "applyEq: band %u safeload failed",
|
||||
static_cast<unsigned>(i));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "driver/i2c_master.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -135,9 +136,22 @@ static int sigma_i2c_write(unsigned int reg, const unsigned char* data,
|
||||
buf[0] = (unsigned char)((reg >> 8) & 0xFFU);
|
||||
buf[1] = (unsigned char)(reg & 0xFFU);
|
||||
memcpy(buf + 2U, data, length);
|
||||
const esp_err_t err =
|
||||
i2c_master_transmit(s_dev, buf, (size_t)(2U + length), 1000);
|
||||
return err == ESP_OK ? 0 : -1;
|
||||
|
||||
// Long safeload sequences (e.g. one EQ band = 5 params x 2 writes +
|
||||
// trigger) chain dozens of back-to-back transactions; a single
|
||||
// transient NACK anywhere in that chain used to abort the whole
|
||||
// sequence. Retry a few times before giving up -- cheap and matches
|
||||
// how every other bus driver in this codebase tolerates bus noise.
|
||||
static const int kMaxAttempts = 3;
|
||||
esp_err_t err = ESP_FAIL;
|
||||
for (int attempt = 0; attempt < kMaxAttempts; ++attempt) {
|
||||
err = i2c_master_transmit(s_dev, buf, (size_t)(2U + length), 1000);
|
||||
if (err == ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(2));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -203,6 +203,11 @@ public:
|
||||
*
|
||||
* @dname tuneFm
|
||||
* @param frequency FM centre frequency in kHz.
|
||||
* @param antCap FM_TUNE_FREQ ARG4/5 ANTCAP (AN649 Command 0x30).
|
||||
* 0 = automatic (varactor set from FE_VARM/VARB
|
||||
* properties); 1-128 bypasses auto-tune and forces
|
||||
* the on-chip antenna varactor directly (AN851
|
||||
* Appendix A calibration procedure).
|
||||
* @return Ok on success, or Si4684Error::WrongBand / TuneFailed.
|
||||
* @pubstate sends FM_TUNE_FREQ and waits for STC (AN649).
|
||||
*
|
||||
@@ -210,7 +215,7 @@ public:
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] std::expected<void, Si4684Error> tuneFm(
|
||||
core::FrequencyKHz frequency);
|
||||
core::FrequencyKHz frequency, std::uint8_t antCap = 0U);
|
||||
|
||||
/**
|
||||
* @brief seekFm — seek FM in the given direction.
|
||||
|
||||
@@ -690,7 +690,7 @@ Si4684Band Si4684Driver::loadedBand() const noexcept
|
||||
}
|
||||
|
||||
std::expected<void, Si4684Error> Si4684Driver::tuneFm(
|
||||
core::FrequencyKHz frequency)
|
||||
core::FrequencyKHz frequency, std::uint8_t antCap)
|
||||
{
|
||||
if (auto band = ensureBand(Si4684Band::Fm); !band) {
|
||||
return band;
|
||||
@@ -703,8 +703,8 @@ std::expected<void, Si4684Error> Si4684Driver::tuneFm(
|
||||
0x00U,
|
||||
static_cast<std::uint8_t>(chipFreq & 0xFFU),
|
||||
static_cast<std::uint8_t>(chipFreq >> 8),
|
||||
0x00U,
|
||||
0x00U,
|
||||
antCap, // ANTCAP[7:0] -- 0 = auto (FE_VARM/VARB), else forced value
|
||||
0x00U, // ANTCAP[15:8] -- range is 0-128, high byte always 0
|
||||
0x00U, // PROG_ID (AN649 ARG6; ignored when DIR_TUNE=0)
|
||||
};
|
||||
if (auto cmd = writeCommand(Command::FmTuneFreq, args, sizeof(args));
|
||||
@@ -728,8 +728,10 @@ std::expected<void, Si4684Error> Si4684Driver::tuneFm(
|
||||
static_cast<unsigned>(readKhz));
|
||||
}
|
||||
ESP_LOGI(kTag,
|
||||
"FM tuned %u kHz rssi=%d dBuV snr=%d dB valid=%d readfreq=%u",
|
||||
"FM tuned %u kHz antcap=%u rssi=%d dBuV snr=%d dB valid=%d "
|
||||
"readfreq=%u",
|
||||
static_cast<unsigned>(frequency.value()),
|
||||
static_cast<unsigned>(antCap),
|
||||
static_cast<int>(rsq->rssiDbuV),
|
||||
static_cast<int>(rsq->snrDb),
|
||||
static_cast<int>(rsq->valid),
|
||||
|
||||
Reference in New Issue
Block a user