復元・復旧サービス充実|(有)フロンティア・オンライン

復元・復旧サービス充実|(有)フロンティア・オンライン

【深淵オーディオ】(11)Core'2 Telemetry Downlink Receiver:ProAudio仕様PopoDAC(USB DAC) 自作(DIY)

‹ 2026/01/05 ›

こんばんは。11回、PopoDAC Core'2 TDR相(Telemetry Downlink Receiver、旧称UAC相)の説明に入ります。


ここまででPopoDACに大分興味が湧いてきましたかね?


(え?まったく湧いてこない・・・?汗)



TDR相の解説

ま、本題です。^^;


TDR相(Telemetry Downlink Receiver)では、USB-UACからOutput EPのデータを受取り、MASTER RINGに取り込む作業を担当します。

発動起源は'AUDIO SOF ISR'、になります。


モジュール構成

モジュール構成は5番「Data Telemerty Receiver」のみとシンプルです。


tud_audio_rx_done_isr

モジュールの中身もシンプル、ただひたすらMASTER RINGへのデータPushに励むのみです。

bool IRAM_ATTR tud_audio_rx_done_isr(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting)

{

    size_t got = 0;


    // 0バイト送信をしくることがある場合への備え(SOFルール的にはありえない)

    if (n_bytes_received > 0) {

        got = tud_audio_n_read(0, g_pcm_buf, n_bytes_received>(g_ddc.uac_quality.frame_size<<UAC_BUFFER_STROKESIZE)?(g_ddc.uac_quality.frame_size<<UAC_BUFFER_STROKESIZE):n_bytes_received);

        if (got > 0) {

            // 0 パケットは ring buffer に書かない

            rb_write(&g_audio_ring, g_pcm_buf, got);

        }

    }


    g_ddc.ddc_rx_size = got;


#if DDC_LOG == 1

    static usb_packet_log_t uac_log;

    uac_log.nsamples = got;

    uac_log.ring_level = rb_available(&g_audio_ring);

    usb_packet_log_write(&uac_log);

#endif

    return true;

}


ここでの仕事では、受取り作業に集中するのみです。

複雑な演算、小数点を伴う演算、状況判断による余計な分岐、その他UACとの駆け引きなどは一切せず、ただひたすら受取り作業に専念します。


「なぜ?」って

だって、'AUDIO SOF ISR'内でやっている作業なのですから。


「IF文使っとるやないですかぁ?」

はい、使っています。

これも確認ができれば、要らなくなります。

やっぱり怖いですが・・・。><


SOF同期内では、USB仕様上は“必ず正しいサイズで送ってくる”ことが保証されるお話をしました。

なので不要な分岐はなるべく削り取る。

分岐を減らすことで ISR の実行時間は安定しますので、“時間の純度”を向上させることに繋げられるといった具合です。


そしてさらに、ここにLOCKやWAITを挿し込むことは勿論厳禁となります。


FreeRTOS-Queue、RingBufferなど内部でLOCKを使うような機能の採用を見送り、万一にでも同期に繋がるような受け渡しにならないように工夫する必要があります。

そのために用意されたのがMASTER RINGであり、RX側で利用するのがそのバイト配列機能部’Lock Free Ring Buffer’となります。


tud_audio_n_availableはつかないの?

UACからのデータ受信に、ループ内でtud_audio_n_availableを使った事例を見かけます。


「これはいつ使うん?」とお思いがちですが、

PopoDACでは、全く使いません。


組込みにtud_audio_n_availableを使ったことがある方はもうお分かりでしょうが、これを使うことがありえるケースは'AUDIO SOF ISR'と非同期の時になります。

同期内で実施している以上、使う必要性はありませんし、USB-DMA側の水位を知る必要性もありません。


USBドライバが'AUDIO SOF ISR'を発呼してる以上、急ぎ適切に処理してくれを正確に伝えてきています。

PopoDAC側でやる仕事は、来たら大至急でこなすが正解なのです。^^;


ESP32-S3 USB-DMA地雷

蛇足になりますが、PopoDACでも実はUSB側はDMA転送ではありません。

FIFOです。


「え?なんでいまさら?」

はい、暴走するからです。


執筆時点のIDFバージョンではTinyUSBでDMAを踏みます(有効にする)と、大変なことになります。汗

これはもはやIOレベルの問題を孕んでおりますので、IDF、TinyUSBが安全ラインに到達するまでオンにはできません。


(もしかして基板設計上ありにならないのかも・・・)


はい撤収(コメントアウト)、FIFO堕ちで落着します。

//#define CFG_TUD_DWC2_DMA_ENABLE      1


(※これは現行IDF/TinyUSBの実装上の問題であり、将来のバージョンでは改善される可能性があります。)


では、次週はCore'3 Timer相 GNC(Guidance & Navigation Control)になります。

お楽しみに♪