1)    Présentation

 

Afin de disposer d’une plateforme répondant aux spécifications du projet (8 canaux audios à numériser) on peut en complément de la solution ARDUINO implémenter la réception sur la carte ZYBO.

L’avantage est de pouvoir disposer d’un nombre d’échantillons par seconde important. L’inconvénient est de rajouter un multiplexeur 8 voies analogiques avec une dynamique comprise entre 0v et 1V, de traiter les échantillons sur réseau IP

La carte ZYBO dispo d’un système on chip (SOC) ZYNQ Z7010 de la société Xilinx. Le SOC Zynq est une famille de FPGA qui contient en plus de la partie logique programmable (Programmable Logic PL) un système microprocesseur ARM double cœur complet avec ses contrôleurs mémoires et ses périphériques (Processing System PS). On dit que son architecture est centrée sur le PS car le processeur démarre en premier, puis charge le fichier de configuration de la PL (boot.bin). Un convertisseur analogique numérique 17 voies (XADC) peut être implémenté dans la partie logique programmable

 

 

 

 

 

 

 

 

 

 

 

2) XADC: Dual 12-Bit 1-MSPS ADCs

Le bloc XADC permet soit de surveiller les alimentations et la température du FPGA via des capteurs sur la puce, soit d’acquérir jusqu’à 17 signaux analogiques externes via un multiplexeur. Il comporte deux convertisseurs analogique/numérique (ADC) 1 Msps 12 bits.

On peut l’utiliser directement en VHDL ou avec le processeur ARM via le bus AXI.

 

 

La carte Zybo ne disposant que de 4 entrées analogiques sur ses connecteurs, on peut utiliser le module XADC en mode multiplexeur externe.

 

3) Le diagramme de déploiement

La société Digilent fournit une distribution LINUX que l’on peut implémenter sur les cartes ZYNQ. Le noyau LINUX fourni par XILINX a été patché par la société Digilent afin de prendre en compte les éléments matériels de la carte ZYBO.

Un environnement de cross compilation type UBUNTU est nécessaire afin de compiler le chargeur de noyau U-BOOT le noyau LINUX, de définir le device-tree, les modules et d’implanter les modules et la distribution LINUX.

Le dialogue entre la carte ZYBO et le PC peut s’effectuer grâce au réseau IP (Internet Protocol) en mode TCP ou UDP mode Broadcast

 

Afin d’échantillonner de manière optimale deux solutions peuvent être envisagées :

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Solution 1 : gestion par interruption et transfert par bus AXI

La solution N°1 permet de déclencher une interruption pour un bloc de 8 canaux convertis et de transférer par le bus AXI les 8 échantillons vers le processing system PS.

L’architecture matérielle réalisée sous vivado est axée autour du PS et du module XADC

 

Le module XDAC génère une interruption après la conversion de 8 canaux analogiques. Cette interruption est gérée par le noyau LINUX. L’applicatif sous LINUX peut alors envoyer des blocs de données de 1024 octets sur le réseau IP.

 

EN bleu clair Ressource réquisitionnée dans le FPGA

 

 

 

 

 


Statistique en mode UDP (Broadcast) débit estimé de 1.520 Mbits/s soit pour un canal 190k bits/s 23750 octets /s 11875 samples/s

 

 

Solution N°2 : transfert par canal DMA (direct Memory access)

Le XDAC permet de streamer un paquet de 256 échantillons par le bus AXI STREAM. Le transfert de ce paquet se fait directement dans la DDR du Processing system grâce à un canal DMA. Cette solution accélère de manière significative l’échange de données entre la partie logique programmable et la partie Processing system. L’applicatif sous LINUX peut alors envoyer très rapidement des blocs de données de 256 échantillons sur le réseau IP.

 

EN bleu clair Ressource réquisitionnée dans le FPGA
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Statistique en mode UDP (Broadcast) débit estimé de 5 329 510 bits/s soit pour un canal 666 188 bit/s ou 83 273 octets /s soit 41 636 échantillons par seconde

 

 

 

Statistique en mode UDP (Broadcast) avec gestion par interruption DMA débit estimé de 7 372 800 bits/s soit pour un canal 921 600 bit/s ou 115 200 octets /soit 57600 échantillons par seconde

 

Solution N°3 : Calculé en temps réel de la FFT et transfert par canal DMA

 

Un bloc IP du type FFT est utilisé avec les canaux DMA. Le flux est régulé en entrée et en sortie du bloc FFT par une pile FIFO de 512 échantillons. La FFT est calculée sur 512 points. Les deux blocs IP AXIS_DMA et le XADC sont programmés par le bus AXI_LITE. Le bloc tlast_gen a été écrit en langage VERILOG. Ce bloc  récupère un signal AXI Stream Slave du XADC qui ne contient pas de signal TLAST. Il sort un signal AXI Stream Master qui contient le signal TLAST. Le signal TLAST est généré après N échantillons valides, où N est le PACKET_LENGTH spécifié à 512 .Le module convertisseur de données (axis_dwith_converter) permet de passer d’un échantillon de 2 octets à un échantillon de 4 octets Pour le Bloc FFT. Trois interruptions sont gérées une pour le canal DMA des échantillons temporelles du XADC, une pour le canal DMA de transfert de DDR3 vers FFT, l’autre pour le canal DMA du bloc FFT vers DDR3.Le bloc XLCONCAT permet de concaténer les trois interruptions sur trois bits IN[0]=LSB, IN[2]=MSB.

 

Fichier pdf schéma vivado

 

Le module sous LINUX permet d’initialiser les différents registres pour le XADC , les deux bloc pour les  canaux DMA AXIS_DMA_0 et AXIS_DMA_1 et la gestion des trois interruptions.

Les trois interruptions peuvent générer un signal vers l’applicatif du domaine utilisateur.

L’applicatif du domaine utilisateur récupère et formatte les échantillons audios et FFT et les diffusent sur le réseau sur une adresse Broadcast.

Une sinusoïde sur un seul canal les autres canaux à 0

 

Effet de l’échantillonnage

 

 

Schéma de câblage

 

 

 

 

 

Les commandes sous LINUX

 

Pour une conversion de 512 échantillons audios sans FFT Hardware

 

 

 

 

 

 

 

 

 

 

 

 

L’applicatif sous windows

 

 

 

Le module sous LINUX

 

 

#include <linux/module.h>   

#include <linux/kernel.h>    

#include <linux/init.h>         

#include <linux/interrupt.h>

#include <linux/irq.h>          

#include <asm/io.h>             

#include <linux/fs.h>                            // Para fops

#include <linux/signal.h>                      // Para señales kernel-userspace

#include <asm/siginfo.h>                     // siginfo

#include <linux/rcupdate.h>                // rcu_read_lock

#include <linux/sched.h>      // find_task_by_pid_type

#include <linux/debugfs.h>                 

#include <linux/uaccess.h>                  // Para 'copy_from_user' and 'copy_to_user'

MODULE_LICENSE("GPL");

 

#define SIG_TEST 44        // Definición de una señal propia (rango de 33 a 64 para real-time signals)

#define SIG_TEST1 43

#define SIG_TEST2 42

#define IRQ_NUM 91 // Interruption canaux DMA fin de transfert de FFT vers DDR3 

#define IRQ_NUM1 90 // Interruption canaux DMA fin de transfert de DDR3 vers FFT

#define IRQ_NUM2 89 // Interruption canaux DMA fin de transfert de XADC vers DDR3

// Línea de interrupción

int pid=0;

//pid_t pid = 0;

//#define IRQ_NUM          61

#define MLI_BASE            0x43C00000

#define swGPIO                  0x41210010

#define LED                         0x41200010

#define VP 0x43C0020C

#define GIER 0x43C0005C

#define CR0 0x43C00300

#define CR1 0x43C00304

#define CR2 0x43C00308

#define status 0x43C00004

#define SEQUENCE 0x43C00320

#define SEQUENCE1 0x43C00324

#define IPISR 0x43C00060

#define IPIER 0x43C00068

#define ADCMODE1 0x43C00330

#define ADCMODE2 0x43C00334

#define VAUXP0 0x43C00240

#define VAUXP1 0x43C00244

#define VAUXP2 0x43C00248

#define VAUXP3 0x43C0024C

#define VAUXP4 0x43C00250

#define VAUXP5 0x43C00254

#define VAUXP6 0x43C00258

#define VAUXP7 0x43C0025C

#define RESETXADC 0x43C00010

#define RESET 0x43C00000

#define S2MM_CONTROL_REGISTER 0x40400030  // canal DMA pour XADC entrant XADC vers DMA

#define S2MM_STATUS_REGISTER 0x40400034

#define S2MM_DESTINATION_ADDRESS 0x40400048

#define S2MM_LENGTH 0x40400058

#define MM2S_CONTROL_REGISTER1 0x40410000  // canal DMA pour FFT DMA vers FFT

#define MM2S_STATUS_REGISTER1 0x40410004

#define MM2S_DESTINATION_ADDRESS1 0x40410018

#define MM2S_LENGTH1 0x40410028

#define S2MM_CONTROL_REGISTER1 0x40410030 // canal DMA pour FFT FFT vers DMA

#define S2MM_STATUS_REGISTER1 0x40410034

#define S2MM_DESTINATION_ADDRESS1 0x40410048

#define S2MM_LENGTH1 0x40410058

 

//#define             vitdet_TCR0         0x43C00018

unsigned long *pdds_VP;      //

unsigned long *pdds_GIER;  //

unsigned long *pdds_CR0;    // pointe sur

unsigned long *pdds_CR1;    // pointe sur

unsigned long *pdds_CR2;    // pointe sur

unsigned long *pdds_status; // pointe sur

unsigned long *pdds_SEQUENCE;      // pointe sur

unsigned long *pdds_SEQUENCE1;     // pointe sur

unsigned long *pdds_IPISR; // pointe sur

unsigned long *pdds_IPIER; // pointe sur

unsigned long *pdds_VAUXP0;            // pointe sur

unsigned long *pdds_VAUXP1;             // pointe sur

unsigned long *pdds_VAUXP2;            // pointe sur

unsigned long *pdds_VAUXP3;            // pointe sur

unsigned long *pdds_VAUXP4;            // pointe sur

unsigned long *pdds_VAUXP5;            // pointe sur

unsigned long *pdds_VAUXP6;            // pointe sur

unsigned long *pdds_VAUXP7;            // pointe sur

unsigned long *pdds_gpioLED;             // pointe sur

unsigned long *pdds_ADCMODE1;

unsigned long *pdds_ADCMODE2;

unsigned long *pdds_RESETXADC;

unsigned long *pdds_RESET;

unsigned long *pdds_S2MM_CONTROL_REGISTER;       //

unsigned long *pdds_S2MM_STATUS_REGISTER;

unsigned long *pdds_S2MM_LENGTH;

unsigned long *pdds_S2MM_DESTINATION_ADDRESS;

unsigned long *pdds_S2MM_CONTROL_REGISTER1;     //

unsigned long *pdds_S2MM_STATUS_REGISTER1;

unsigned long *pdds_S2MM_LENGTH1;

unsigned long *pdds_S2MM_DESTINATION_ADDRESS1;

unsigned long *pdds_MM2S_CONTROL_REGISTER1;     //

unsigned long *pdds_MM2S_STATUS_REGISTER1;

unsigned long *pdds_MM2S_LENGTH1;

unsigned long *pdds_MM2S_DESTINATION_ADDRESS1;

 

//unsigned long *pvitdet_TCR0;         // Puntero al counter register del vitdet 0

 

#define DEVICE_NAME "XADCINT" // Nombre del dispositivo

#define SUCCESS 0            // Valor de retorno Success

 

struct task_struct *t=NULL;

struct dentry *file_debugfs;              // Archivo para comunicación kernel-userspace

struct dentry *file;

static int app_pid = 0;// PID de la aplicación en el userspace

unsigned long longueur=0;

unsigned long addresse=0;

// Función write (llamada cuando write() es usado en el espacio de usuario)

ssize_t syscall_write(struct file *flip, const char *buf, size_t length, loff_t *offset)

{

char myMLI_phrase[10];

      u32 myddsdet_value;

 

      if (length < 11) {

          if (copy_from_user(myMLI_phrase, buf, length))

              return -EFAULT;

 

         //myvitdet_phrase[count] = '\0';

     }

 

 

//printk("syscall_write.\n");

//printk("Value received: %u.\n", value);

/*printk(" ecriture %x, %x, %x, %x,%x,%x,%x\n",myMLI_phrase[0],myMLI_phrase[1],myMLI_phrase[2],myMLI_phrase[3],myMLI_phrase[4],myMLI_phrase[5],myMLI_phrase[6]);*/

     wmb();

pid=(myMLI_phrase[2]<<8)+myMLI_phrase[3];

longueur=(myMLI_phrase[4]<<8)+myMLI_phrase[5];

addresse=(myMLI_phrase[6]<<24)+(myMLI_phrase[7]<<16)+(myMLI_phrase[8]<<8)+myMLI_phrase[9];

//printk("adresse est %x \n",addresse);

//printk("longueur est %x \n",longueur);          

// programmation de la consigne de vitesse

               iowrite32(myMLI_phrase[0],  pdds_gpioLED);//

if (myMLI_phrase[1]==0x00)

                               iowrite32(0x00000000,  pdds_S2MM_CONTROL_REGISTER);//desactive l'inter  halt DMA

else if (myMLI_phrase[1]==0x01) iowrite32(0x00001001,  pdds_S2MM_CONTROL_REGISTER);//run DMA IOC inter validé

else if (myMLI_phrase[1]==0x02) iowrite32(0x00000004,  pdds_S2MM_CONTROL_REGISTER);//reset DMA

else if (myMLI_phrase[1]==0x03) iowrite32(0x00001000,  pdds_S2MM_STATUS_REGISTER);//clear IRQ IOC

else if (myMLI_phrase[1]==0x04) iowrite32(addresse,  pdds_S2MM_DESTINATION_ADDRESS);//send address

else if (myMLI_phrase[1]==0x05) iowrite32(longueur,  pdds_S2MM_LENGTH);//send length

else if (myMLI_phrase[1]==0x06)

                               iowrite32(0x00000000,  pdds_S2MM_CONTROL_REGISTER1);//desactive l'inter  halt DMA FFT FFT vers DMA

else if (myMLI_phrase[1]==0x07) iowrite32(0x00001001,  pdds_S2MM_CONTROL_REGISTER1);//run DMA IOC inter validé FFT

else if (myMLI_phrase[1]==0x08) iowrite32(0x00000004,  pdds_S2MM_CONTROL_REGISTER1);//reset DMA  FFT

else if (myMLI_phrase[1]==0x09) iowrite32(0x00001000,  pdds_S2MM_STATUS_REGISTER1);//clear IRQ IOC FFT

else if (myMLI_phrase[1]==0x0A) iowrite32(addresse,  pdds_S2MM_DESTINATION_ADDRESS1);//send address FFT

else if (myMLI_phrase[1]==0x0B) iowrite32(longueur,  pdds_S2MM_LENGTH1);//send length FFT

else if (myMLI_phrase[1]==0x0C)

                               iowrite32(0x00000000,  pdds_MM2S_CONTROL_REGISTER1);//desactive l'inter  halt DMA FFT DMA vers FFT

else if (myMLI_phrase[1]==0x0D) iowrite32(0x00001001,  pdds_MM2S_CONTROL_REGISTER1);//run DMA IOC inter validé FFT

else if (myMLI_phrase[1]==0x0E) iowrite32(0x00000004,  pdds_MM2S_CONTROL_REGISTER1);//reset DMA  FFT

else if (myMLI_phrase[1]==0x0F) iowrite32(0x00001000,  pdds_MM2S_STATUS_REGISTER1);//clear IRQ IOC FFT

else if (myMLI_phrase[1]==0x10) iowrite32(addresse,  pdds_MM2S_DESTINATION_ADDRESS1);//send address FFT

else if (myMLI_phrase[1]==0x11) iowrite32(longueur,  pdds_MM2S_LENGTH1);//send length FFT

 

                //iowrite32((myvitdet_phrase[4]<<24)+(myvitdet_phrase[5]<<16)+(myvitdet_phrase[6]<<8)+(myvitdet_phrase[7]), pvitdet_TCR0);

               

     return length;

 }

 

 

static irqreturn_t irq_handler(int irq,void* dev_id)

{

int ret;

struct siginfo info;

unsigned long temp;

unsigned long timervalue;

///******* signal vers l'espace utilisateur *******

iowrite32(0x00000000, pdds_S2MM_CONTROL_REGISTER);// DMA STOP INTER desactive XADC vers DMA

memset(&info, 0, sizeof(struct siginfo));

memset(&t, 0, sizeof(struct task_struct));

info.si_signo = SIG_TEST;

info.si_code = SI_QUEUE;

info.si_int = 125; //real-time

rcu_read_lock();

//t = find_task_by_pid_type(PIDTYPE_PID, pid);  //find the task_struct associated with this pid

//t = pid_task(find_pid_ns(app_pid, &init_pid_ns), PIDTYPE_PID);

t = pid_task(find_vpid(pid), PIDTYPE_PID);

if(t == NULL){

printk("ancun numero de PID.\n");

rcu_read_unlock();

return IRQ_HANDLED;

}

rcu_read_unlock();

ret = send_sig_info(SIG_TEST, &info, t); // envoit le signal vers le domaine utilisateur 44

if (ret < 0) {

printk("erreur emission du signal.\n");

return IRQ_HANDLED;

}

 //printk("interruption kernel.\n");

return IRQ_HANDLED;

}

 

 

static irqreturn_t irq_handler1(int irq,void* dev_id)

{

int ret;

struct siginfo info;

unsigned long temp;

unsigned long timervalue;

///******* signal vers l'espace utilisateur *******

iowrite32(0x00000000, pdds_MM2S_CONTROL_REGISTER1);// DMA STOP INTER desactive FFT DMA vers FFT

memset(&info, 0, sizeof(struct siginfo));

memset(&t, 0, sizeof(struct task_struct));

info.si_signo = SIG_TEST;

info.si_code = SI_QUEUE;

info.si_int = 125; // Las señales real-time pueden llevar hasta 32 bits de datos

rcu_read_lock();

//t = find_task_by_pid_type(PIDTYPE_PID, pid);  //find the task_struct associated with this pid

//t = pid_task(find_pid_ns(app_pid, &init_pid_ns), PIDTYPE_PID);

t = pid_task(find_vpid(pid), PIDTYPE_PID);

if(t == NULL){

printk("ancun numero de PID.\n");

rcu_read_unlock();

return IRQ_HANDLED;

}

rcu_read_unlock();

ret = send_sig_info(SIG_TEST1, &info, t); // envoit le signal vers le domaine utilisateur  43

if (ret < 0) {

printk("erreur emission du signal.\n");

return IRQ_HANDLED;

}

 //printk("interruption kernel.\n");

return IRQ_HANDLED;

}

 

 

static irqreturn_t irq_handler2(int irq,void* dev_id)

{

int ret;

struct siginfo info;

unsigned long temp;

unsigned long timervalue;

///******* signal vers l'espace utilisateur *******

iowrite32(0x00000000, pdds_S2MM_CONTROL_REGISTER1);// DMA STOP INTER desactive FFT FFT vers DMA

memset(&info, 0, sizeof(struct siginfo));

memset(&t, 0, sizeof(struct task_struct));

info.si_signo = SIG_TEST;

info.si_code = SI_QUEUE;

info.si_int = 125; //  real-time

rcu_read_lock();

//t = find_task_by_pid_type(PIDTYPE_PID, pid);  //find the task_struct associated with this pid

//t = pid_task(find_pid_ns(app_pid, &init_pid_ns), PIDTYPE_PID);

t = pid_task(find_vpid(pid), PIDTYPE_PID);

if(t == NULL){

printk("ancun numero de PID.\n");

rcu_read_unlock();

return IRQ_HANDLED;

}

rcu_read_unlock();

ret = send_sig_info(SIG_TEST2, &info, t); // envoit le signal vers le domaine utilisateur 42

if (ret < 0) {

printk("erreur emission du signal.\n");

return IRQ_HANDLED;

}

 //printk("interruption kernel.\n");

return IRQ_HANDLED;

}

 

 

 

 

// Función read

ssize_t syscall_read(struct file *flip, char *buf, size_t length, loff_t *offset)

{

unsigned int value;

printk("syscall_read.\n");

u32 myddsdet_value;

char tab[10];

     myddsdet_value =(u32) ioread32(pdds_VAUXP0);

     printk("la valeur du premier registre  est 0x%08lx\n",myddsdet_value);

                myddsdet_value =(u32) ioread32(pdds_VAUXP1);

printk("la valeur du deuxieme registre est 0x%08lx \n",myddsdet_value);

myddsdet_value =(u32) ioread32(pdds_VAUXP2);

printk("la valeur du troisieme registre est 0x%08lx \n",myddsdet_value);

myddsdet_value =(u32) ioread32(pdds_VAUXP3);

printk("la valeur du quatrieme registre est 0x%08lx \n",myddsdet_value);

myddsdet_value =(u32) ioread32(pdds_VAUXP4);

printk("la valeur du cinquieme registre est 0x%08lx \n",myddsdet_value);

tab[0]=(u8) ioread32(pdds_VAUXP0);

tab[1]=(u8) ioread32(pdds_VAUXP1);

tab[2]=(u8) ioread32(pdds_VAUXP2);

tab[3]=(u8) ioread32(pdds_VAUXP3);

tab[4]=(u8) ioread32(pdds_VAUXP4);

tab[5]=(u8) (ioread32(pdds_VAUXP5));

tab[6]=(u8) (ioread32(pdds_VAUXP6));

tab[7]=(u8) (ioread32(pdds_VAUXP7));

tab[8]=(u8) (ioread32(pdds_status));

tab[9]=(u8) (ioread32(pdds_S2MM_STATUS_REGISTER));

 

 

 

//myvitdet_value =(u32) ioread32(pvitdet_TCR0);

//printk("la valeur est 0x%08lx \n",myddsdet_value);

if (copy_to_user(buf, tab, length) != 0) return -EFAULT; else return 0;

}

 

// Archivo de operaciones

struct file_operations syscall_fops = {

.owner = THIS_MODULE,

.read = syscall_read,            // read()

.write = syscall_write,          // write()

};

 

 

// Módulo init

static int __init mod_init(void)

{

printk(KERN_ERR "Init syscall module V1.1 \n");

 

 

// Se registran las interrupciones del vitdet

 

 

pdds_VP = ioremap_nocache(VP,0x4); // first register

pdds_GIER = ioremap_nocache(GIER,0x4);  //

pdds_CR0 = ioremap_nocache(CR0,0x4);  //

pdds_CR1 = ioremap_nocache(CR1,0x4);//

pdds_CR2 = ioremap_nocache(CR2,0x4);//

pdds_status= ioremap_nocache(status,0x4);

pdds_SEQUENCE=ioremap_nocache(SEQUENCE,0x4);

pdds_SEQUENCE1 = ioremap_nocache(SEQUENCE1,0x4);//

pdds_IPISR= ioremap_nocache(IPISR,0x4);

pdds_IPIER=ioremap_nocache(IPIER,0x4);

pdds_VAUXP0=ioremap_nocache(VAUXP0,0x4);

pdds_VAUXP1=ioremap_nocache(VAUXP1,0x4);

pdds_VAUXP2=ioremap_nocache(VAUXP2,0x4);

pdds_VAUXP3=ioremap_nocache(VAUXP3,0x4);

pdds_VAUXP4=ioremap_nocache(VAUXP4,0x4);

pdds_VAUXP5=ioremap_nocache(VAUXP5,0x4);

pdds_VAUXP6=ioremap_nocache(VAUXP6,0x4);

pdds_VAUXP7=ioremap_nocache(VAUXP7,0x4);

pdds_gpioLED=ioremap_nocache(LED,0x4);

pdds_ADCMODE1=ioremap_nocache(ADCMODE1,0x4);

pdds_ADCMODE2=ioremap_nocache(ADCMODE2,0x4);

pdds_RESETXADC=ioremap_nocache(RESETXADC,0x4);

pdds_RESET=ioremap_nocache(RESET,0x4);

pdds_S2MM_CONTROL_REGISTER=ioremap_nocache(S2MM_CONTROL_REGISTER,0x4);   //

pdds_S2MM_STATUS_REGISTER=ioremap_nocache(S2MM_STATUS_REGISTER,0x4);

pdds_S2MM_LENGTH=ioremap_nocache(S2MM_LENGTH,0x4);

pdds_S2MM_DESTINATION_ADDRESS=ioremap_nocache(S2MM_DESTINATION_ADDRESS,0x4);

pdds_S2MM_CONTROL_REGISTER1=ioremap_nocache(S2MM_CONTROL_REGISTER1,0x4); //

pdds_S2MM_STATUS_REGISTER1=ioremap_nocache(S2MM_STATUS_REGISTER1,0x4);

pdds_S2MM_LENGTH1=ioremap_nocache(S2MM_LENGTH1,0x4);

pdds_S2MM_DESTINATION_ADDRESS1=ioremap_nocache(S2MM_DESTINATION_ADDRESS1,0x4);

pdds_MM2S_CONTROL_REGISTER1=ioremap_nocache(MM2S_CONTROL_REGISTER1,0x4); //

pdds_MM2S_STATUS_REGISTER1=ioremap_nocache(MM2S_STATUS_REGISTER1,0x4);

pdds_MM2S_LENGTH1=ioremap_nocache(MM2S_LENGTH1,0x4);

pdds_MM2S_DESTINATION_ADDRESS1=ioremap_nocache(MM2S_DESTINATION_ADDRESS1,0x4);

//pvitdet_TCR0 = ioremap_nocache(vitdet_TCR0,0x4);  // Mapeo del count register del vitdet 0

iowrite32(0x00000001, pdds_RESETXADC);   ////mode Mux channel chanel 14 no average

iowrite32(0x00000000, pdds_RESETXADC);   // // mode continu alarm off

iowrite32(0x0000081E, pdds_CR0);   ////mode Mux channel chanel 14 no average

iowrite32(0x00002F0F, pdds_CR1);   // // mode continu alarm off

iowrite32(0x00000400, pdds_CR2);  // //ADCCLK = DCLK/4 100MHZ%4 =25MHZ power ON

iowrite32(0x00000000, pdds_SEQUENCE);  //

iowrite32(0x000000FF, pdds_SEQUENCE1);   // consigne sorties

iowrite32(0x00000000, pdds_GIER); // desactive inter

iowrite32(0x00000020, pdds_IPISR);              // valide E0S

iowrite32(0x00000020, pdds_IPIER);

iowrite32(0x00000000, pdds_ADCMODE1);    

iowrite32(0x00000000, pdds_ADCMODE2);

iowrite32(0x00000004, pdds_S2MM_CONTROL_REGISTER);// reset DMA XADC

iowrite32(0x00000000, pdds_S2MM_CONTROL_REGISTER);// DMA XADC STOP INTER desactive

iowrite32(0x00000004, pdds_S2MM_CONTROL_REGISTER1);// reset DMA FFT

iowrite32(0x00000000, pdds_S2MM_CONTROL_REGISTER1);// DMA FFT STOP INTER desactive

iowrite32(0x00000004, pdds_MM2S_CONTROL_REGISTER1);// reset DMA FFT

iowrite32(0x00000000, pdds_MM2S_CONTROL_REGISTER1);// DMA FFT STOP INTER desactive

//iowrite32(0x000000D0, pdds_reg0);            // Generate mode, downcounter, reload generate

 

// value, no load, enable IRQ, enable vitdet

printk("la valeur pdds_CR0 est 0x%08lx \n",*pdds_CR0);

printk("la valeur pdds_CR1 est 0x%08lx \n",*pdds_CR1);

printk("la valeur pdds_CR2 est 0x%08lx \n",*pdds_CR2);

printk("la valeur pdds_SEQUENCE1 est 0x%08lx \n",*pdds_SEQUENCE);

printk("la valeur pdds_SEQUENCE1 est 0x%08lx \n",*pdds_SEQUENCE1);

printk("la valeur pdds_GIER est 0x%08lx \n",*pdds_GIER);

printk("la valeur pdds_IPISR est 0x%08lx \n",*pdds_IPISR);

printk("la valeur pdds_IPIER est 0x%08lx \n",*pdds_IPIER);

printk("la valeur pdds_ADCMODE1 est 0x%08lx \n",*pdds_ADCMODE1);

//printk("la valeur des switches est 0x%08lx \n",*pdds_gpiosw);

printk("la valeur des LEDs est 0x%08lx \n",*pdds_gpioLED);

printk("la valeur status register DMA est 0x%08lx \n",*pdds_S2MM_STATUS_REGISTER);

// Se utiliza un archivo de configuración de lectura y escritura para el paso de información

file_debugfs = debugfs_create_file("XADCINT", 0644, NULL, NULL, &syscall_fops);

if (file_debugfs ==0) printk(KERN_ERR "erreur creation XADC. \n");

if (request_irq(IRQ_NUM,irq_handler,IRQF_DISABLED, DEVICE_NAME, NULL ))

{

printk(KERN_ERR "Not Registered IRQ. \n");

return -EBUSY;

}

printk(KERN_ERR "Registered IRQ1. \n");

if (request_irq(IRQ_NUM1,irq_handler1,IRQF_DISABLED, DEVICE_NAME, NULL ))

{

printk(KERN_ERR "Not Registered IRQ1. \n");

return -EBUSY;

}

printk(KERN_ERR "Registered IRQ1. \n");

if (request_irq(IRQ_NUM2,irq_handler2,IRQF_DISABLED, DEVICE_NAME, NULL ))

{

printk(KERN_ERR "Not Registered IRQ2. \n");

return -EBUSY;

}

printk(KERN_ERR "Registered IRQ2. \n");

 

 

t=NULL;

 

return SUCCESS;

}

 

 

 

// exit module

static void __exit mod_exit(void)

{

debugfs_remove(file_debugfs);

debugfs_remove(file);

iounmap(pdds_VP); // Se "des-mapean" los registros del vitdet 0

iounmap(pdds_GIER);

iounmap(pdds_CR0);

iounmap(pdds_CR1);

iounmap(pdds_status);

iounmap(pdds_SEQUENCE);

iounmap(pdds_SEQUENCE1);              // Se "des-mapean" los registros del vitdet 0

iounmap(pdds_IPISR);

iounmap(pdds_IPIER);

iounmap(pdds_VAUXP0);

iounmap(pdds_VAUXP1);

iounmap(pdds_VAUXP2);

iounmap(pdds_VAUXP3);

iounmap(pdds_VAUXP4);

iounmap(pdds_VAUXP5);

iounmap(pdds_VAUXP6);

iounmap(pdds_VAUXP7);

iounmap(pdds_gpioLED);

iounmap(pdds_S2MM_CONTROL_REGISTER);

iounmap(pdds_S2MM_STATUS_REGISTER);

iounmap(pdds_S2MM_DESTINATION_ADDRESS);

iounmap(pdds_S2MM_LENGTH);

iounmap(pdds_S2MM_CONTROL_REGISTER1);

iounmap(pdds_S2MM_LENGTH1);

iounmap(pdds_S2MM_DESTINATION_ADDRESS1);

iounmap(pdds_S2MM_STATUS_REGISTER1);

iounmap(pdds_MM2S_CONTROL_REGISTER1);

iounmap(pdds_MM2S_STATUS_REGISTER1);

iounmap(pdds_MM2S_LENGTH1);

iounmap(pdds_MM2S_DESTINATION_ADDRESS1);

 

 

 

 

 

//iounmap(pvitdet_TCR0);

free_irq(IRQ_NUM, NULL);               // Se desregistran las interrupciones

free_irq(IRQ_NUM1, NULL);             // Se desregistran las interrupciones

free_irq(IRQ_NUM2, NULL);             // Interruption canaux DMA de XADC vers DDR3

printk(KERN_ERR "Exit syscall Module. \n");

}

 

module_init(mod_init);

module_exit(mod_exit);

MODULE_AUTHOR ("phil");

MODULE_DESCRIPTION("Testdriver for the Xilinx XADC.");

MODULE_LICENSE("GPL v2");

MODULE_ALIAS("custom:syscall");

 

 

 

 

 

 

 

 

 

 

 

 

Notions abordées

 

Les Threads

Les signaux

Les sockets

Les interruptions sous LINUX

Les modules sous LINUX

Bloc IP XADC

Bloc IP AXI-DMA

 

Outils

 

Vivado 2015.4

Ubuntu avec outil de cross compilation pour le noyau LINUX ZYNQ 3.18