AccueilWiki i.MX8MP → Audio

Audio sur i.MX8M Plus

Guide complet du sous-systeme audio : SAI, ALSA, DSP HiFi4, NPU, effets temps reel, multivoie TDM, integration codec TI TAC5212, et pipelines de traitement.

Vue d’ensemble

L’i.MX8M Plus integre l’un des sous-systemes audio les plus complets de la famille i.MX. Il combine des interfaces serie haute performance (SAI), un DSP Cadence HiFi4 dedie au traitement audio, un NPU pour l’inference IA, et un convertisseur de frequence asynchrone (EASRC).

🎵 Sous-systeme audio i.MX8MP
Interfaces SAI6x SAI (SAI1-SAI3, SAI5-SAI7)
DSPCadence HiFi4 @ 800 MHz
NPUVivante VIP8000, 2.3 TOPS
EASRC4 canaux, ratio 1:8 a 8:1
MICFIL8 canaux PDM (4x stereo)
HDMIHDMI 2.0a TX + eARC RX
Audio PLLs2x PLL fractionnaires
DMASDMA (32 canaux)

Architecture audio

Diagramme bloc audio i.MX8MP
SAI1I2S / TDM
SAI2I2S / TDM
SAI3I2S / TDM
SAI5I2S / TDM / HDMI RX
SAI6I2S (interne DSP)
SAI7I2S (interne DSP)
MICFIL8ch PDM Mic
EASRCSample Rate Conv
HiFi4 DSP @ 800 MHzEncodage, Decodage, Effets, Mixage
NPU VIP8000 @ 2.3 TOPSNoise Reduction, KWD, Speech Enhancement
HDMI 2.0a TXAudio jusqu’a 8ch / 192kHz
eARC / SPDIF RXAudio Return Channel

Aperçu du pipeline cible

Voici le pipeline complet que nous allons construire dans ce tutoriel. Chaque bloc sera detaille dans les sections suivantes.

Voici le pipeline audio complet multivoie 8 canaux avec 4x TAC5212 sur SAI7 en TDM. Ce flow represente un cas reel de traitement audio embarque : capture multicanal, pre-traitement DSP, inference IA sur le NPU, post-traitement DSP avec EQ et exciter, puis sortie vers les DAC.

Configuration materielle

4 codecs TAC5212 partagent un seul bus TDM sur SAI7 (1 ligne TX, 1 ligne RX). Le TAC5212 #0 est en mode Controller (master) : il genere les signaux BCLK et FSYNC. Les 3 autres sont en mode Target (slave). Chaque codec occupe 2 slots TDM, pour un total de 8 canaux ADC + 8 canaux DAC sur un seul SAI.

graph TD
    subgraph BUS["Bus TDM partage — 1 fil TX, 1 fil RX"]
        direction LR
        B1["BCLK = 12.288 MHz
genere par TAC #0"] B2["FSYNC = 48 kHz
genere par TAC #0"] B3["SDIN : i.MX8MP TX → codecs"] B4["SDOUT : codecs TX → i.MX8MP"] end BUS --- T0 & T1 & T2 & T3 T0["TAC5212 #0
MASTER — I2C 0x48
Slot 0-1"] T1["TAC5212 #1
SLAVE — I2C 0x49
Slot 2-3"] T2["TAC5212 #2
SLAVE — I2C 0x4A
Slot 4-5"] T3["TAC5212 #3
SLAVE — I2C 0x4B
Slot 6-7"] T0 --- IO0["Mic/Ligne
HP/Ampli"] T1 --- IO1["Mic/Ligne
HP/Ampli"] T2 --- IO2["Mic/Ligne
HP/Ampli"] T3 --- IO3["Mic/Ligne
HP/Ampli"] style BUS fill:#eff6ff,stroke:#2563eb,stroke-width:2px style T0 fill:#fef3c7,stroke:#d97706,stroke-width:2px style T1 fill:#f0fdf4,stroke:#10b981 style T2 fill:#f0fdf4,stroke:#10b981 style T3 fill:#f0fdf4,stroke:#10b981 style IO0 fill:#fff,stroke:#cbd5e1 style IO1 fill:#fff,stroke:#cbd5e1 style IO2 fill:#fff,stroke:#cbd5e1 style IO3 fill:#fff,stroke:#cbd5e1

Etape par etape : du micro a la sortie

Le flux audio traverse 7 etapes. Voici le detail de chacune :

Etape 1 — Capture analogique (monde reel → codec)

Les signaux analogiques (microphones, instruments, lignes) arrivent sur les entrees differentielles des 4 TAC5212. Chaque codec effectue la conversion analogique-numerique (ADC) a 24 bits, jusqu’a 192 kHz, avec un SNR de 119 dB. Le PGA (Programmable Gain Amplifier) integre au TAC5212 ajuste le gain d’entree par canal.

# Entrees analogiques -> ADC des 4 codecs TAC5212 # # TAC5212 #0 : IN_A (mic/ligne ch0) -> ADC -> PCM 24-bit slot 0 # IN_B (mic/ligne ch1) -> ADC -> PCM 24-bit slot 1 # TAC5212 #1 : IN_A (mic/ligne ch2) -> ADC -> PCM 24-bit slot 2 # IN_B (mic/ligne ch3) -> ADC -> PCM 24-bit slot 3 # TAC5212 #2 : IN_A (mic/ligne ch4) -> ADC -> PCM 24-bit slot 4 # IN_B (mic/ligne ch5) -> ADC -> PCM 24-bit slot 5 # TAC5212 #3 : IN_A (mic/ligne ch6) -> ADC -> PCM 24-bit slot 6 # IN_B (mic/ligne ch7) -> ADC -> PCM 24-bit slot 7 # # Le TAC5212 #0 (master) genere BCLK et FSYNC pour tous les codecs. # BCLK = 48000 Hz * 32 bits * 8 slots = 12.288 MHz # FSYNC = 48000 Hz (une frame = 8 slots)

Etape 2 — Transport TDM (codec → SAI7)

Les 8 canaux PCM sont multiplexes dans le temps sur un seul fil (SDOUT). Chaque codec emet ses 2 slots pendant la fenetre temporelle qui lui est assignee. Le SAI7 de l’i.MX8MP recoit les 8 slots sur sa ligne RX unique et les demultiplexe en 8 canaux PCM en memoire via SDMA (DMA).

# Trame TDM sur le fil SDOUT (codecs -> i.MX8MP SAI7 RX) : # # |<--------- 1 frame FSYNC = 1/48000 s = 20.83 us --------->| # +——–+——–+——–+——–+——–+——–+——–+——–+ # | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7 | # | 32 bit | 32 bit | 32 bit | 32 bit | 32 bit | 32 bit | 32 bit | 32 bit | # +——–+——–+——–+——–+——–+——–+——–+——–+ # TAC #0 TAC #0 TAC #1 TAC #1 TAC #2 TAC #2 TAC #3 TAC #3 # ch L ch R ch L ch R ch L ch R ch L ch R # # Seul le codec qui « possede » le slot emet pendant cette fenetre. # Les autres codecs mettent leur sortie en haute impedance (tri-state). # # SDMA transfere les donnees SAI7 RX -> buffer circulaire en DRAM # sans intervention du CPU A53 (zero-copy DMA).

Etape 3 — Pre-traitement DSP HiFi4 (encodage, preparation)

Le DSP HiFi4 (800 MHz) recupere les 8 canaux PCM bruts depuis la DRAM partagee. Il effectue le pre-traitement necessaire avant l’inference IA :

graph LR
    RX["SAI7 FIFO RX
8ch PCM brut"] --> DC["DC Block
par canal"] --> HPF["HPF 80 Hz
par canal"] --> GAIN["Gain
normalisation"] style RX fill:#eff6ff,stroke:#2563eb,stroke-width:2px style DC fill:#f0fdf4,stroke:#10b981 style HPF fill:#f0fdf4,stroke:#10b981 style GAIN fill:#f0fdf4,stroke:#10b981
graph LR
    WIN["Fenetrage
25 ms / hop 10 ms"] --> FFT["FFT"] --> MFCC["MFCC
40 bins Mel"] --> Q["Quantize
INT8"] --> OUT["Tenseur → DRAM
pret pour NPU"] style WIN fill:#fef3c7,stroke:#d97706 style FFT fill:#fef3c7,stroke:#d97706 style MFCC fill:#fef3c7,stroke:#d97706 style Q fill:#fef3c7,stroke:#d97706 style OUT fill:#faf5ff,stroke:#7c3aed,stroke-width:2px

Temps de traitement : < 2 ms pour 8 canaux @ 800 MHz

Etape 4 — Inference NPU (traitement IA)

Le NPU VIP8000 (2.3 TOPS) execute le modele de reseau de neurones. Le CPU A53 orchestre le transfert des tenseurs et declenche l’inference via le VX Delegate de TensorFlow Lite. Le NPU travaille sur les features preparees par le DSP, pas sur le PCM brut.

graph TD
    IN["Tenseur INT8
depuis DRAM partagee"] TF["TFLite + VX Delegate
NPU VIP8000, 2.3 TOPS"] RNN["RNNoise INT8
40 MFCC → 40 gains
spectraux par canal"] KWD["KWD INT8
MFCC → score mot-cle
> 0.85 = detecte"] G["gains_spectral[8][40]
8 canaux x 40 bandes"] K["kwd_score
notification CPU"] DRAM["DRAM partagee
→ DSP post-traitement"] IN --> TF TF --> RNN & KWD RNN --> G KWD --> K G & K --> DRAM style IN fill:#faf5ff,stroke:#7c3aed style TF fill:#faf5ff,stroke:#7c3aed,stroke-width:2px style RNN fill:#fef3c7,stroke:#d97706,stroke-width:2px style KWD fill:#fef3c7,stroke:#d97706,stroke-width:2px style G fill:#f0fdf4,stroke:#10b981 style K fill:#fff7ed,stroke:#f59e0b style DRAM fill:#eff6ff,stroke:#2563eb

Temps d’inference : ~5 ms par frame (pipeline, non bloquant)

Etape 5 — Post-traitement DSP HiFi4 (decodage, effets, mixage)

Le DSP recupere les gains spectraux du NPU et les applique au signal temporel via un filtrage overlap-add. Puis il enchaine les effets audio en temps reel :

graph TD
    IN["Gains NPU + PCM pre-traite
8 canaux depuis DRAM"] M["1. Masque spectral
IFFT(FFT(ch) × gains[ch])
Overlap-add, 8 canaux"] EQ["2. EQ parametrique IIR
5 bandes biquad par canal
Low Shelf 80Hz · Peaking 250/1k/4kHz · High Shelf 12kHz"] EX["3. Exciter
HPF 2kHz → soft clip (tanh) → mix
Wet/dry : 15-25%"] DRC["4. DRC multi-bande
20-250Hz ratio 3:1 · 250-4kHz ratio 2:1
4k-20kHz ratio 4:1"] MIX["5. Mixage matriciel
8ch in → N ch out
Matrice configurable"] LIM["6. Limiteur brickwall
-1 dBFS"] OUT["8ch PCM traites
→ SAI7 TX FIFO"] IN --> M --> EQ --> EX --> DRC --> MIX --> LIM --> OUT style IN fill:#faf5ff,stroke:#7c3aed style M fill:#f0fdf4,stroke:#10b981,stroke-width:2px style EQ fill:#f0fdf4,stroke:#10b981,stroke-width:2px style EX fill:#fef3c7,stroke:#d97706,stroke-width:2px style DRC fill:#f0fdf4,stroke:#10b981,stroke-width:2px style MIX fill:#eff6ff,stroke:#2563eb style LIM fill:#fef2f2,stroke:#ef4444,stroke-width:2px style OUT fill:#eff6ff,stroke:#2563eb,stroke-width:2px

Temps de traitement total : < 3 ms pour 8 canaux @ 800 MHz

Etape 6 — Transport TDM sortie (SAI7 → codecs DAC)

Le SAI7 TX emet les 8 canaux traites sur la ligne SDIN. Chaque TAC5212 ne lit que les 2 slots qui lui sont assignes et ignore les autres.

graph LR
    SAI["SAI7 TX
8ch PCM traites"] subgraph FRAME["Trame TDM — 1 frame FSYNC = 8 slots x 32 bits"] direction LR S0["Slot 0
ch L"] S1["Slot 1
ch R"] S2["Slot 2
ch L"] S3["Slot 3
ch R"] S4["Slot 4
ch L"] S5["Slot 5
ch R"] S6["Slot 6
ch L"] S7["Slot 7
ch R"] end SAI --> S0 S0 & S1 --> D0["TAC5212 #0
DAC"] S2 & S3 --> D1["TAC5212 #1
DAC"] S4 & S5 --> D2["TAC5212 #2
DAC"] S6 & S7 --> D3["TAC5212 #3
DAC"] style SAI fill:#eff6ff,stroke:#2563eb,stroke-width:2px style FRAME fill:#f8fafc,stroke:#94a3b8 style D0 fill:#fef3c7,stroke:#d97706,stroke-width:2px style D1 fill:#f0fdf4,stroke:#10b981 style D2 fill:#f0fdf4,stroke:#10b981 style D3 fill:#f0fdf4,stroke:#10b981

Chaque codec ne lit que ses 2 slots et ignore les autres (haute impedance).

Etape 7 — Conversion DAC et sortie analogique

Chaque TAC5212 convertit ses 2 canaux PCM en signal analogique via ses DAC 24-bit (120 dB SNR). Les sorties differentielles alimentent des amplificateurs de puissance ou des casques.

Latence totale du pipeline : Capture ADC (~0.5 ms) + transport TDM (~0.02 ms) + DSP pre (~2 ms) + NPU inference (~5 ms, pipeline) + DSP post (~3 ms) + transport TDM (~0.02 ms) + DAC (~0.5 ms) = ~11 ms bout en bout. Avec un buffer ALSA de 256 frames @ 48 kHz (5.3 ms) le round-trip total est de l’ordre de 15-20 ms, compatible avec le monitoring temps reel.

Schema recapitulatif du pipeline complet

graph TD
    IN["🎤 8x Microphones / Lignes
Monde reel analogique"] ADC["TAC5212 x4 — ADC
8ch analogique → 8ch PCM 24-bit
119 dB SNR, 48 kHz"] RX["SAI7 RX — TDM 8 slots
DMA interne AudioMix
Pas de SDMA, pas de DDR"] PRE["DSP HiFi4 @ 800 MHz
PRE-TRAITEMENT ~2 ms
DC Block → HPF 80 Hz → Gain
FFT → MFCC 40 bins → Quantize INT8"] NPU["NPU VIP8000 — 2.3 TOPS
INFERENCE IA ~5 ms
RNNoise : 40 gains spectraux
KWD : score mot-cle"] POST["DSP HiFi4 @ 800 MHz
POST-TRAITEMENT ~3 ms
Masque NPU → EQ 5 bandes IIR
Exciter → DRC 3 bandes
Mixage → Limiteur -1 dBFS"] TX["SAI7 TX — TDM 8 slots
DMA interne AudioMix"] DAC["TAC5212 x4 — DAC
8ch PCM → 8ch analogique
120 dB SNR"] OUT["🔊 8x Haut-parleurs / Amplis
Monde reel analogique"] IN --> ADC --> RX --> PRE PRE -- "tenseur features
via DRAM partagee" --> NPU NPU -- "gains spectraux[8][40]
via DRAM partagee" --> POST POST --> TX --> DAC --> OUT style IN fill:#fff,stroke:#94a3b8,stroke-width:1px style ADC fill:#fef3c7,stroke:#d97706,stroke-width:2px style RX fill:#eff6ff,stroke:#2563eb,stroke-width:2px style PRE fill:#f0fdf4,stroke:#10b981,stroke-width:2px style NPU fill:#faf5ff,stroke:#7c3aed,stroke-width:2px style POST fill:#f0fdf4,stroke:#10b981,stroke-width:2px style TX fill:#eff6ff,stroke:#2563eb,stroke-width:2px style DAC fill:#fef3c7,stroke:#d97706,stroke-width:2px style OUT fill:#fff,stroke:#94a3b8,stroke-width:1px
Latence bout en bout : ~11 ms | Round-trip : ~15-20 ms

SAI (Serial Audio Interface)

Le SAI (Synchronous Audio Interface) est le peripherique de transport audio numerique de l’i.MX8MP. Chaque SAI supporte I2S, Left-Justified, Right-Justified et TDM (Time Division Multiplexing).

Caracteristiques par SAI

Mapping SAI sur i.MX8MP

SAIAdresse baseData linesUsage typiqueAcces DSP
SAI10x30C100001 TX + 1 RXCodec audio principal (WM8960 sur EVK)Non
SAI20x30C200001 TX + 1 RXCodec secondaire, Bluetooth audioNon
SAI30x30C300001 TX + 2 RXCodec externe, TDM multi-canalNon
SAI50x30C500004 TX + 4 RXHDMI RX (eARC), multi-canal 8ch+Non
SAI60x30C600001 TX + 1 RXInterne — lien DSP HiFi4Oui
SAI70x30C700001 TX + 1 RXDSP HiFi4 — codec externe TDM (4x TAC5212)Oui
⚠️
Point d’architecture critique : SAI6 et SAI7 ne sont pas des SAI comme les autres. Ils ont un chemin direct vers le DSP HiFi4, ce qui change fondamentalement la facon dont l’audio est traite. Voir la section detaillee ci-dessous.

SAI6 & SAI7 : le chemin direct vers le DSP

C’est le point le plus important de l’architecture audio i.MX8MP et il est tres mal documente par NXP. Comprendre la difference entre SAI1-3/SAI5 et SAI6/SAI7 est essentiel pour concevoir une carte electronique audio performante.

Le probleme : SAI1-3, SAI5 (chemin CPU)

Les SAI « normaux » (SAI1, SAI2, SAI3, SAI5) sont connectes au bus AXI principal du SoC. L’audio suit ce chemin :

Chemin CPU (SAI1-3/SAI5)
graph TD
    C1["Codec externe"] --> C2["SAI1/2/3/5"]
    C2 --> C3["Bus AXI principal
partage GPU, USB, ETH..."] C3 --> C4["SDMA
32 canaux DMA"] C4 --> C5["DDR DRAM
buffer ALSA"] C5 --> C6["CPU A53
Linux kernel"] C6 --> C7["App userspace"] style C1 fill:#fff,stroke:#94a3b8 style C2 fill:#fef2f2,stroke:#ef4444,stroke-width:2px style C3 fill:#fef2f2,stroke:#ef4444,stroke-width:2px style C4 fill:#fef2f2,stroke:#ef4444 style C5 fill:#fef2f2,stroke:#ef4444 style C6 fill:#fef2f2,stroke:#ef4444 style C7 fill:#fff,stroke:#94a3b8
❌ Latence 5-25 ms (scheduling Linux)
❌ Contention bus AXI
❌ Double copie SAI→DDR→DSP
❌ Xruns sous charge CPU
❌ CPU ne peut pas dormir
Chemin DSP direct (SAI6/SAI7)
graph TD
    D1["Codec externe
4x TAC5212"] --> D2["SAI7"] D2 --> D3["Bus interne AudioMix
dedie, sans contention"] D3 --> D4["DSP HiFi4 @ 800 MHz
acces direct FIFO"] D4 --> D5["DTCM / ITCM
256 KB, 1 cycle"] style D1 fill:#fff,stroke:#94a3b8 style D2 fill:#f0fdf4,stroke:#10b981,stroke-width:2px style D3 fill:#f0fdf4,stroke:#10b981,stroke-width:2px style D4 fill:#fef3c7,stroke:#d97706,stroke-width:2px style D5 fill:#f0fdf4,stroke:#10b981
✅ Latence < 100 µs
✅ Bus dedie AudioMix
✅ Zero copie, FIFO direct
✅ Deterministe, zero xrun
✅ CPU A53 peut dormir

La solution : SAI6 & SAI7 (chemin DSP direct)

SAI6 et SAI7 sont a l’interieur du bloc AudioMix, un sous-systeme materiel dedie a l’audio. Ce bloc a son propre bus interne qui connecte directement les SAI au DSP HiFi4, sans passer par le bus AXI principal ni par le CPU A53.

Architecture du bloc AudioMix

Le bloc AudioMix (aussi appele Audio Subsystem) est un domaine d’alimentation et d’horloge separe dans le SoC i.MX8MP. Il contient :

graph TD
    subgraph AUDIOMIX["AudioMix Subsystem"]
        direction TB
        subgraph SAI_EXT["SAI externes"]
            direction LR
            SAI1["SAI1
ext"] SAI2["SAI2
ext"] SAI3["SAI3
ext"] SAI5["SAI5
ext"] end SAI1 & SAI2 & SAI3 & SAI5 --> AXI SAI1 & SAI2 & SAI3 & SAI5 -.-> INTBUS AXI["Bus AXI principal
vers CPU A53 / DDR"] INTBUS["Bus interne AudioMix
dedie, sans contention"] subgraph SAI_DSP["SAI internes DSP"] direction LR SAI6["SAI6
DSP IPC"] SAI7["SAI7
DSP + codec ext"] end INTBUS --> SAI6 & SAI7 SAI6 & SAI7 --> DSP["DSP HiFi4
Cadence @ 800 MHz
DTCM 256 KB / ITCM 256 KB"] subgraph PERIPH["Peripheriques audio"] direction LR MICFIL["MICFIL
8ch PDM"] EASRC["EASRC
4ch SRC"] PLL["Audio PLL1/PLL2
+ clock gates"] end end AXI --> A53["CPU Cortex-A53
Linux / DDR"] style AUDIOMIX fill:#f8fafc,stroke:#2563eb,stroke-width:2px style SAI_EXT fill:#eff6ff,stroke:#93c5fd style SAI_DSP fill:#f0fdf4,stroke:#6ee7b7 style PERIPH fill:#fff,stroke:#e2e8f0 style AXI fill:#fef2f2,stroke:#ef4444,stroke-width:2px style INTBUS fill:#f0fdf4,stroke:#10b981,stroke-width:2px style DSP fill:#fef3c7,stroke:#d97706,stroke-width:2px style A53 fill:#fef2f2,stroke:#ef4444

Point cle : SAI1-3 et SAI5 transitent par le bus AXI (rouge) vers le CPU A53 et la DDR. SAI6 et SAI7 ont un chemin direct (vert) vers le DSP HiFi4 via le bus interne AudioMix.

Pourquoi SAI7 pour les TAC5212 ?

Le choix de connecter les 4 TAC5212 sur SAI7 (et pas SAI1 ou SAI3) a des consequences majeures sur les performances :

CritereSAI1-3 (chemin CPU)SAI7 (chemin DSP direct)
Latence entree → DSP5-25 ms (Linux scheduling + SDMA + DDR)< 100 µs (DMA interne, FIFO direct)
Latence round-trip15-50 ms< 1 ms (DSP seul)
DeterminismeNon-deterministe (Linux, IRQ, scheduling)Deterministe (firmware DSP, boucle fixe)
XrunsPossibles sous charge CPUImpossibles (DSP dedie)
CPU A53 load~5-15% (IRQ, SDMA, ALSA, copies)0% (le DSP fait tout)
Mode sleepImpossible (A53 doit rester actif)A53 peut dormir, le DSP continue
Contention busPartage AXI avec GPU, USB, ETH, …Bus dedie AudioMix
Acces donneesDDR : ~100 ns par accesDTCM : 1 cycle (~1.25 ns @ 800 MHz)
💡
En resume : en connectant les TAC5212 sur SAI7, l’audio entre dans les codecs, passe par le bus TDM, arrive directement dans le DSP HiFi4 via le bus interne AudioMix, est traite en memoire locale du DSP (DTCM), et ressort par le meme SAI7 — le tout sans jamais toucher le CPU A53 ni la DDR. C’est exactement le design pour de l’audio temps reel haute performance.

SAI6 vs SAI7 : differences

CaracteristiqueSAI6SAI7
Data lines1 TX + 1 RX1 TX + 1 RX
Acces DSPOui (chemin direct)Oui (chemin direct)
Pins externesDisponibles mais limites (partage pads)Disponibles via remapping SAI2 pads
Usage typiqueLien interne DSP ↔ A53 (IPC audio)Codec externe via DSP (TDM / I2S)
SOF supportOui (DAI backend)Oui (DAI backend)

SAI6 est souvent utilise comme un « pont » audio interne : le CPU A53 envoie des donnees audio au DSP via SAI6 (par exemple un flux MP3 a decoder). SAI7 est le choix naturel pour connecter un codec externe quand on veut que le DSP traite l’audio directement, sans passer par Linux.

Firmware DSP : comment ca marche concretement

Le DSP HiFi4 execute un firmware (SOF ou NXP imx-audio-framework) qui accede directement aux registres FIFO de SAI7 :

# Le DSP voit SAI7 comme un peripherique mappe en memoire. # Il lit/ecrit directement dans les registres FIFO : # # SAI7_TDR (Transmit Data Register) : 0x30C70020 # SAI7_RDR (Receive Data Register) : 0x30C70028 # # Boucle typique du firmware DSP (pseudo-code Xtensa) : # # while (1) { # // Attendre que le FIFO RX ait des donnees (IRQ ou polling) # wait_for_sai7_rx_fifo_not_empty(); # # // Lire 8 echantillons (8 slots TDM) depuis le FIFO RX # for (ch = 0; ch < 8; ch++) # input[ch] = SAI7_RDR; // lecture directe, 1 cycle DTCM # # // === TRAITEMENT DSP === # // DC block, HPF, EQ, DRC, etc. sur les 8 canaux # dsp_process(input, output, 8); # # // Ecrire 8 echantillons dans le FIFO TX # for (ch = 0; ch < 8; ch++) # SAI7_TDR = output[ch]; // ecriture directe # } # # Temps de boucle : ~5-20 microsecondes pour 8 canaux # = latence quasi-nulle entre entree et sortie

Impact sur la conception de la carte

# Regles de design pour exploiter le chemin direct DSP : # # 1. CONNECTER le codec sur SAI7 (pas SAI1/SAI2/SAI3) # -> Le DSP accede directement aux echantillons # # 2. Pas de MCLK vers les TAC5212 # -> Le TAC5212 n’a PAS de pin MCLK # -> Sa PLL interne genere BCLK/FSYNC sans horloge externe # -> Cela simplifie le routage PCB (un signal de moins a router) # # 3. I2C pour la configuration des codecs # -> Les registres TAC5212 sont configures par le CPU A53 via I2C # -> Une fois configures, le DSP prend le relais pour l’audio # -> Le CPU n’intervient plus dans le flux audio # # 4. GPIO RESET commun ou individuel # -> Un GPIO commun simplifie le design (1 resistor de pull-up) # -> Des GPIO individuels permettent de reset un codec sans les autres # # 5. Routage PCB critique : # -> BCLK et FSYNC : traces appairees, meme longueur # -> SDIN / SDOUT : traces controlees en impedance (50 ohm) # -> Pas de MCLK a router (le TAC5212 n’a pas de pin MCLK) # -> Plan de masse ininterrompu sous les traces audio

Horloges audio (PLL)

L’i.MX8MP possede deux PLL audio fractionnaires qui generent les horloges MCLK, BCLK et LRCLK pour les SAI.

PLLFrequence typiqueMultiples ciblesUsage
AUDIO_PLL1393.216 MHz8 kHz, 16k, 32k, 48k, 96k, 192k, 384kFamille 48 kHz (standard)
AUDIO_PLL2361.2672 MHz11.025k, 22.05k, 44.1k, 88.2k, 176.4kFamille 44.1 kHz (CD audio)

Arbre d’horloge SAI

AUDIO_PLL1 (393.216 MHz) → audio_pll1_out → SAI1_CLK_ROOT (diviser) → MCLK SAI1 → SAI3_CLK_ROOT (diviser) → MCLK SAI3 → SAI5_CLK_ROOT (diviser) → MCLK SAI5 → SAI7_CLK_ROOT (diviser) → horloge interne SAI7 (pas de MCLK vers TAC5212) # MCLK typiques : # 48 kHz * 256 = 12.288 MHz # 48 kHz * 512 = 24.576 MHz # 96 kHz * 256 = 24.576 MHz # 192 kHz * 256 = 49.152 MHz # Relations BCLK : # BCLK = sample_rate * bits_per_slot * nb_slots # Ex TDM 8 slots 32-bit @ 48kHz : BCLK = 48000 * 32 * 8 = 12.288 MHz

Configuration DTS des horloges

&sai7 { /* Assigner AUDIO_PLL1 comme parent d’horloge */ assigned-clocks = <&clk IMX8MP_CLK_SAI7>; assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; assigned-clock-rates = <24576000>; /* Pas de fsl,sai-mclk-direction-output : * le TAC5212 n’a pas de pin MCLK. * Sa PLL interne genere BCLK/FSYNC sans horloge externe. */ };

EASRC (Enhanced Asynchronous Sample Rate Converter)

L’EASRC est un convertisseur de frequence d’echantillonnage hardware a 4 canaux. Il permet de convertir entre des domaines d’horloge differents sans artefacts (filtrage anti-alias integre).

ParametreSpecification
Nombre de canaux4 (paires de contextes IN/OUT)
Ratio de conversion1:8 a 8:1 (ex: 8 kHz ↔ 192 kHz)
Resolutions16, 20, 24, 32 bits
Frequences8 kHz a 384 kHz
ModeAsynchrone (domaines d’horloge independants)
Firmwarefirmware-imx (easrc-imx8mn.bin)

Cas d’usage

# DTS : activer EASRC &easrc { fsl,asrc-rate = <48000>; fsl,asrc-format = <2>; /* S24_LE */ status = « okay »; }; # ALSA : utiliser EASRC pour reechantillonner aplay -D « plug:easrc » -r 48000 fichier_192khz.wav

MICFIL (Microphones PDM)

Le MICFIL (Microphone Interface) capture directement les signaux de microphones PDM (Pulse Density Modulation) sans codec externe. Il integre un decimateur et un filtre CIC.

ParametreSpecification
Canaux8 canaux PDM (4 paires stereo)
Frequences16 kHz, 22.05 kHz, 44.1 kHz, 48 kHz
Resolutions16, 24 bits (apres decimation)
QualiteFiltre DC offset, HPF integre
DetectionVoice Activity Detection (VAD) hardware
# DTS : activer MICFIL &micfil { pinctrl-names = « default »; pinctrl-0 = <&pinctrl_pdm>; assigned-clocks = <&clk IMX8MP_CLK_PDM>; assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; assigned-clock-rates = <196608000>; status = « okay »; }; # Capture 8 canaux de microphones PDM arecord -D hw:1,0 -c 8 -r 48000 -f S24_LE capture_8ch.wav
📌
Le codec externe. Maintenant que vous connaissez les interfaces audio du SoC, nous allons nous concentrer sur le codec que nous utilisons dans ce design : le TI TAC5212. Cette section explique comment 4 codecs partagent un bus TDM, pourquoi l’un d’eux doit etre master, et quel driver Linux les pilote.

Integration TI TAC5212

Le TAC5212 de Texas Instruments est un codec audio stereo haute performance parfaitement adapte a l’i.MX8MP pour des applications audio professionnelles et industrielles.

🎛 TI TAC5212 — Specifications
ADC2ch, 119 dB SNR, 24-bit
DAC2ch diff (4ch SE), 120 dB SNR
THD+N ADC-98 dB
THD+N DAC-104 dB
Sample Rate4 kHz – 768 kHz
Interface audioI2S, TDM, LJ (16/20/24/32-bit)
ControleI2C ou SPI
Alimentation1.8V ou 3.3V (AVDD)
Conso8 mW (rec) / 11 mW (play) @ 1.8V
BoitierVQFN 4×4 mm, 24 pins
Temperature-40 a +125 °C
FeaturesPLL, HPF, EQ biquad, VAD, bypass

Famille TI TAx5212

VarianteTypeDescription
TAC5212Codec (ADC+DAC)Stereo ADC 119dB + stereo DAC 120dB
TAA5212ADC seulStereo ADC 119dB (capture uniquement)
TAD5212DAC seulStereo DAC 120dB (lecture uniquement)
TAC5412-Q1Codec autoVersion automotive (AEC-Q100)

Connexion hardware (4x TAC5212 sur SAI7 TDM)

# Cablage 4x TAC5212 sur SAI7 en TDM # Le TAC5212 #0 est en mode Controller (master) : il genere BCLK et FSYNC. # Les TAC5212 #1, #2, #3 sont en mode Target (slave). # Tous partagent un seul fil TX et un seul fil RX (TDM). # # i.MX8MP SAI7 Dir 4x TAC5212 (bus commun) # ======================== === =================================== # SAI7_TX_DATA –> SDIN (commun, 4 codecs, 1 fil) # SAI7_RX_DATA <– SDOUT (commun, 4 codecs, 1 fil) # SAI7_TX_BCLK <– BCLK (genere par TAC5212 #0) # SAI7_TX_SYNC <– FSYNC (genere par TAC5212 #0) # (pas de MCLK : le TAC5212 n’a pas de pin MCLK) # # I2C3_SCL / SDA –> SCL/SDA (bus commun, addr diff.) # GPIO1_IO13 –> RESET (commun ou individuel) # # Adresses I2C : # TAC5212 #0 (master) : 0x48 (ADDR pin = GND) # TAC5212 #1 (slave) : 0x49 (ADDR pin = pull-up 10k) # TAC5212 #2 (slave) : 0x4A (ADDR pin = SDA) # TAC5212 #3 (slave) : 0x4B (ADDR pin = SCL) # # Alimentation (identique pour les 4 codecs) : # AVDD = 3.3V (ou 1.8V), DVDD = 1.8V, IOVDD = 1.8V

Multi-codec TDM (4x TAC5212 sur SAI7)

# 4 codecs TAC5212 cascades en TDM sur SAI7 # Chaque codec occupe 2 slots TDM (1 stereo ADC + 1 stereo DAC). # SAI7 a 1 seule ligne TX et 1 seule ligne RX = TDM obligatoire. # # SAI7 TDM 8 slots, 32-bit : # # TAC5212 #0 (I2C 0x48, master) : ADC -> slots 0-1, DAC <- slots 0-1 # TAC5212 #1 (I2C 0x49, slave) : ADC -> slots 2-3, DAC <- slots 2-3 # TAC5212 #2 (I2C 0x4A, slave) : ADC -> slots 4-5, DAC <- slots 4-5 # TAC5212 #3 (I2C 0x4B, slave) : ADC -> slots 6-7, DAC <- slots 6-7 # # = 8 canaux ADC + 8 canaux DAC sur un seul SAI ! # # Le TAC5212 #0 en mode Controller genere BCLK et FSYNC. # Les 3 autres en mode Target se synchronisent sur ces signaux. # # BCLK = 48000 * 32 * 8 = 12.288 MHz # Pas de MCLK : la PLL interne du TAC5212 #0 genere BCLK/FSYNC directement

Audio multivoie / TDM

Configuration TDM dans le driver SAI

# Parametres TDM dans le device tree : # # dai-tdm-slot-num = <8>; # Nombre de slots par frame # dai-tdm-slot-width = <32>; # Largeur d’un slot en bits # # Le nombre de canaux audio = nombre de slots actifs # La largeur du slot peut etre > largeur de l’echantillon # (ex: echantillon 24-bit dans un slot 32-bit, les 8 bits de poids fort sont a 0) # Slots actifs (bitmask) : # dai-tdm-slot-tx-mask = <1 1 1 1 0 0 0 0>; # slots 0-3 actifs en TX # dai-tdm-slot-rx-mask = <1 1 1 1 0 0 0 0>; # slots 0-3 actifs en RX

Synchronisation sur SAI7

graph TD
    MASTER["TAC5212 #0
Controller (master)
PLL interne
Genere BCLK + FSYNC"] BUS["BCLK + FSYNC
bus TDM commun"] SAI["SAI7
slave"] T1["TAC5212 #1
target"] T2["TAC5212 #2
target"] T3["TAC5212 #3
target"] MASTER --> BUS BUS --> SAI & T1 & T2 & T3 style MASTER fill:#fef3c7,stroke:#d97706,stroke-width:2px style BUS fill:#f0fdf4,stroke:#10b981,stroke-width:2px style SAI fill:#eff6ff,stroke:#2563eb,stroke-width:2px style T1 fill:#f0fdf4,stroke:#10b981 style T2 fill:#f0fdf4,stroke:#10b981 style T3 fill:#f0fdf4,stroke:#10b981

Le codec master garantit un jitter minimal sur BCLK/FSYNC, critique pour le SNR de 119 dB.

Pourquoi un codec master plutot que le SAI master ?

Dans une architecture TDM multi-codec, il y a 3 options pour generer les horloges BCLK et FSYNC :

OptionSource BCLK/FSYNCAvantagesInconvenients
1. SAI master
(i.MX8MP genere)
SAI7 du SoC Simple a configurer dans le DTS
Pas de dependance sur un codec externe
Jitter eleve : les PLL du SoC (AUDIO_PLL1/2) introduisent un jitter de ~200-500 ps, car elles derivent d’un oscillateur systeme multi-usage
Degradation SNR : le jitter sur BCLK se traduit directement en bruit de phase sur la conversion ADC/DAC
Routage PCB complexe : BCLK sort du SoC, va vers 4 codecs — les traces longues ajoutent du skew
2. Codec master
(TAC5212 #0 genere)
PLL interne du TAC5212 #0
(pas de MCLK — horloge autonome)
Jitter ultra-faible : la PLL audio du TAC5212 est optimisee pour l’audio, jitter < 50 ps RMS
SNR maximal : 119 dB — les horloges sont generees au plus pres des convertisseurs
Routage court : BCLK/FSYNC partent du codec #0 directement vers ses voisins sur le bus TDM
Un seul domaine d’horloge : tous les codecs + SAI7 sont synchronises sur la meme source
Le codec #0 doit demarrer en premier (sequence de boot)
Si le codec #0 tombe, tout le bus TDM s’arrete
3. Oscillateur externe
(horloge independante)
Oscillateur audio dedie sur le PCB Jitter minimal (crystal oscillator)
Independant du SoC
Composant supplementaire, cout PCB
Un signal d’horloge de plus a router
Rarement necessaire avec un codec de qualite

Conclusion : l’option 2 (codec master) est le choix standard dans l’industrie pour les raisons suivantes :

1. Qualite d’horloge superieure

Le TAC5212 integre une PLL audio dediee concue specifiquement pour generer des horloges a faible jitter. Contrairement aux PLL du SoC i.MX8MP qui doivent aussi piloter des bus memoire, des interfaces USB, Ethernet, etc., la PLL du codec n’a qu’un seul role : generer BCLK et FSYNC avec un jitter minimal.

Le jitter sur BCLK est le facteur limitant numero 1 du SNR d’un convertisseur ADC/DAC. Un jitter de 500 ps sur un signal audio a 20 kHz avec un DAC 24-bit degrade le SNR d’environ 6-10 dB. Avec le TAC5212 en master (jitter < 50 ps), on conserve les 119 dB de SNR annonces par Texas Instruments.

2. Simplicite de synchronisation multi-codec

Avec un seul codec generant BCLK/FSYNC :

3. Routage PCB optimal

En mode codec master, les signaux BCLK et FSYNC sont generes physiquement au milieu du bus TDM, la ou sont les codecs. Le trajet est court :

# Trajet des horloges en mode codec master : # # TAC5212 #0 (master) ──BCLK/FSYNC──┬── TAC5212 #1 (target) # ├── TAC5212 #2 (target) # ├── TAC5212 #3 (target) # └── SAI7 (slave) # # Longueur typique des traces : 10-30 mm # Skew max entre codecs : < 1 ns (negligeable a 12.288 MHz) # # Trajet des horloges en mode SAI master : # # i.MX8MP (SAI7) ──BCLK/FSYNC──┬── TAC5212 #0 (target) ~50mm # ├── TAC5212 #1 (target) ~60mm # ├── TAC5212 #2 (target) ~70mm # └── TAC5212 #3 (target) ~80mm # # Les traces plus longues ajoutent du skew et captent plus de bruit

4. Comportement standard I2S/TDM

La specification I2S et TDM prevoit qu’un seul device genere les horloges (le bus master). Dans la majorite des designs audio professionnels et embarques, c’est le codec qui est master, pas le SoC. Les raisons :

/* Extrait du device tree — le codec est master */ simple-audio-card,format = « i2s »; /* ou « dsp_a » pour TDM */ simple-audio-card,bitclock-master = <&codec_dai>; /* BCLK vient du codec */ simple-audio-card,frame-master = <&codec_dai>; /* FSYNC vient du codec */ /* Cela configure SAI7 en mode slave automatiquement. * Le driver fsl_sai.c detecte qu’il n’est pas master * et ne programme pas ses propres diviseurs d’horloge. */

5. Changement de frequence d’echantillonnage simplifie

Un avantage majeur du mode codec master : changer la frequence d’echantillonnage ne necessite qu’une seule commande I2C vers le codec #0. Sa PLL interne recalcule automatiquement BCLK et FSYNC, et tous les devices du bus (targets + SAI7) suivent instantanement sans aucune reconfiguration.

Codec master (TAC5212 #0)SAI master (i.MX8MP)
Passer de 48 kHz a 96 kHz 1 ecriture I2C sur le registre PLL du codec #0
BCLK passe de 12.288 a 24.576 MHz automatiquement
FSYNC passe de 48 a 96 kHz
Les targets et SAI7 suivent sans intervention
Reprogrammer AUDIO_PLL1 dans le CCM du SoC
Recalculer les diviseurs SAI7 (MCLK DIV, BIT CLK DIV)
Risque d’affecter d’autres peripheriques partageant la meme PLL
Necessite potentiellement un arret/relance du flux DMA
Support multi-rate
(44.1 / 48 / 96 / 192 kHz)
Le TAC5212 supporte nativement 8 a 768 kHz
Un seul registre a changer : SAMPLE_RATE_CFG
La PLL interne gere les deux familles (44.1 et 48 kHz)
Le SoC a 2 PLL audio (AUDIO_PLL1 pour 48x, AUDIO_PLL2 pour 44.1x)
Switcher de famille necessite de changer de PLL source
Complexite supplementaire dans le driver fsl_sai.c
Runtime switch
(changement a chaud)
Possible via snd_soc_dai_set_sysclk()
Le codec reconfigure sa PLL en ~1 ms
Transition propre (mute automatique pendant le relock)
Necessite clk_set_rate() sur la PLL du CCM
Temps de relock PLL SoC : 5-10 ms
Risque de glitch audible si le flux n’est pas coupe

En resume, avec le codec master, le changement de sample rate est une operation locale qui ne touche qu’un seul composant (le TAC5212 #0 via I2C). Toute la chaine se reconfigure en cascade, sans intervention logicielle sur les 3 targets ni sur le SoC.

6. Tolerance aux pannes et demarrage

Le seul inconvenient du mode codec master est la dependance au codec #0 pour tout le bus TDM. En pratique, cela se gere facilement :

Driver Linux : pcm6240 (famille TAx5212)

Le TAC5212 est supporte par le driver kernel pcm6240, un driver generique qui couvre 20+ codecs TI de la meme famille (PCM6240, PCM6260, TAA5212, TAD5212, TAC5212, TAC5412-Q1, etc.).

💡
Le driver s’appelle pcm6240, pas tac5212. C’est un driver « famille » qui detecte le type exact du codec via la string compatible dans le device tree. Il est upstream dans le kernel Linux depuis la version 6.6.

Localisation dans les sources kernel

# Fichiers source du driver pcm6240 : sound/soc/codecs/pcm6240.c # Implementation principale du driver sound/soc/codecs/pcm6240.h # Definitions des registres et structures # Kconfig sound/soc/codecs/Kconfig # CONFIG_SND_SOC_PCM6240 # Compatible strings supportees (extrait de pcm6240.c) : # « ti,adc3120 » « ti,adc5120 » « ti,adc6120 » # « ti,dix4192 » « ti,pcm1690 » « ti,pcm3120 » # « ti,pcm3140 » « ti,pcm5120 » « ti,pcm5140 » # « ti,pcm6120 » « ti,pcm6140 » « ti,pcm6240 » # « ti,pcm6260 » « ti,pcm9211 » # « ti,taa5212 » « ti,tad5212 » « ti,tac5212 » <-- notre codec # "ti,tac5412" "ti,pcm5242" "ti,pcm5142"

Configuration kernel

# Activer le driver pcm6240 dans la config kernel : CONFIG_SND_SOC_PCM6240=y # Ou en module : CONFIG_SND_SOC_PCM6240=m # Verifier que le driver est bien compile : $ zcat /proc/config.gz | grep PCM6240 CONFIG_SND_SOC_PCM6240=y # Le module s’appelle snd-soc-pcm6240 : $ modinfo snd-soc-pcm6240

Integration dans Yocto

Pour activer le driver dans votre BSP Yocto i.MX8MP, ajoutez un fragment de configuration kernel dans votre layer :

# Creer le fragment dans votre layer : # meta-monprojet/recipes-kernel/linux/linux-imx/tac5212.cfg CONFIG_SND_SOC_PCM6240=y # Ajouter le fragment dans la recette kernel : # meta-monprojet/recipes-kernel/linux/linux-imx_%.bbappend FILESEXTRAPATHS:prepend := « ${THISDIR}/${PN}: » SRC_URI += « file://tac5212.cfg » # Verifier l’integration : $ bitbake linux-imx -c menuconfig # -> Device Drivers -> Sound card support -> ALSA -> CODEC drivers # -> Texas Instruments PCM6240 family

Verification du driver au boot

# Verifier que le driver s’est bien attache aux codecs : $ dmesg | grep pcm6240 [ 2.341] pcm6240 3-0048: TAC5212 detected, firmware version 1.0 [ 2.345] pcm6240 3-0049: TAC5212 detected, firmware version 1.0 [ 2.348] pcm6240 3-004a: TAC5212 detected, firmware version 1.0 [ 2.351] pcm6240 3-004b: TAC5212 detected, firmware version 1.0 # Scanner le bus I2C pour confirmer les adresses : $ i2cdetect -y 2 0 1 2 3 4 5 6 7 8 9 a b c d e f 40: — — — — — — — — 48 49 4a 4b — — — — # Lire un registre d’identification (registre 0x00 = Device ID) : $ i2cget -y 2 0x48 0x00 0x52 # = TAC5212 # Verifier la carte son ALSA : $ aplay -l **** Liste des Peripheriques PLAYBACK **** carte 0: imx8mptdm8ch [imx8mp-tdm-8ch], peripherique 0: …
📌
Declarer le hardware a Linux. Le codec et le bus TDM sont configures — il faut maintenant les decrire dans le Device Tree pour que le noyau Linux detecte et initialise la carte son. Sans un DTS correct, aucune carte son n’apparait dans ALSA.

Device Tree (DTS)

Activation SAI7 avec pinmux

/* Pinmux SAI7 dans le fichier DTS * Note : SAI7 utilise les pins SAI2 remappees via l’audiomix. * Le pinmux exact depend du PCB. Verifier le schema. */ &iomuxc { pinctrl_sai7: sai7grp { fsl,pins = < /* SAI7 partage le pad group avec SAI2 sur certaines configs. * Adapter selon le schema de votre carte. */ MX8MP_IOMUXC_SAI2_TXFS__AUDIOMIX_SAI7_TX_SYNC 0xd6 MX8MP_IOMUXC_SAI2_TXC__AUDIOMIX_SAI7_TX_BCLK 0xd6 MX8MP_IOMUXC_SAI2_TXD0__AUDIOMIX_SAI7_TX_DATA0 0xd6 MX8MP_IOMUXC_SAI2_RXD0__AUDIOMIX_SAI7_RX_DATA0 0xd6 /* Pas de MCLK : le TAC5212 n'a pas de pin MCLK */ >; }; };

Node SAI7

&sai7 { pinctrl-names = « default »; pinctrl-0 = <&pinctrl_sai7>; assigned-clocks = <&clk IMX8MP_CLK_SAI7>; assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; assigned-clock-rates = <24576000>; /* Pas de fsl,sai-mclk-direction-output : le TAC5212 n’a pas de pin MCLK */ /* SAI7 en slave : BCLK et FSYNC generes par TAC5212 #0 (Controller) */ fsl,sai-synchronous-rx; status = « okay »; };

Exemples DTS complets

Exemple 1 : TAC5212 simple (I2S stereo sur SAI7)

/* Un seul TAC5212 en I2S stereo sur SAI7 * Le codec est en mode Controller (genere BCLK/FSYNC). * SAI7 est en slave. */ &i2c3 { clock-frequency = <400000>; status = « okay »; tac5212: audio-codec@48 { compatible = « ti,tac5212 »; reg = <0x48>; reset-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>; AVDD-supply = <&reg_3v3>; DVDD-supply = <&reg_1v8>; IOVDD-supply = <&reg_1v8>; clocks = <&clk IMX8MP_CLK_SAI7>; clock-names = « mclk »; #sound-dai-cells = <0>; }; }; / { sound-tac5212 { compatible = « simple-audio-card »; simple-audio-card,name = « imx8mp-tac5212 »; simple-audio-card,format = « i2s »; simple-audio-card,bitclock-master = <&codec_dai>; simple-audio-card,frame-master = <&codec_dai>; simple-audio-card,widgets = « Headphone », « HP Out », « Line », « Line In », « Microphone », « Mic In »; simple-audio-card,routing = « HP Out », « OUTA+ », « HP Out », « OUTA-« , « INA1+ », « Line In », « INA1-« , « Line In »; cpu_dai: simple-audio-card,cpu { sound-dai = <&sai7>; }; codec_dai: simple-audio-card,codec { sound-dai = <&tac5212>; }; }; };

Exemple 2 : 4x TAC5212 en TDM sur SAI7 (8 canaux)

/* 4 codecs TAC5212 cascades en TDM sur SAI7 * TAC5212 #0 = Controller (master, genere BCLK/FSYNC) * TAC5212 #1, #2, #3 = Target (slave) * SAI7 en slave (recoit BCLK/FSYNC du codec master) */ &i2c3 { clock-frequency = <400000>; status = « okay »; tac5212_0: audio-codec@48 { compatible = « ti,tac5212 »; reg = <0x48>; reset-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>; AVDD-supply = <&reg_3v3>; DVDD-supply = <&reg_1v8>; IOVDD-supply = <&reg_1v8>; #sound-dai-cells = <0>; /* Mode Controller : genere BCLK et FSYNC */ ti,asi-tx-drive = « controller »; /* Slots TDM 0-1 */ ti,tdm-tx-slots = <0x03>; /* bitmask : slot 0 + slot 1 */ ti,tdm-rx-slots = <0x03>; }; tac5212_1: audio-codec@49 { compatible = « ti,tac5212 »; reg = <0x49>; AVDD-supply = <&reg_3v3>; DVDD-supply = <&reg_1v8>; IOVDD-supply = <&reg_1v8>; #sound-dai-cells = <0>; /* Slots TDM 2-3 */ ti,tdm-tx-slots = <0x0c>; ti,tdm-rx-slots = <0x0c>; }; tac5212_2: audio-codec@4a { compatible = « ti,tac5212 »; reg = <0x4a>; AVDD-supply = <&reg_3v3>; DVDD-supply = <&reg_1v8>; IOVDD-supply = <&reg_1v8>; #sound-dai-cells = <0>; /* Slots TDM 4-5 */ ti,tdm-tx-slots = <0x30>; ti,tdm-rx-slots = <0x30>; }; tac5212_3: audio-codec@4b { compatible = « ti,tac5212 »; reg = <0x4b>; AVDD-supply = <&reg_3v3>; DVDD-supply = <&reg_1v8>; IOVDD-supply = <&reg_1v8>; #sound-dai-cells = <0>; /* Slots TDM 6-7 */ ti,tdm-tx-slots = <0xc0>; ti,tdm-rx-slots = <0xc0>; }; }; &sai7 { pinctrl-names = « default »; pinctrl-0 = <&pinctrl_sai7>; assigned-clocks = <&clk IMX8MP_CLK_SAI7>; assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; assigned-clock-rates = <24576000>; fsl,sai-mclk-direction-output; /* SAI7 en slave : clocks viennent du TAC5212 #0 */ fsl,sai-synchronous-rx; status = « okay »; }; / { sound-tdm { compatible = « simple-audio-card »; simple-audio-card,name = « imx8mp-tdm-8ch »; simple-audio-card,format = « dsp_a »; /* TDM mode */ /* Le codec master genere BCLK et FSYNC */ simple-audio-card,bitclock-master = <&codec0_dai>; simple-audio-card,frame-master = <&codec0_dai>; simple-audio-card,cpu { sound-dai = <&sai7>; dai-tdm-slot-num = <8>; dai-tdm-slot-width = <32>; }; /* 4 DAI links multi-codec */ codec0_dai: simple-audio-card,codec@0 { sound-dai = <&tac5212_0>; }; simple-audio-card,codec@1 { sound-dai = <&tac5212_1>; }; simple-audio-card,codec@2 { sound-dai = <&tac5212_2>; }; simple-audio-card,codec@3 { sound-dai = <&tac5212_3>; }; }; };

Exemple 3 : SAI7 + EASRC + HDMI

/* Configuration avec EASRC pour convertir entre SAI7 (48kHz) et HDMI (variable) */ &easrc { fsl,asrc-rate = <48000>; fsl,asrc-format = <2>; /* S24_LE */ status = « okay »; }; /* La carte son peut router l’audio via EASRC : SAI7 (48kHz) –> EASRC (conversion) –> HDMI TX (44.1/96/192 kHz) HDMI RX (eARC, variable) –> EASRC (48kHz) –> SAI7 –> codec */

Kernel config audio

# Configuration kernel requise pour l’audio i.MX8MP # Core ALSA CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_SOC_IMX_PCM_DMA=y # SAI driver CONFIG_SND_SOC_FSL_SAI=y # EASRC CONFIG_SND_SOC_FSL_EASRC=y # MICFIL CONFIG_SND_SOC_FSL_MICFIL=y # Machine driver CONFIG_SND_IMX_SOF=y CONFIG_SND_SOC_IMX_CARD=y CONFIG_SND_SIMPLE_CARD=y # SOF (Sound Open Firmware) CONFIG_SND_SOC_SOF=y CONFIG_SND_SOC_SOF_IMX8M=y CONFIG_SND_SOC_SOF_IMX_COMMON=y CONFIG_SND_SOC_SOF_XTENSA=y # Codec TAC5212 (driver pcm6240 family — upstream depuis kernel 6.6) CONFIG_SND_SOC_PCM6240=y # HDMI audio CONFIG_SND_SOC_IMX_HDMI=y # SDMA (DMA audio) CONFIG_IMX_SDMA=y
📌
Le stack logiciel. Le Device Tree est en place, la carte son est detectee. Nous pouvons maintenant utiliser ALSA et le framework ASoC pour capturer, jouer et mixer l’audio depuis l’espace utilisateur.

ALSA / ASoC

Le sous-systeme audio Linux repose sur ALSA (Advanced Linux Sound Architecture) et son extension ASoC (ALSA System on Chip) qui decompose le driver en trois composants :

ComposantRoleExemple i.MX8MP
Platform driverDMA et interface materiellesnd-soc-fsl-sai, imx-pcm-dma
Codec driverPilote du codec audio (ADC/DAC)snd-soc-wm8960, snd-soc-pcm6240 (TAC5212)
Machine driverLien entre platform et codecsnd-soc-imx-card, simple-audio-card

DAPM (Dynamic Audio Power Management)

DAPM gere automatiquement l’alimentation des widgets audio. Seuls les chemins audio actifs sont alimentes, economisant l’energie.

# Voir les widgets DAPM et leur etat cat /sys/kernel/debug/asoc/imx-audio-tac5212/dapm/*/status # Voir les routes audio actives cat /sys/kernel/debug/asoc/imx-audio-tac5212/dapm/*/routes

Commandes ALSA

Lister les cartes et peripheriques

# Lister les cartes son aplay -l # **** Liste des Peripheriques Materiels PLAYBACK **** # carte 0: imxaudiotac5212 [imx-audio-tac5212], peripherique 0: … # carte 1: imxhdmi [imx-hdmi], peripherique 0: … # Lister les PCM disponibles aplay -L arecord -L # Informations detaillees sur une carte cat /proc/asound/cards cat /proc/asound/card0/pcm0p/info

Lecture (aplay)

# Lecture basique aplay -D hw:0,0 fichier.wav # Lecture avec format specifique aplay -D hw:0,0 -f S24_LE -r 48000 -c 2 fichier.raw # Lecture multi-canal (8 canaux TDM) aplay -D hw:0,0 -f S32_LE -r 48000 -c 8 fichier_8ch.raw # Lecture avec buffer reduit (faible latence) aplay -D hw:0,0 –period-size=256 –buffer-size=1024 -f S24_LE -r 48000 fichier.wav # Test des haut-parleurs speaker-test -D hw:0,0 -c 2 -r 48000 -t sine -f 1000 speaker-test -D hw:0,0 -c 8 -r 48000 -t wav # test multicanal

Capture (arecord)

# Capture stereo 48kHz 24-bit arecord -D hw:0,0 -f S24_LE -r 48000 -c 2 -d 10 capture.wav # Capture multicanal TDM 8 canaux arecord -D hw:0,0 -f S32_LE -r 48000 -c 8 -d 5 capture_8ch.wav # Capture continue vers stdout (pipe vers traitement) arecord -D hw:0,0 -f S24_LE -r 48000 -c 2 -t raw | ./mon_traitement # Capture PDM microphones (MICFIL) arecord -D hw:1,0 -f S24_LE -r 16000 -c 4 -d 10 capture_pdm.wav # Capture avec vumetre arecord -D hw:0,0 -f S24_LE -r 48000 -c 2 -V stereo /dev/null

Controle mixer (amixer / tinymix)

# Lister tous les controles amixer -c 0 contents amixer -c 0 scontrols # Regler le volume de sortie amixer -c 0 sset ‘DAC’ 80% amixer -c 0 sset ‘Headphone’ 120 # Regler le gain d’entree amixer -c 0 sset ‘ADC PGA Gain’ 20dB amixer -c 0 sset ‘Capture Volume’ 80% # Activer/desactiver un chemin amixer -c 0 sset ‘Left Input Mux’ ‘Differential’ amixer -c 0 sset ‘Right Input Mux’ ‘Differential’ # Sauvegarder / restaurer la config alsactl store -f /etc/asound.state alsactl restore -f /etc/asound.state # — tinymix (TinyALSA, plus leger) — # Lister les controles tinymix -D 0 # Lire un controle tinymix -D 0 get « DAC Volume » # Ecrire un controle tinymix -D 0 set « DAC Volume » 200 # — tinyplay / tinycap — tinyplay fichier.wav -D 0 -d 0 tinycap capture.wav -D 0 -d 0 -c 2 -r 48000 -b 24

ALSA avance

Configuration asound.conf

# /etc/asound.conf – Configuration ALSA globale # Definir la carte par defaut pcm.!default { type plug slave.pcm « dmixer » } # Mixer logiciel (permet plusieurs applications simultanees) pcm.dmixer { type dmix ipc_key 1024 slave { pcm « hw:0,0 » period_time 0 period_size 1024 buffer_size 4096 rate 48000 format S24_LE channels 2 } } # Loopback : capturer la sortie audio pcm.loopback { type plug slave.pcm « hw:2,0 » } # Multi-canal : mapper les canaux TDM pcm.tdm8ch { type plug slave { pcm « hw:0,0 » channels 8 format S32_LE rate 48000 } ttable { 0.0 1 # canal 0 -> slot 0 1.1 1 # canal 1 -> slot 1 2.2 1 # canal 2 -> slot 2 3.3 1 # canal 3 -> slot 3 4.4 1 # canal 4 -> slot 4 5.5 1 # canal 5 -> slot 5 6.6 1 # canal 6 -> slot 6 7.7 1 # canal 7 -> slot 7 } } # Multi-canal avec downmix stereo pcm.stereo_from_8ch { type route slave { pcm « hw:0,0 » channels 8 } ttable { 0.0 0.5 # gauche = mix(slot0 + slot2) 0.2 0.5 1.1 0.5 # droite = mix(slot1 + slot3) 1.3 0.5 } }

Mesurer la latence

# Formats supportes par le peripherique cat /proc/asound/card0/pcm0p/sub0/hw_params # Latence = period_size / sample_rate # Ex: period_size=256, rate=48000 -> latence = 5.33 ms # Round-trip (capture+playback) : ~10.67 ms avec 2 periodes # Verifier les xruns (depassements de buffer) cat /proc/asound/card0/pcm0p/sub0/status # xruns doit rester a 0 pour un flux stable
📌
Traitement audio sur le DSP. ALSA transporte les echantillons, mais le DSP HiFi4 @ 800 MHz est la ou le traitement se fait : filtrage, EQ, DRC, beamforming — le tout en temps reel, sans charger le CPU A53.

HiFi4 DSP

Le Cadence HiFi4 DSP est un processeur de signal numerique dedie, optimise pour le traitement audio. Il tourne a 800 MHz et dispose de son propre bus AXI, DTCM/ITCM et acces a la DRAM partagee.

ParametreSpecification
CoeurCadence Tensilica HiFi4
Frequence800 MHz
ArchitectureVLIW, 2x MAC 32×32, 4x MAC 16×16
ITCM64 Ko (instructions, acces cycle unique)
DTCM64 Ko (donnees, acces cycle unique)
DRAM partageeAcces a la DRAM via AXI
PeripheriquesSAI6, SAI7 (acces direct)
CommunicationMailbox (MU) + shared memory + rpmsg
Firmware loadremoteproc ou custom loader

Communication ARM ↔ DSP

graph LR
    subgraph A53["Cortex-A53 (Linux)"]
        direction TB
        APP["Application
(aplay, gst-launch)"] ALSA["ALSA / ASoC"] RPMSG_A["rpmsg driver"] SHM_A["Shared Memory"] APP --> ALSA --> RPMSG_A --> SHM_A end subgraph DSP["HiFi4 DSP"] direction TB FW["Firmware DSP
(SOF / NXP fw)"] PIPE["Audio Pipeline"] RPMSG_D["rpmsg-lite"] SHM_D["Shared Memory"] FW --> PIPE --> RPMSG_D --> SHM_D end RPMSG_A -- "MU (Mailbox)" --- RPMSG_D SHM_A -- "DRAM (DMA)" --- SHM_D style A53 fill:#eff6ff,stroke:#2563eb,stroke-width:2px style DSP fill:#fef3c7,stroke:#d97706,stroke-width:2px

Firmware NXP (imx-audio-framework)

NXP fournit son propre framework DSP (imx-audio-framework) qui tourne sur le HiFi4. Il est oriente decodage audio avec offloading du CPU.

Codecs supportes (decodage DSP)

CodecLibrairie DSPFormats
MP3lib_dsp_mp3_dec.soMPEG-1/2 Layer III, 8-48 kHz
AAClib_dsp_aac_dec.soAAC-LC, HE-AAC v1/v2, 8-48 kHz
FLAClib_dsp_flac_dec.soFLAC 1.0, 16/24-bit, jusqu’a 192 kHz
Vorbislib_dsp_vorbis_dec.soOgg Vorbis, 8-48 kHz
SBClib_dsp_sbc_dec.soSBC (Bluetooth audio)
PCM/WAVnatifPCM brut, 8-384 kHz, 16/24/32 bits

Architecture du framework NXP

graph LR
    subgraph LINUX["Linux (A53)"]
        direction TB
        APP2["Application
(aplay, gst-launch)"] WRAP["dsp_wrapper
lib_dsp_wrap.so"] RPMSG2["rpmsg char driver"] SHM2["shared memory (DRAM)"] APP2 --> WRAP --> RPMSG2 --> SHM2 end subgraph DSP2["DSP (HiFi4)"] direction TB FW2["dsp_framework"] SRC["audio_source"] DEC["decoder
(MP3/AAC/FLAC)"] PP["post_process"] SINK["audio_sink (SAI7)"] FW2 --> SRC --> DEC --> PP --> SINK RPMSG3["rpmsg-lite"] SBUF["shared buffer"] RPMSG3 --> SBUF end RPMSG2 -- "MU" --- RPMSG3 SHM2 -- "DMA" --- SBUF style LINUX fill:#eff6ff,stroke:#2563eb,stroke-width:2px style DSP2 fill:#fef3c7,stroke:#d97706,stroke-width:2px
# Flow typique : # 1. ARM lit le fichier MP3 depuis le filesystem # 2. ARM ecrit les trames encodees dans le buffer partage # 3. DSP decode les trames en PCM # 4. DSP envoie le PCM vers SAI7 (sortie audio) # 5. Le CPU A53 est libre pour d’autres taches

Utilisation

# Charger le firmware DSP echo /lib/firmware/imx/dsp/hifi4.bin > /sys/class/remoteproc/remoteproc0/firmware echo start > /sys/class/remoteproc/remoteproc0/state # Lire un MP3 via le DSP (CPU offload) dsp_test -t mp3 -f musique.mp3 # Lire un AAC via le DSP dsp_test -t aac -f audio.aac # Pipeline GStreamer avec decodage DSP gst-launch-1.0 filesrc location=musique.mp3 ! mpegaudioparse ! dspmp3dec ! audioconvert ! alsasink
Limitations du framework NXP : Le framework proprietaire est oriente decodage uniquement. Il ne supporte pas nativement les effets audio (EQ, DRC, compression), le mixage multi-source, ni les topologies complexes. Pour ces cas, privilegiez SOF.

SOF (Sound Open Firmware)

Sound Open Firmware est un projet open-source (Linux Foundation) qui fournit un firmware DSP complet avec un pipeline audio configurable. SOF est supporte sur i.MX8MP et represente l’avenir du traitement audio embarque.

🔧 SOF vs Firmware NXP

Firmware NXP

  • Proprietaire
  • Oriente decodage audio
  • Codecs fixes (MP3, AAC, FLAC…)
  • Pas d’effets configurables
  • Pipeline statique
  • Mieux documente par NXP

SOF

  • Open-source (BSD-3)
  • Pipeline audio complet et flexible
  • EQ (IIR/FIR), DRC, Volume, Mixer
  • Beamforming (TDFB)
  • Topologies dynamiques
  • Base Zephyr RTOS sur HiFi4
  • Communaute active (Intel + NXP)

Build SOF pour i.MX8MP

# — Methode 1 : Build avec Zephyr (recommande) — # Installer west (outil Zephyr) pip3 install west # Initialiser le workspace SOF west init -m https://github.com/thesofproject/sof sof-workspace cd sof-workspace west update # Builder le firmware pour i.MX8MP cd sof python3 scripts/xtensa-build-zephyr.py imx8m # Le firmware est genere dans : # build-imx8m/zephyr/zephyr.ri -> /lib/firmware/imx/sof/sof-imx8m.ri # Builder les topologies cd tools/topology make # Topologies dans : /lib/firmware/imx/sof-tplg/ # — Methode 2 : Build avec Docker — docker run -it –rm \ -v $(pwd):/sof \ thesofproject/sof \ ./scripts/xtensa-build-zephyr.py imx8m

Installer SOF sur la cible

# Copier le firmware scp sof-imx8m.ri root@cible:/lib/firmware/imx/sof/ # Copier les topologies scp sof-tplg/*.tplg root@cible:/lib/firmware/imx/sof-tplg/ # Charger le driver SOF (kernel config requise) # CONFIG_SND_SOC_SOF=y # CONFIG_SND_SOC_SOF_IMX8M=y # CONFIG_SND_SOC_SOF_IMX_COMMON=y # Verifier le chargement dmesg | grep sof # sof-imx8m-dsp: firmware loaded: sof-imx8m.ri # sof-imx8m-dsp: topology loaded: sof-imx8mp-eq-iir-drc.tplg

Composants SOF disponibles

ComposantDescriptionCas d’usage
VolumeControle de gain numerique par canalMixage, fade in/out, mute
MixerMixage multi-source (N entrees → 1 sortie)Superposer musique + voix + notif
MUX/DEMUXRoutage de canaux, selection de sourceRouter mic vers enregistrement ou communication
IIR EQEgaliseur a reponse impulsionnelle infinieBass boost, treble, correction de salle
FIR EQEgaliseur a reponse impulsionnelle finieFiltre passe-bas/haut precis, crossover
DRCCompresseur de dynamiqueLimiter, compresseur, noise gate
Multiband DRCDRC multi-bande (3 bandes)Mastering, loudness, protection HP
TDFBTime Domain Fixed BeamformerArray de microphones, rejection bruit directionnel
SRCSample Rate ConverterConversion de frequence DSP (alternative a EASRC)
DCBLOCKFiltre DC offset removalSupprimer la composante continue
CrossoverFiltre de coupure multi-voieSeparer bass/mid/treble pour multi-ampli
SMART_AMPAmplificateur intelligentProtection des haut-parleurs
NXP EAPEffets audio NXP (bass boost, loudness)Enrichissement audio proprietaire

Topologies SOF

La topologie definit le graphe de traitement audio charge sur le DSP. Elle est compilee en fichier .tplg et chargee au demarrage.

Topologies disponibles pour i.MX8MP

# Lister les topologies installees ls /lib/firmware/imx/sof-tplg/ # Topologies typiques : # sof-imx8mp-wm8960.tplg -> Passthrough basique (WM8960) # sof-imx8mp-eq-iir.tplg -> Egaliseur IIR # sof-imx8mp-eq-fir.tplg -> Egaliseur FIR # sof-imx8mp-drc.tplg -> Compresseur de dynamique # sof-imx8mp-eq-iir-drc.tplg -> EQ IIR + DRC # sof-imx8mp-mixer.tplg -> Mixeur multi-source # sof-imx8mp-src.tplg -> Sample Rate Converter # sof-imx8mp-tdfb.tplg -> Beamformer micro array # sof-imx8mp-multiband-drc.tplg -> DRC 3 bandes

Changer de topologie

# Arreter le DSP echo stop > /sys/class/remoteproc/remoteproc0/state # Changer la topologie via le module param # Option 1 : lien symbolique cd /lib/firmware/imx/sof-tplg/ ln -sf sof-imx8mp-eq-iir-drc.tplg sof-imx8mp.tplg # Option 2 : parametre module (dans le DTS ou cmdline) # sof_imx8.tplg_filename=sof-imx8mp-eq-iir-drc.tplg # Redemarrer le DSP echo start > /sys/class/remoteproc/remoteproc0/state

Exemple : pipeline EQ IIR + DRC

graph LR
    CP["Capture PCM"] --> CV["Volume"] --> CE["EQ IIR"] --> CD["DRC"] --> CO["DAI SAI7 OUT"]
    style CP fill:#f0fdf4,stroke:#10b981
    style CV fill:#f0fdf4,stroke:#10b981
    style CE fill:#f0fdf4,stroke:#10b981
    style CD fill:#f0fdf4,stroke:#10b981
    style CO fill:#f0fdf4,stroke:#10b981
            

↓ Capture → Playback

graph LR
    PI["DAI SAI7 IN"] --> PD["DRC"] --> PE["EQ IIR"] --> PV["Volume"] --> PO["Playback PCM"]
    style PI fill:#eff6ff,stroke:#2563eb
    style PD fill:#eff6ff,stroke:#2563eb
    style PE fill:#eff6ff,stroke:#2563eb
    style PV fill:#eff6ff,stroke:#2563eb
    style PO fill:#eff6ff,stroke:#2563eb
            
# Topologie : sof-imx8mp-eq-iir-drc.tplg # # Le EQ corrige la reponse frequentielle # Le DRC compresse la dynamique et protege les HP # Controler l’EQ en runtime via sof-ctl sof-ctl -D hw:0 -c name=’EQIIR0.0 eqiir_coef_0′ -s eq_iir_coef_flat.txt sof-ctl -D hw:0 -c name=’EQIIR0.0 eqiir_coef_0′ -s eq_iir_coef_bass_boost.txt # Controler le DRC sof-ctl -D hw:0 -c name=’DRC0.0 drc_coef_0′ -s drc_coef_default.txt

Effets audio DSP

Voici des exemples concrets d’effets audio realisables sur le HiFi4 avec SOF :

Egaliseur parametrique (IIR Biquad)

# Generer les coefficients d’un EQ parametrique # Outil : sof/tools/tune/eq/eq_iir_blob_gen.m (Octave/Matlab) # Exemple : bass boost +6dB a 100Hz, Q=0.7 # Coefficients biquad (format SOF) : # Type: peaking, Freq: 100, Gain: 6.0, Q: 0.707 # Type: peaking, Freq: 3000, Gain: -3.0, Q: 1.0 # Type: highshelf, Freq: 8000, Gain: 2.0, Q: 0.707 # Charger les coefficients sof-ctl -D hw:0 -c name=’EQIIR0.0 eqiir_coef_0′ -br -s bass_boost.txt # Fichier de coefficients (format binaire blob) : # Genere avec eq_iir_blob_gen.m ou sof-ctl-ipc4.py

Compresseur de dynamique (DRC)

# Parametres DRC typiques : # threshold: -20 dBFS (seuil de declenchement) # ratio: 4:1 (taux de compression) # attack: 5 ms (temps d’attaque) # release: 100 ms (temps de relachement) # makeup_gain: +10 dB (gain de compensation) # knee: 6 dB (largeur du coude) # Le DRC SOF supporte : # – Compresseur standard # – Limiteur (ratio infini) # – Noise gate (expansion sous le seuil) # – Mode multi-bande (3 bandes avec crossover) # Charger une config DRC sof-ctl -D hw:0 -c name=’DRC0.0 drc_coef_0′ -br -s drc_compressor.txt

Filtre FIR (crossover, anti-alias)

# Generer un filtre FIR passe-bas 4kHz (crossover) # Outil : sof/tools/tune/eq/eq_fir_blob_gen.m # Exemple avec Python + scipy : # from scipy.signal import firwin # coeffs = firwin(128, 4000, fs=48000) # -> Exporter en format SOF blob # Charger le filtre sof-ctl -D hw:0 -c name=’EQFIR0.0 eqfir_coef_0′ -br -s crossover_lpf_4k.txt

Beamforming micro array (TDFB)

# Le TDFB (Time Domain Fixed Beamformer) applique des # delais et gains par microphone pour focaliser la # captation dans une direction donnee. # Configuration typique : array lineaire 4 mics, espacement 50mm # Direction cible : 0 degres (face) # Rejet lateral : -20 dB # Les coefficients sont precalcules avec les outils SOF : # sof/tools/tune/tdfb/tdfb_design.m (Matlab/Octave) # Charger la config beamformer sof-ctl -D hw:0 -c name=’TDFB0.0 tdfb_coef_0′ -br -s beam_0deg.txt
📌
Aller plus loin : IA et pipeline complet. Le DSP gere le traitement audio classique. Pour des taches plus complexes (classification de sons, debruitage neuronal, detection d’anomalies), le NPU Vivante (2.3 TOPS) prend le relais. Cette section montre comment combiner DSP + NPU dans un pipeline temps reel.

NPU pour l’audio

Le NPU VIP8000 (2.3 TOPS) peut etre utilise pour des taches d’inference IA sur l’audio, en complement du DSP pour le traitement signal classique.

Cas d’usage NPU audio

ApplicationModele typeEntreePerformance
Noise ReductionRNNoise, DTLN, DeepFilterNetSpectrogramme / frames PCM< 5 ms par frame (16 kHz)
Keyword DetectionMicro Speech (TFLM), kws_ref_modelMFCC features (16 kHz)< 10 ms inference
Speech EnhancementConv-TasNet, DCCRNSignal temporel / complexeTemps reel a 16 kHz
Speaker IDX-Vector, ECAPA-TDNNMel spectrogramme~50 ms par utterance
Speech-to-TextWhisper Tiny (quantize INT8)Mel spectrogramme 80-bin~3x temps reel
Audio ClassificationYAMNet, AudioSetMel spectrogramme< 20 ms inference

Exemple : RNNoise sur NPU

# Pipeline : DSP capture -> NPU denoise -> DSP sortie # # 1. Le DSP capture les frames audio via SAI (16 kHz, mono) # 2. Le DSP calcule les features (MFCC ou bandes Bark) # 3. Les features sont envoyees au NPU via shared memory # 4. Le NPU execute le modele RNNoise (TFLite + VX Delegate) # 5. Le NPU retourne les gains par bande # 6. Le DSP applique les gains spectraux (debruitage) # 7. Le DSP envoie l’audio debruite vers SAI sortie # Quantizer et convertir le modele pour le NPU : # 1. Exporter le modele en TFLite (INT8) vela –accelerator-config ethos-u55-256 rnnoise_model.tflite # Ou utiliser le toolkit eIQ NXP # 2. Executer l’inference /usr/bin/tensorflow-lite-vx-delegate \ –model rnnoise_int8.tflite \ –input audio_features.bin \ –output gains.bin

Pipeline complet SAI → DSP → NPU → DSP

Le pipeline audio complet multivoie combine le DSP HiFi4 et le NPU dans une chaine de traitement temps reel :

# ==================================================================== # PIPELINE MULTIVOIE TEMPS REEL # ==================================================================== # # ENTREE (4x stereo = 8 canaux via TDM sur SAI7) # ====== # TAC5212 #0 (2ch ADC, master) –TDM slot 0-1–> SAI7 RX –> DSP HiFi4 # TAC5212 #1 (2ch ADC, slave) –TDM slot 2-3–> SAI7 RX –> DSP HiFi4 # TAC5212 #2 (2ch ADC, slave) –TDM slot 4-5–> SAI7 RX –> DSP HiFi4 # TAC5212 #3 (2ch ADC, slave) –TDM slot 6-7–> SAI7 RX –> DSP HiFi4 # # TRAITEMENT DSP (pre-processing) # =============== # Pour chaque canal : # 1. DC Block (supprimer offset) # 2. HPF 80 Hz (supprimer les infra) # 3. Gain / Volume # 4. EASRC si necessaire (resample vers 16 kHz pour NPU) # # TRAITEMENT NPU (inference IA) # ============= # 5. Feature extraction (MFCC 40 bins, fenetres 25ms, hop 10ms) # 6. RNNoise / DTLN : debruitage par bande spectrale # 7. KWD : detection de mot-cle (optionnel, en parallele) # 8. Speaker ID : identification du locuteur (optionnel) # # TRAITEMENT DSP (post-processing) # =============== # Pour chaque canal de sortie : # 9. Application des gains NPU (debruitage spectral) # 10. EQ parametrique IIR (correction de salle / HP) # 11. DRC multi-bande (compression 3 bandes) # 12. Crossover (separation bass/mid/treble) # 13. Mixage multi-source (voix + musique + notifications) # 14. Limiteur de sortie (protection des transducteurs) # # SORTIE (multivoie via SAI7 TX) # ====== # DSP HiFi4 –PCM–> SAI7 TX slot 0-1 –TDM–> TAC5212 #0 DAC (HP L/R) # DSP HiFi4 –PCM–> SAI7 TX slot 2-3 –TDM–> TAC5212 #1 DAC (Sub + Center) # DSP HiFi4 –PCM–> SAI7 TX slot 4-5 –TDM–> TAC5212 #2 DAC (Surround L/R) # DSP HiFi4 –PCM–> SAI7 TX slot 6-7 –TDM–> TAC5212 #3 DAC (Monitoring)
📌
Mise en production. Le pipeline fonctionne. Il reste a l’optimiser pour le temps reel (latence, priorites, isolation CPU) et a l’integrer avec les frameworks utilisateur comme PipeWire ou GStreamer.

Audio temps reel

Latence et buffers

ParametreValeur typiqueImpact latence
Period size256 frames5.33 ms @ 48 kHz
Buffer size1024 frames (4 periodes)21.33 ms buffer total
Latence capture~5-10 ms1-2 periodes
Latence playback~5-10 ms1-2 periodes
Round-trip total~15-25 msCapture + DSP + Playback
DSP traitement< 1 msPipeline SOF complet
NPU inference~5-10 msSelon modele et taille

Optimisations temps reel

# 1. Kernel PREEMPT_RT # Activer le patch PREEMPT_RT dans le kernel Linux # CONFIG_PREEMPT_RT=y # 2. Priorite temps reel pour les threads audio chrt -f 80 aplay -D hw:0,0 fichier.wav # Ou avec nice : nice -n -20 aplay -D hw:0,0 fichier.wav # 3. Desactiver le CPU frequency scaling echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor echo performance > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor echo performance > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor echo performance > /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor # 4. Isoler un coeur CPU pour l’audio (kernel cmdline) # isolcpus=3 nohz_full=3 rcu_nocbs=3 # Puis pincer le thread audio sur ce coeur : taskset -c 3 ./mon_app_audio # 5. Reduire la taille des periodes ALSA aplay -D hw:0,0 –period-size=128 –buffer-size=512 fichier.wav # Latence = 128/48000 = 2.67 ms par periode # 6. Verifier les xruns cat /proc/asound/card0/xrun_debug echo 7 > /proc/asound/card0/pcm0p/xrun_debug # debug verbeux

PipeWire / GStreamer

PipeWire

# PipeWire remplace PulseAudio et JACK, unifiant audio et video # Verifier le statut pw-cli info wpctl status # Lister les noeuds audio pw-cli list-objects Node # Regler le volume wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.8 # Configuration faible latence dans /etc/pipewire/pipewire.conf # context.properties = { # default.clock.rate = 48000 # default.clock.quantum = 256 # default.clock.min-quantum = 128 # default.clock.max-quantum = 1024 # }

GStreamer pipelines audio

# Lecture fichier vers ALSA gst-launch-1.0 filesrc location=musique.wav ! wavparse ! audioconvert ! alsasink device=hw:0,0 # Capture micro vers fichier gst-launch-1.0 alsasrc device=hw:0,0 ! audioconvert ! wavenc ! filesink location=capture.wav # Reechantillonnage gst-launch-1.0 filesrc location=audio_44100.wav ! wavparse ! audioresample ! \ « audio/x-raw,rate=48000 » ! audioconvert ! alsasink device=hw:0,0 # Mixage de deux sources gst-launch-1.0 audiomixer name=mix ! audioconvert ! alsasink device=hw:0,0 \ filesrc location=musique.wav ! wavparse ! audioconvert ! mix. \ alsasrc device=hw:1,0 ! audioconvert ! mix. # Streaming RTP audio multicanal gst-launch-1.0 alsasrc device=hw:0,0 num-buffers=-1 ! \ « audio/x-raw,rate=48000,channels=2,format=S24LE » ! \ audioconvert ! rtpL24pay ! udpsink host=192.168.1.100 port=5004 # Lecture depuis flux RTP gst-launch-1.0 udpsrc port=5004 ! « application/x-rtp » ! rtpL24depay ! \ audioconvert ! alsasink device=hw:0,0 # Pipeline VU-metre en temps reel gst-launch-1.0 alsasrc device=hw:0,0 ! audioconvert ! level ! fakesink

Troubleshooting

ProblemeCause probableSolution
Pas de carte son detectee SAI ou codec desactive dans DTS Verifier status = « okay » sur SAI + codec + sound node
Son distordu / crachements Mauvais BCLK ratio ou PLL du codec non verrouillee Verifier que BCLK = Fs * slot_width * nb_slots (ex: 48000 * 32 * 8 = 12.288 MHz)
xruns (under/overruns) Latence trop faible ou CPU charge Augmenter period-size, utiliser PREEMPT_RT, isoler CPU
Canaux permutes en TDM Slot offset incorrect Verifier dai-tdm-slot-tx-mask / rx-mask
Codec I2C non detecte Adresse I2C ou reset GPIO i2cdetect -y 2 pour scanner le bus
EASRC firmware manquant firmware-imx absent Verifier /lib/firmware/imx/easrc/
DSP ne demarre pas Firmware absent ou corrupted Verifier dmesg | grep remoteproc et firmware path
SOF topology erreur Incompatibilite firmware/tplg Recompiler topologie avec meme version SOF que le firmware

Commandes de debug

# Etat complet du sous-systeme audio cat /proc/asound/cards cat /proc/asound/card0/pcm0p/sub0/hw_params cat /proc/asound/card0/pcm0p/sub0/status # Debug ASoC cat /sys/kernel/debug/asoc/components cat /sys/kernel/debug/asoc/dais cat /sys/kernel/debug/asoc/codecs # Scanner I2C (trouver le codec) i2cdetect -y 2 # Lire un registre codec i2cget -y 2 0x48 0x00 # Debug clocks audio cat /sys/kernel/debug/clk/audio_pll1_out/clk_rate cat /sys/kernel/debug/clk/sai7_root_clk/clk_rate # Debug DSP cat /sys/class/remoteproc/remoteproc0/state cat /sys/class/remoteproc/remoteproc0/name dmesg | grep -i « sof\|hifi4\|dsp\|remoteproc » # Debug DMA cat /proc/interrupts | grep sdma cat /sys/kernel/debug/dmaengine/summary

Ressources

Documentation NXP

Sound Open Firmware

Texas Instruments

Communaute

i.MX8M Plus →
Presentation complete du SoC : CPU, GPU, NPU, DSP, video, connectivite.
Yocto BSP →
Build, paquets NXP, images, layers, customisation, deploiement.

Besoin d’expertise audio sur i.MX8MP ?

Integration codec, pipeline DSP/NPU temps reel, multivoie TDM, SOF, ALSA — c’est mon activite principale. Parlons de votre projet.

Discuter de votre projet audio →