
Dans cet article, nous partagerons notre expérience dans le développement de cartes d'interface de l'unité d'interface basée sur le SoC ARM + FPGA Xilinx Zynq 7000. Les cartes ont été conçues pour enregistrer des signaux vocaux au format analogique et numérique PRI / BRI (ISDN, E1 / T1). Le dispositif final lui-même sera utilisé pour enregistrer les négociations dans l'aviation civile.
Iron: sélection de la plate-forme matérielle de l'appareil
Le choix de la plate-forme matérielle a été déterminé par la prise en charge des protocoles PRI / BRI, qui ne peuvent être mis en œuvre que du côté FPGA. Les microcontrôleurs (MCU) et les microprocesseurs (MPU) ne convenaient pas.
On pourrait choisir deux solutions à ce problème:
- Microblaze IP core synthese
- SoC Zynq-7000.
Nous avons opté pour un système sur puce Zynq 7000 (SoC), car il est plus facile d'écrire des applications logicielles et offre plus de fonctionnalités pour les tâches actuelles et futures.
Au total, la liste de fer suivante a été collectée dans le cadre du projet:
1.Xilinx Zynq 7020 (
Mars-ZX3 et
Mars EB1 )
Enclustra Mars ZX3 SOM
Plinthe Enclustra Mars EB12. TI TLV320AIC34 (
tlv320aic34evm-k et carte mère USB).
Carte de débogage pour TLV320AIC34 (TLV320AIC34EVM-K)
Carte d'extension USB-MODEVM pour TLV320AIC34EVM-K3. IDT82P2288 - Microcircuits PRI, XHFC-4SU - BRI, il n'y avait pas de kits de débogage, nous n'avons donc posé que les bases d'un noyau ip pour les tests, et le baptême du feu s'est produit en plein processus, après avoir fabriqué des cartes prototypes.
Travailler avec le système sur la puce Xilinx Zynq 7000
La structure interne du SoC Xilinx Zynq 7000
Étapes pour générer des fichiers de démarrage pour Xilinx ZynqLe clignotement / téléchargement des exécutables pour Zynq est différent du téléchargement habituel pour MPU. Le travail habituel avec les processeurs Cortex-A consiste à charger u-boot, kernel linux, rootfs. Et sur Zynq, le bitstream apparaît, le fichier du firmware pour les FPGA. Le train de bits contient une description des blocs matériels du FPGA et de la communication interne avec le processeur. Ce fichier est chargé au démarrage du système. Du côté de Linux, il existe également un mécanisme qui vous permet de flasher la pièce PL immédiatement pendant le fonctionnement, un tel appareil est appelé xdevcfg (
gestionnaire ZYNQ FPGA depuis 2018.1 ).
Interfaces PRI / BRI
Caractéristiques des réseaux numériques PRI / BRIL'interface à débit primaire (PRI) est une interface réseau RNIS standard qui définit la discipline de connexion des stations RNIS à des circuits à large bande qui connectent les commutateurs locaux et centraux ou les commutateurs de réseau.
Type de trame transmise pour PRI
Vue de la trame transmise pour BRI
La structure interne de la physique PRI - IDT82P2288
La structure interne de la physique BRI - XHFC-4SUCodec audio TLV320AIC34
Le
codec audio TLV320AIC34 basse consommation à quatre canaux pour l'audio et la téléphonie portables est une bonne solution pour une utilisation en téléphonie analogique.
Tlv320aic34 Partie A, le codec audio contient deux de ces blocs fonctionnelsLes données peuvent être transmises via l'interface I2S, ainsi que via DSP, PCM, TDM.
I2S est une norme d'interface de bus série, il est utilisé pour connecter des appareils audio numériques et représente électriquement 3 conducteurs qui vont d'un appareil actif à un appareil passif, ainsi que 4 signaux qui leur correspondent comme suit:
- Horloge Bit (BCLK).
- Synchronisation de trame de signal d'horloge (selon les mots) (WCLK).
- Signal de données qui peut émettre ou recevoir 2 canaux divisés dans le temps (DIN / DOUT).
Les canaux pour recevoir et transmettre des données sont divisés, c'est-à -dire qu'il existe un canal séparé pour recevoir des données et un canal pour la transmission. Le contrôleur reçoit les données transmises par le codec audio, mais l'inverse est également possible.
Cadre I2S, caractéristiques de l'interface I2SAprès avoir sélectionné tous les composants matériels, nous avons résolu le problème de connexion du codec audio et du Xilinx Zynq 7020.
Recherche de cœurs I2S
Le moment probablement le plus difficile lorsque je travaillais avec le flux audio dans le Xilinx Zynq 7020 était que sur la partie processeur de ce système, il n'y avait pratiquement pas de bus I2S sur la puce, j'ai donc dû trouver le cœur I2S. Cette tâche était compliquée par la condition que le noyau ip soit libre.
Nous nous sommes installés sur plusieurs cœurs ip. Trouvé pour le noyau en métal nu I2S
Digilent . Nous avons trouvé plusieurs cœurs ip sur les
opencores et, probablement, la meilleure option pour nous est le noyau ip
Analog Devices . Ils produisent des coeurs ip pour leur équipement, pour l'interaction FPGA / FPGA.
Nous sommes intéressés par l'ip-core appelé
AXI-I2S-ADI. Analog Devices lui-même fait la promotion de ces cœurs ip pour ses plates-formes matérielles.
Liste totale des cas d'utilisation:
- Métal nu - noyau IP pour I2S (audio Digilent ZYBO)
- opencores.org
- ContrĂ´leur AXI-I2S-ADI (Analog Devices)
AXI-I2S-ADI IP Core
Le noyau ip lui-même ressemble à ceci: il a les lignes bclk, wclk, din, dout. Il se connecte au DMA Xilinx Zynq 7000, dans notre exemple, la partie DMA PS est utilisée. Tous les échanges de données ont lieu via DMA. Le DMA peut être une unité autonome ou faire partie intégrante du PS SoC.
Lors de la configuration de ce noyau ip, il est important de ne pas oublier de soumettre la fréquence maître mclk à tlv320aic34 lui-même, en option lors de l'utilisation du kit de débogage pour tlv320aic34 - soumettre une fréquence maître externe.
Bloc fonctionnel avec axi-i2s-adi connectéAprès la procédure de configuration, la tâche consistait à lancer la fonctionnalité dans le système d'exploitation Linux.
Configuration d'i2c (tlv320aic34 est configuré sur cette interface):
i2c0: i2c@e0004000 { ... tlv320aic3x: tlv320aic3x@18 { #sound-dai-cells = <0>; compatible = "ti,tlv320aic3x"; reg = <0x18>; gpio-reset = <&axi_gpio_0 0 0>; ai3x-gpio-func = <&axi_gpio_0 1 0>, /* AIC3X_GPIO1_FUNC_DISABLED */ <&axi_gpio_0 2 0>; /* AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT */ AVDD-supply = <&vmmc2>; DRVDD-supply = <&vmmc2>; IOVDD-supply = <&vmmc2>; DVDD-supply = <&vmmc2>; ai3x-micbias-vg = <1>; }; ... };
Configuration d'i2s (les données audio sont transmises via cette interface):
i2s_clk: i2s_clk { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <11289600>; clock-output-names = "i2s_clk"; }; axi_i2s_adi_0: axi_i2s_adi@43C00000 { compatible = "adi,axi-i2s-1.00.a"; reg = <0x43C00000 0x1000>; xlnx,bclk-pol = <0x0>; xlnx,dma-type = <0x1>; xlnx,has-rx = <0x1>; xlnx,has-tx = <0x1>; xlnx,lrclk-pol = <0x0>; xlnx,num-ch = <0x1>; xlnx,s-axi-min-size = <0x000001FF>; xlnx,slot-width = <0x18>; }; &axi_i2s_adi_0 { #sound-dai-cells = <0>; compatible = "adi,axi-i2s-1.00.a"; clocks = <&clkc 15>, <&i2s_clk>; clock-names = "axi", "ref"; dmas = <&dmac_s 0 &dmac_s 1>; dma-names = "tx", "rx"; };
Configuration de la carte son dans l'arborescence des appareils (cartes audio):
sound { compatible = "simple-audio-card"; simple-audio-card,name = "TLV320AIC34"; simple-audio-card,format = "i2s"; simple-audio-card,bitclock-master = <&dailink0_master>; simple-audio-card,frame-master = <&dailink0_master>; simple-audio-card,widgets = ... simple-audio-card,routing = ... dailink0_master: simple-audio-card,cpu { clocks = <&i2s_clk>; sound-dai = <&axi_i2s_adi_0>; }; simple-audio-card,codec { clocks = <&i2s_clk>; sound-dai = <&tlv320aic3x>; }; }; };
Après toutes les manipulations pour configurer et configurer le codec dans l'arborescence des périphériques sous Linux, la carte audio convoitée est apparue et nous avons pu entendre de la musique (notre premier morceau de musique était Highway to Hell, AC / DC).
Voici ce que nous devions faire pour cela:
- Généré la fréquence nécessaire à l'aide de clk_wiz (assistant de pointage)
- DTS correctement configuré pour tlv320aic34
- Ajout de la prise en charge du pilote tlv320aic3x
- Ajout de packages audio Ă buildroot pour lire le flux audio (aplay, madplay, etc.)
Dans le processus de développement du dispositif final, nous avons été confrontés à la tâche de connecter 4 microcircuits tlv320aic34. La puce tlv320aic34 décrite ci-dessus contient 2 blocs pour travailler avec le flux audio, chaque bloc a sa propre ligne i2c pour configurer et configurer les paramètres audio. Un bloc ne peut avoir que quatre adresses, respectivement, il est impossible de connecter quatre microcircuits tlv320aic34 à une interface i2c, vous devez utiliser deux interfaces i2c (8 blocs audio indépendants). Pour chaque bloc, si vous démarrez mclk, blck, wclk, din / dout individuellement, vous devez ajouter 40 lignes de signal au total, ce qui est impossible et irrationnel du point de vue du circuit pour le module som que nous avons choisi, car en plus de ces signaux, vous avez dû connecter de nombreuses autres lignes et interfaces.
En conséquence, nous avons décidé de passer la carte audio en
mode TDM , dans lequel toutes les lignes mclk, bclk, din, dout sont combinées, ce qui réduit le nombre total de lignes de communication. Cette décision a affecté le fonctionnement de axi-i2s-adi, car le noyau ip lui-même fonctionnait en mode maître. De plus, ce changement ne nous a pas permis d'utiliser notre ip-core en mode TDM, et une décision résolue nous a obligé à abandonner l'utilisation de l'ip-core sélectionné. J'ai dû écrire un noyau ip pour écouter le trafic i2s et l'envoyer à dma, cette solution nous a permis de créer une interface commune pour recevoir des données qui ne dépendrait pas du type de carte pour l'enregistrement des appels (cartes analogiques et numériques).
L'architecture initiale pour recevoir le flux audio et son traitement via l'interface i2s:

L'architecture finale pour recevoir le flux audio et son traitement via l'interface i2s:

Architecture de réception d'un flux PRI et de son traitement:

Architecture de réception et de traitement des flux BRI:

Axi dma
Il s'agit d'un élément important du système de synchronisation des données pour dma.
Fenêtre de configuration AXI DMA dans Xilinx VivadoSur l'écran d'impression, le bloc AXI DMA lui-même est présenté. Il a de nombreux paramètres. Vous pouvez configurer le bus combien de données à transférer. Les données peuvent être alignées ou dans n'importe quel format. Une description détaillée du fonctionnement et de l'interaction avec axi dma est décrite
dans la documentation technique (de version en version, il y a un ajout et une correction des inexactitudes dans la description, ainsi qu'un raffinement des noyaux ip).
Vérifier le transfert de données via AXI DMA, les options de test AXI DMA
Lors du développement du pilote, nous avons décidé de trouver l'open source et de l'adapter à notre tâche. En conséquence, nous avons choisi les sources du
projet github ezdma (jeu de mots, lu comme dma facile).
La prochaine étape est le développement d'un pilote de test, c'était une étape préparatoire en prévision du moment où un noyau ip avec des fonctionnalités prêtes à l'emploi du département de développement FPGA nous est parvenu (le processus de développement décrit a été formé par des programmeurs intégrés). Avant ce moment, nous avons décidé de prendre AXI DMA, AXI DATA FIFO et de faire un bouclage pour éviter les erreurs futures. Nous avons bouclé l'envoi et la réception des données, nous avons donc vérifié le résultat de notre travail et les performances de notre chauffeur. Nous avons un peu adapté la fonctionnalité, l'avons adaptée à nos souhaits sur l'interface d'interaction et vérifié une fois de plus l'opérabilité du pilote et le principe d'interaction sélectionné.
Conception de blocs rétrospectifs, la première façon de tester AXI DMAUn exemple de description de DMA et ezdma dans une arborescence de périphériques:
/ { amba_pl: amba_pl { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; ranges ; axi_dma_1: axi_dma { #dma-cells = <1>; compatible = "xlnx,axi-dma-1.00.a"; reg = <0x40400000 0x10000>; clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk"; clocks = <&clkc 15>, <&clkc 15>, <&clkc 15>, <&clkc 15>; interrupt-parent = <&intc>; interrupts = <0 29 4 0 30 4>; xlnx,addrwidth = <0x20>; xlnx,include-sg; dma-channel@40400000 { compatible = "xlnx,axi-dma-mm2s-channel"; dma-channels = <0x1>; interrupts = <0 29 4>; xlnx,datawidth = <0x20>; xlnx,device-id = <0x0>; xlnx,include-dre ; }; dma-channel@40400030 { compatible = "xlnx,axi-dma-s2mm-channel"; dma-channels = <0x1>; interrupts = <0 30 4>; xlnx,datawidth = <0x20>; xlnx,device-id = <0x0>; xlnx,include-dre ; }; }; ezdma0 { compatible = "ezdma"; dmas = <&axi_dma_1 0 &axi_dma_1 1>; dma-names = "loop_tx", "loop_rx"; // used when obtaining reference to above DMA core using dma_request_slave_channel() ezdma,dirs = <2 1>; // direction of DMA channel: 1 = RX (dev->cpu), 2 = TX (cpu->dev) }; ... }; };
Vous pouvez facilement générer des fichiers dts / dtsi à l'aide de l'
outil Générateur d'arborescence de périphériques .
La deuxième étape de notre processus de développement est la création d'un noyau ip de test pour vérifier les performances du pilote, mais cette fois, les données seront significatives, avec le transfert via AXIS vers AXI_DMA (comme ce sera le cas dans la version finale du noyau ip).
Flux de travail de l'interface AXISNous implémentons deux variantes d'ip-kernels pour la génération de données, la première version testée est implémentée via verilog, la seconde - sur HLS (dans ce contexte, HLS est apparu sous le slogan "stylé-mode-jeunesse").
Le générateur de données verilog (et généralement dans les langages de la famille hdl - verilog, vhdl, etc.) est une solution standard lors du développement de cœurs ip de ce type. Voici quelques extraits de code pour le noyau IP intermédiaire:
module GenCnt ( …. assign HandsHake = m_axis_din_tready & m_axis_dout_tvalid; always @(posedge Clk) begin if (Rst) begin smCnt <= sIDLE; end else begin case (smCnt) sIDLE: begin smCnt <= sDATA; end sDATA: begin if (Cnt == cTopCnt - 1) begin smCnt <= sLAST; end end ... endmodule
Il n'est pas nécessaire d'avoir une description plus détaillée, car il s'agit d'une tâche typique d'un concepteur FPGA.
Une «bête» plus intéressante ici est HLS.
Vivado HLS (High Level Synthesis) est le nouveau logiciel de CAO Xilinx pour créer des appareils numériques en utilisant des langages de haut niveau tels que OpenCL, C ou C ++.
C / C ++ sont les principaux langages pour un ingénieur logiciel embarqué, donc résoudre un problème en utilisant ces langages est plus intéressant en termes d'implémentation et d'analyse comparative pour de futurs projets.
Voici deux petits exemples de travail avec HLS. Le premier exemple est un générateur de données pour AXI_DMA, le deuxième exemple est l'échange de données entre la partie processeur et la logique programmable via l'interface s_axilite.
L'échange de données via l'interface s_axilite (le deuxième exemple) a été implémenté de sorte qu'à tout moment dans procfs, il était possible de soustraire le flux binaire chargé, et qu'il était possible de suivre l'exactitude du travail en versionnant pour la partie PL de SoC. Ici, un point très intéressant apparaît avec s_axilite: Vivado HLS génère un pilote pour Linux (le pilote, à son tour, nous nous sommes adaptés pour travailler à travers procfs pour préserver l'hérédité de l'écriture). Un exemple du code généré pour Linux est ci-dessous (le chemin vers la solution source1 / impl / ip / drivers / name_xxx / src /).
Étapes de la synthèse HLS et de la génération de code RTLGénérateur de données HLS pour vérifier le fonctionnement avec AXI_DMA:
#include <ap_axi_sdata.h> #include <hls_stream.h> #define SIZE_STREAM 1024 struct axis { int tdata; bool tlast; }; void data_generation(axis outStream[SIZE_STREAM]) { #pragma HLS INTERFACE axis port=outStream int i = 0; do{ outStream[i].tdata = i; outStream[i].tlast = (i == (SIZE_STREAM - 1)) ? 1 : 0; i++; }while( i < SIZE_STREAM); }
Un exemple d'obtention de version et de type de carte d'interface:
#include <stdio.h> void info( int &aVersion, int &bSubVersion, int &cTypeBoard, int version, int subVersion, int typeBoard ){ #pragma HLS INTERFACE s_axilite port=aVersion #pragma HLS INTERFACE s_axilite port=bSubVersion #pragma HLS INTERFACE s_axilite port=cTypeBoard #pragma HLS INTERFACE ap_ctrl_none port=return aVersion = version; bSubVersion = subVersion; cTypeBoard = typeBoard; }
Comme vous l'avez remarqué, pour le développement sur hls, il est très important de comprendre le travail et l'application de divers pragmas (HLS pragma), car le processus de synthèse est directement lié aux pragmas.
Pilote généré pour s_axilite:
Un fichier important qui vous indique l'emplacement des variables (registres) dans l'espace d'adressage est le fichier x # votre_nom # _hw.h. Vous pouvez toujours vérifier l'exactitude du noyau ip écrit à l'aide de l'outil devmem.
Le contenu de ce fichier:
Ce fichier décrit les adresses des registres, les registres correspondent à l'emplacement des arguments dans la fonction. Après la synthèse du projet, vous pouvez voir comment le projet créé sera exécuté en cycles.
Exemple de battement de projetTravailler avec hls a montré que cet outil est adapté pour résoudre rapidement des tâches, en particulier il a fait ses preuves pour résoudre des problèmes mathématiques de vision par ordinateur, qui peuvent être facilement décrits en C ++ ou C, ainsi que pour créer de petits noyaux ip pour les interactions et les échanges informations avec des interfaces FPGA standard.
Dans le même temps, HLS n'est pas adapté à la mise en œuvre d'interfaces matérielles spécifiques, par exemple, dans notre cas, il s'agissait d'I2S, et le code rtl généré prend plus d'espace sur FPGA que celui écrit dans les langages hdl standard.
La dernière étape des tests de pilotes est le développement d'un générateur de trafic I2S. Ce noyau ip répète les fonctionnalités des noyaux ip précédents, sauf qu'il génère des données incrémentielles (trafic) qui correspondent aux données I2S réelles en mode TDM.
Conception de blocs pour les futurs tests de cœur I2S personnalisés et générateur de trafic I2SEn conséquence, nous avons obtenu les résultats de hls, axi dma et s_axilite, vérifié les performances de nos logiciels et pilotes.
Conclusions
Nous avons réussi à développer les types de cartes d'interface nécessaires, ainsi que les noyaux ip pour tdm, pri, bri. Nous avons considérablement amélioré l'approche actuelle du développement de tels appareils et créé une solution complète qui peut rivaliser avec des cartes d'interface similaires d'
Asterick ,
patton et autres. L'avantage de notre solution est que le développeur n'a pas besoin d'une liaison intermédiaire entre le PC et le PCI pour le transfert de données, il pourra transmettre directement les informations reçues via Ethernet.