Root cause of FM/DAB "stonata" audio: xtalCtun=31/nominal XTAL_FREQ defaults were never measured against this board's actual crystal (Abracon ABM8-19.200MHZ-10-1-U-T, CL=10pF, two external 15pF load caps). Fixed via CTUN trim by ear (31->0) plus a new live calibration loop that reads the Si4684's own FM_RSQ FREQOFF field (broadcast carriers are GPS-locked, so it's a free precision frequency reference) to trim XTAL_FREQ with no lab equipment. Converged to CTUN=0, XTAL_FREQ=19199750 Hz, residual -3/-4 ppm cross-checked on two stations. New tools/infrastructure (kept, not one-off): - Si4684Driver::recalibrateXtal() + POST /api/tuner/xtal-calibrate: live crystal re-trim without an ESP32 reflash. - FM_RSQ FREQOFF exposed as "freqoff_ppm" in GET /api/tuner/status. - tools/si4684_xtal_calibration.py: automates the trim loop. - tools/si4684_antenna_calibration.py: AN851 Appendix A ANTCAP/VARM/VARB sweep tool (same session, separate calibration). - CONFIG_ESP32_I2S_TEST_TONE (off by default): isolates Si4684-specific audio issues from shared-downstream ones by writing a tone directly over the I2S bus the Si4684 also uses. - SIGMA_WRITE_REGISTER_BLOCK/sigma_safeload_block now retry on NACK and verify via read-back instead of firing I2C writes blind. - FM de-emphasis set to European 50us (was left at the US 75us default). - DAB_ACF_ENABLE restored to its previous 0x0000 with a citation explaining why (tested the datasheet default of 0x0003, made things audibly worse). See docs/si4684-rf-investigation-report.md's 2026-08-23 entry for the full elimination chain and docs/TODO.md for follow-up work (persisting calibration results to EEPROM instead of requiring a firmware edit). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
140 lines
5.1 KiB
C
140 lines
5.1 KiB
C
/**
|
|
* @file SigmaStudioFW.h
|
|
* @brief Minimal SigmaStudio download helpers for ADAU1701 RAM boot.
|
|
*
|
|
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
|
|
*
|
|
* Copyright 2026 Michele Bigi
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Subset of the Analog Devices SigmaStudio export support library.
|
|
*
|
|
* @author Michele Bigi
|
|
* @date 2026-07-06
|
|
*/
|
|
#pragma once
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef unsigned char ADI_REG_TYPE;
|
|
|
|
/**
|
|
* @brief Bind the I2C port used by SIGMA_WRITE_REGISTER_BLOCK.
|
|
*
|
|
* @param port ESP-IDF I2C master port number.
|
|
* @param addr7 ADAU1701 7-bit I2C address (0x34 on DigiRadio).
|
|
*/
|
|
void sigma_studio_bind_i2c(int port, unsigned char addr7);
|
|
|
|
/** @brief Attach the I2C device handle created by Adau1701Driver. */
|
|
void sigma_studio_set_device(void* i2cDevHandle);
|
|
|
|
/**
|
|
* @brief Acquire the process-wide ADAU1701 I2C lock.
|
|
*
|
|
* Guards a logical multi-transaction operation (e.g. a safeload burst)
|
|
* against interleaving from another FreeRTOS task — individual
|
|
* i2c_master_transmit calls are already serialised by the ESP-IDF I2C
|
|
* driver, but a sequence of several transactions is not atomic without
|
|
* this. Callers: Adau1701Driver safeload paths and the SigmaStudio TCP
|
|
* bridge (components/net/SigmaStudioTcpServer).
|
|
*/
|
|
void sigma_studio_lock(void);
|
|
|
|
/** @brief Release the lock acquired by sigma_studio_lock(). */
|
|
void sigma_studio_unlock(void);
|
|
|
|
/**
|
|
* @brief Write a contiguous register/data block to the ADAU1701.
|
|
*
|
|
* Retries each I2C chunk up to 3 times on NACK, matching the reliability
|
|
* already applied to the runtime safeload path (see sigma_i2c_write).
|
|
*
|
|
* @param devAddress SigmaStudio device address (0x68 write addr).
|
|
* @param address 16-bit target address in DSP memory map.
|
|
* @param length Payload length in bytes (may exceed 255).
|
|
* @param pData Payload bytes.
|
|
* @return 0 on success, non-zero if any chunk failed after retries.
|
|
*/
|
|
int SIGMA_WRITE_REGISTER_BLOCK(unsigned char devAddress,
|
|
unsigned int address,
|
|
unsigned int length,
|
|
ADI_REG_TYPE* pData);
|
|
|
|
/**
|
|
* @brief Read a contiguous register/data block from the ADAU1701.
|
|
*
|
|
* @param reg 16-bit source address in DSP memory map.
|
|
* @param data Destination buffer.
|
|
* @param length Number of bytes to read.
|
|
* @return 0 on success, non-zero on I2C failure.
|
|
*/
|
|
int sigma_i2c_read(unsigned int reg, unsigned char* data, unsigned int length);
|
|
|
|
/**
|
|
* @brief Read back a previously written block and compare it byte-for-byte.
|
|
*
|
|
* Diagnostic aid for boot-time DSP program replay: a chunk that ACKed but
|
|
* still landed wrong (or a register that doesn't hold the value it was
|
|
* given) shows up here even though SIGMA_WRITE_REGISTER_BLOCK reported
|
|
* success. Read-only — never aborts anything by itself, callers decide.
|
|
*
|
|
* @param address 16-bit address the block was written to.
|
|
* @param expected Bytes that were written.
|
|
* @param length Payload length in bytes (may exceed 255).
|
|
* @return 0 if the read-back matches, non-zero on mismatch or read failure.
|
|
*/
|
|
int sigma_verify_block(unsigned int address, const ADI_REG_TYPE* expected,
|
|
unsigned int length);
|
|
|
|
/** Safeload data register base (0x0810..0x0814). */
|
|
#define ADAU1701_SAFELOAD_DATA_BASE 0x0810U
|
|
/** Safeload address register base (0x0815..0x0819). */
|
|
#define ADAU1701_SAFELOAD_ADDR_BASE 0x0815U
|
|
/** DSP core control register (IST bit triggers safeload). */
|
|
#define ADAU1701_CORE_CONTROL_REG 0x081CU
|
|
/** IST bit value OR-ed into core control to commit safeload. */
|
|
#define ADAU1701_CORE_IST_TRIGGER 0x003CU
|
|
|
|
/**
|
|
* @brief Safeload one 8.23 fixpoint parameter (click-free update).
|
|
*
|
|
* @param paramAddr Parameter RAM address from DigiRadio_IC_1_PARAM.h.
|
|
* @param fixpoint 32-bit SigmaStudio fixpoint value.
|
|
* @return 0 on success, non-zero on I2C failure.
|
|
*/
|
|
int sigma_safeload_param(unsigned int paramAddr, int fixpoint);
|
|
|
|
/**
|
|
* @brief Safeload up to five parameters in one IST transfer (e.g. biquad).
|
|
*
|
|
* @param count Number of pairs (1..5).
|
|
* @param paramAddrs Parameter RAM addresses.
|
|
* @param fixpoints 32-bit fixpoint values.
|
|
* @return 0 on success, non-zero on I2C failure.
|
|
*/
|
|
int sigma_safeload_block(unsigned char count, const unsigned int* paramAddrs,
|
|
const int* fixpoints);
|
|
|
|
/**
|
|
* @brief Safeload up to five parameters from raw wire bytes (pass-through).
|
|
*
|
|
* Used by the SigmaStudio TCP bridge: unlike sigma_safeload_block(), which
|
|
* reconstructs the 4-byte payload from a host int, this forwards each
|
|
* 4-byte word exactly as received over the network — no endianness
|
|
* reinterpretation.
|
|
*
|
|
* @param count Number of words (1..5).
|
|
* @param paramAddrs Parameter RAM addresses.
|
|
* @param rawWords count*4 raw bytes, one 4-byte word per address.
|
|
* @return 0 on success, non-zero on I2C failure.
|
|
*/
|
|
int sigma_safeload_raw_block(unsigned char count, const unsigned int* paramAddrs,
|
|
const unsigned char* rawWords);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|