typedef struct { // audio stream settings audio_quality_t uac_quality; // USB-side state management bool usb_mounted; // USB mount state bool uac_alt1_active; // Out EP open/close (speaker stream) uint8_t uac_alt1_muted; // mute state int16_t uac_alt1_volume; // volume // Feedback pre-roll: reduce drift during startup int16_t uac_fb_inverval_count; /* align TX interval to (1 << (UAC_EXPLICIT_FB_INTERVAL - 1)) ms */ bool uac_fb_started; // FB launch signal bool uac_fb_start_pending; // FB launch preparation signal bool uac_fb_locked; // FB lock state int16_t uac_fb_lockcount; // FB unlock counter int32_t uac_long_err_mHz; // long-term accumulated error (mHz) // I2S pre-roll: absorb drift immediately after ALT1 activation bool i2s_starting; // I2S launch preparation signal uint32_t i2s_start_ms; // I2S launch countdown timer // I2S ASRC controller (SRC and Killer) bool i2s_src_enabled; // ASRC enable/disable (debug) bool i2s_src_inited; // SRC pre-roll completed flag bool i2s_src_locked; // SRC locked int16_t i2s_src_lockcount; // SRC unlock counter int32_t i2s_pcnt_delta_hz; // delta Hz passed to SRC float i2s_src_phase_ratio; // resampler phase ratio (USB/I2S) float i2s_src_smooth_ratio; // SRC smoothing rate float i2s_src_phase; // ASRC internal phase (interpolator state) int i2s_src_in_idx; // interpolator input sample index // counter pre-roll bool counter_warmup_rollout; // counter warm-up completed // monitoring — health status int16_t ddc_ring_looses; // DDC ring starvation, quantization noise, jitter noise source float ddc_ring_wl; // DDC ring water level int16_t ddc_rx_size; // UAC receive buffer size int16_t ddc_tx_size; // I2S transmit buffer size} ddc_control_t;
typedef struct { int32_t sample_rate; int8_t channels; int8_t resolution_bits; int8_t sample_bytes; int16_t frame_size; int16_t mclk_multi; float rms_max;} audio_quality_t;
typedef struct { int src; int mclk; int16_t mclk_multiple; int16_t lrck; int bclk; int bclk_divn; // integer part = mclk / bclk int bclk_divi; // fractional part = mclk % bclk // Counters int16_t pcnt_diff; int16_t pcnt_cur; int16_t pcnt_last; int32_t pcnt_fs; int16_t pcnt_warmup; int32_t pcnt_fs_history[3]; // 3‑point median filter int16_t pcnt_fs_factor; // ASRC-related uint32_t last_fb; // Q14 int32_t acc_q14; // fractional accumulator (Q14) int32_t delta_fb_q; float source_clock_ratio;} clock_counter_t;
typedef struct { bool uac_fb_started; // after UAC FB has started bool uac_fb_locked; // UAC FB locked bool i2s_inited; // I2S initialized bool i2s_locked; // I2S locked bool pcnt_countdown; // startup countdown bool pcnt_rollupped; // counter in actual operation int16_t delta_fb_q; // UAC Feedback (10.14) int32_t delta_hz; // ASRC input int16_t pcnt_diff; // raw PCNT value int32_t pcnt_fs; // PCNT Hz int32_t fs_raw; // raw PCNT → raw Hz int32_t long_err_mHz; // long-term FB error float ratio_clock; // control loop (I2S/USB) float ratio_phase; // resampler (USB/I2S) float ratio_smooth; // ASRC internal smoothing float i2s_src_phase; // ASRC phase (interpolator internal state) int i2s_src_in_idx; // interpolator input sample index uint64_t tick_us; // added: log timestamp (microseconds) call_position_e call_position; // caller position} log_entry_t;
int32_t ddc_log_print_detail(ddc_control_t *ddc, int32_t start, int32_t count){ if (start >= MAX_DDC_LOG) return 0; // Header if (start == 0) { ESP_LOGI(TAG, "DDC cfg rate=%u bits=%d ch=%d mclk_multi=%d", ddc->uac_quality.sample_rate, ddc->uac_quality.resolution_bits, ddc->uac_quality.channels, ddc->uac_quality.mclk_multi ); } int tail = start count; if (tail > MAX_DDC_LOG) tail = MAX_DDC_LOG; for (int i = start; i < tail; i ) { log_entry_t *L = &g_ddc_log[i]; // ---- Phase detection ---- const char *phase = (!L->i2s_locked) ? "PHASE0(I2S_INIT)" : (!L->pcnt_rollupped) ? "PHASE1(PCNT_WARMUP)" : (!L->uac_fb_started) ? "PHASE2(FB_WAIT_START)" : (!L->uac_fb_locked) ? "PHASE3(FB_WAIT_LOCK)" : "PHASE4(LOCKED)"; // ---- STUCK detection ---- bool fs_stuck = (L->fs_raw == ddc->uac_quality.sample_rate); bool pcntfs_stuck = (L->pcnt_fs == ddc->uac_quality.sample_rate); bool dhz_stuck = (L->delta_hz == 0); bool dfb_stuck = (L->delta_fb_q == 0); ESP_LOGI(TAG, "idx=%d tick=%u part=%d %s\n" " I2S: init=%d lock=%d\n" " PCNT: warm=%d up=%d diff=%d fs_raw=%ld%s fs=%d%s dhz=%ld%s\n" " FB: start=%d lock=%d dfb=%d%s long=%ld ratio clock=%.6f\n" " SRC: ratio phase=%.6f smooth=%.6f", i, (uint32_t)(L->tick_us & 0xFFFFFFFF), L->call_position, phase, // I2S L->i2s_inited, L->i2s_locked, // PCNT L->pcnt_countdown, L->pcnt_rollupped, L->pcnt_diff, L->fs_raw, fs_stuck ? " (STUCK)" : "", L->pcnt_fs, pcntfs_stuck ? " (STUCK)" : "", L->delta_hz, dhz_stuck ? " (NO-MOVE)" : "", // FB L->uac_fb_started, L->uac_fb_locked, L->delta_fb_q, dfb_stuck ? " (NO-MOVE)" : "", L->long_err_mHz, L->ratio_clock, // SRC L->ratio_clock, L->ratio_smooth ); } return tail - start;}