Localisation sonore par GCC

From Eric

(Difference between revisions)
Jump to: navigation, search
m (Created page with " = Le code C de test de la GCC =")
m
Line 1: Line 1:
-
 
= Le code C de test de la GCC =
= Le code C de test de la GCC =
 +
 +
Le code de la version (préliminaire est donné ci-après) :
 +
 +
// (Eric)
 +
 +
// La fréquence d'horloge est fosc= 7.42MHz x 16 (PLL) =118.72MHz
 +
// Le temps de cycle est fcy = fosc/4, soit :
 +
#define FCY 29680000UL
 +
 +
#include <xc.h>
 +
#include <libpic30.h>
 +
#include <dsp.h>
 +
#include <stdio.h>
 +
 +
#include <float.h>
 +
#include "chuck_fft.h"
 +
#include "fft_num_rec.h"
 +
//-----------------------------------------------------------------------------
 +
// Configuration du chip
 +
//-----------------------------------------------------------------------------
 +
 +
// Horloge interne à 7.37Mhz, x16 par la PLL # 120Mhz
 +
// soit environ 30 MIPS (il y a 4 tics par cycle instruction)
 +
_FOSC(CSW_FSCM_OFF & FRC_PLL16);
 +
_FWDT(WDT_OFF);                /* Watch dog Timer OFF                        */
 +
_FBORPOR(PBOR_OFF );            /* Brown Out OFF, MCLR Enabled                */
 +
_FGS(CODE_PROT_OFF);            /* Code Protect OFF                            */
 +
 +
 +
 +
 +
// Seuil à partir duquel on fait le calcul de position (puissance au carré)
 +
#define PWR_THRESHOLD 0.0
 +
 +
// Nombre total d'échantillons.
 +
// Attention : le buffer contient NB_SAMPLES valeurs réelles
 +
// qui vont donner NB_SAMPLES / 2 valeurs complexes après FFT.
 +
#define NB_SAMPLES 128
 +
 +
//-----------------------------------------------------------------------------
 +
// Définition des fonctions locales
 +
//-----------------------------------------------------------------------------
 +
 +
 +
// Transmet une chaine de caractère sur le port série.
 +
static void print (const char * msg);
 +
 +
// Démarre une séquence d'échantillonnage (63 valeurs))
 +
void do_sampling( void );
 +
 +
// Effectue le calcul de corrélation
 +
void do_gcc( void );
 +
 +
// Affiche le résultat de la FFT sous forme d'histogramme
 +
void dump_data( int channel );
 +
 +
// Normalise dans [0,1] les valeurs complexes à partie imaginaire
 +
// nulle.
 +
void normalize( int channel );
 +
 +
// Retourne la puissance (carrée) maximale du signal complexe.
 +
float maxpwr( int channel);
 +
 +
// Affiche la position par un "#".
 +
// La position est comprise entre 0 et 70.
 +
void show_pos ( int pos ) ;
 +
 +
//-----------------------------------------------------------------------------
 +
// Définition des variables globales internes
 +
//-----------------------------------------------------------------------------
 +
 +
// Compteur d'échantillons.
 +
unsigned char nb_samples=0;
 +
 +
// Les délais calculés par la GCC doivent être filtrés.
 +
// Nombre de délais pris en compte pour le filtrage par moyenne glissante.
 +
// Doit être une puissance de 2.
 +
#define MAX_DELAYS 4
 +
//  Variables utilisées pour le filtrage des délais
 +
float delays[MAX_DELAYS];  // Les délais mesurés sur les n derniers cycles;
 +
int delays_ind = 0;      // L'index dans le buffer.
 +
 +
//-----------------------------------------------------------------------------
 +
// Définition des variables globales externes
 +
//-----------------------------------------------------------------------------
 +
 +
//-----------------------------------------------------------------------------
 +
// Le signal.
 +
//-----------------------------------------------------------------------------
 +
 +
// La variable "data" contient les NB_SAMPLES échantillons réels en entrée
 +
// et les NB_SAMPLES/2 valeurs complexes en sortie de la FFT.
 +
float data[2][NB_SAMPLES];
 +
 +
// Utilisés pour naviguer dans le tableau data.
 +
static unsigned int * p_int_ch0 = (unsigned int *) & data[0][0];
 +
static unsigned int * p_int_ch1 = (unsigned int *) & data[1][0];
 +
 +
//-----------------------------------------------------------------------------
 +
// Définition des ports
 +
//-----------------------------------------------------------------------------
 +
// Attention : la modification d'un port de sortie doit utiliser LAT et non PORT
 +
// car si on utilise PORT, le compilo. génère un READ-MODIFY-WRITE qui va
 +
// entrainer la modification des bits AUTRES que celui que l'on veut modifier...
 +
#define LED0 LATEbits.LATE0
 +
#define LED1 LATEbits.LATE1
 +
 +
//-----------------------------------------------------------------------------
 +
//  Setup ports
 +
//-----------------------------------------------------------------------------
 +
// PORT B
 +
// - D0 : ---
 +
// - D1 : ---
 +
// - D2 : <= SOUND 1 IN (Analog input)
 +
// - D3 : <= SOUND 2 IN (Analog input)
 +
// - D4 : ---
 +
// - D5 : ---
 +
// - D6 : ---
 +
// - D7 : ---
 +
// - D8 : ==
 +
// PORT C
 +
// - D0 : ---
 +
// - D1 : ---
 +
// - D2 : ---
 +
// - D3 : ---
 +
// - D4 : ---
 +
// - D5 : ---
 +
// - D6 : ---
 +
// - D7 : ---
 +
// PORT D
 +
// - D0 : ---
 +
// - D1 : ---
 +
// - D2 : ---
 +
// - D3 : ---
 +
// - D4 : ---
 +
// - D5 : ---
 +
// - D6 : ---
 +
// - D7 : ---
 +
// PORT E
 +
// - D0 : => LED 1
 +
// - D1 : => LED 2
 +
// - D2 : ---
 +
// - D3 : ---
 +
// - D4 : ---
 +
// - D5 : ---
 +
// - D6 : ---
 +
// - D7 : ---
 +
// - D8 : ---
 +
// PORT F
 +
// - D0 : ---
 +
// - D1 : ---
 +
// - D2 : ---
 +
// - D3 : ---
 +
// - D4 : U2RX
 +
// - D5 : U2TX => Vers PC via convertisseur RS232 TTL <=> USB
 +
// - D6 : ---
 +
// - D7 : ---
 +
 +
// Attention : un bit à 1 dans TRIS<X> signifie "ENTREE"
 +
void setup_ports()
 +
{
 +
// Tous les ports à 0
 +
PORTB=0;
 +
PORTC=0;
 +
PORTD=0;
 +
PORTE=0;
 +
PORTF=0;
 +
 +
// Positionnement de la direction des ports (par défaut en entrée)
 +
  TRISB = 0xFFFF;
 +
  TRISC = 0xFFFF;
 +
  TRISD = 0xFFFF;
 +
 +
TRISE = 0xFFFF;
 +
            TRISEbits.TRISE0=0; // LED 0
 +
            TRISEbits.TRISE1=0; // LED 1
 +
 +
  TRISF = 0xFFFF;
 +
 +
}
 +
 +
/*
 +
* Configuration des lignes séries
 +
*/
 +
void setup_serials()
 +
{
 +
    // Configuration 8 N 1
 +
    U2MODEbits.PDSEL = 0;
 +
    U2MODEbits.STSEL = 0;
 +
 +
    // Baud Rate Generator (BRG) à 15
 +
    // soit :
 +
    // Fcy = 7.37e6 x 16 ) / 4
 +
    // Bds = Fcy / (16 x (BRG+1)) = 115156 # 115200 bds
 +
    U2BRG = 15;
 +
 +
    // Activation du port no 2 (broches 28=RX, 27=TX)
 +
    U2MODEbits.UARTEN=1;
 +
    U2STAbits.UTXEN=1;
 +
}
 +
 +
 +
/*
 +
* Configuration des timers
 +
*/
 +
void setup_timers()
 +
{
 +
    // Configuration du timer de conversion de l'ADC
 +
    T3CONbits.TCKPS = 0b0; // Prescaler 1/1
 +
    T3CONbits.TCS = 0 ;    // Internal clock = Tosc/4
 +
    TMR3 = 0;
 +
    PR3 = 295;  // Cette valeur correspond à une fréquence de 100Khz :
 +
                // fCy/295 = 7.37e6 x 16 /4 / 295 = 100000
 +
 +
}
 +
 +
/*
 +
* Configuration de l'ADC .
 +
*/
 +
void setup_adc()
 +
{
 +
    // Inhibition de l'ADC
 +
    ADCON1bits.ADON = 0;
 +
 +
    // Configuration en entrée analogique de AN2 et AN3
 +
    ADPCFGbits.PCFG2 = 0;
 +
    ADPCFGbits.PCFG3 = 0;
 +
 +
    // Configuration des références de tension :
 +
    ADCON2bits.VCFG= 0b0; // References de tension AVDD / AVSS
 +
 +
    // Configuration des temps d'échantillonnage
 +
    // TAD=TCYC/2(ADCS+1))
 +
    ADCON3bits.ADCS=63;
 +
    ADCON3bits.SAMC=31;
 +
    ADCON3bits.ADRC= 0;        // Utilisation de l'horloge système.
 +
 +
    ADCON1bits.SIMSAM = 0b01; // Simultaneous sampling
 +
 +
    ADCON1bits.SSRC = 0b010; // Conversion trigger sur le timer 3
 +
    ADCON1bits.ASAM = 0b1; // L'échantillonnage est automatique après fin
 +
                                // de la conversion
 +
 +
    ADCON1bits.FORM = 0b0; // Représentation des valeurs en entier.
 +
 +
 +
    // Configuration des entrées des samplers (MUXA)
 +
    ADCHSbits.CH123NA = 0;  // CH1, CH2, CH3 negative input is VREF-
 +
    ADCHSbits.CH123SA = 1 ; // CH1 positive input is AN3, CH2 positive input
 +
                            // is AN4, CH3 positive input is AN5
 +
    ADCHSbits.CH0NA = 0;    // CH0 negative input is VREF-
 +
    ADCHSbits.CH0SA = 2;    // CH0 positive input is AN2
 +
    ADCSSL = 0b0;
 +
 +
    ADCON2bits.CHPS = 0b01; // Convert channels 0 and 1
 +
    ADCON2bits.ALTS = 0;    // MUX A only
 +
    ADCON2bits.CSCNA = 0;  // Do not scan inputs
 +
 +
    ADCON3bits.ADRC=0b0;
 +
 +
    ADCON2bits.BUFM = 0;    // 1 seul groupe de 16 buffers
 +
    ADCON2bits.SMPI = 1;    // Interruption après deux conversions,
 +
                            // Les résultats sont donc dans ADCBUF0..3 puisqu'on
 +
                            // échantillonne ch0 et ch1.
 +
 +
    // Activation de l'ADC
 +
    ADCON1bits.ADON = 1;
 +
 +
    // Autoriser les interruptions sur ADC
 +
    IEC0bits.ADIE = 1;
 +
 +
}
 +
 +
/*
 +
* Configuration des ITs externes
 +
*/
 +
void setup_it()
 +
{
 +
    // Aucune it externe.
 +
}
 +
 +
 +
 +
// Traitement de l'IT 1
 +
void __attribute__((__interrupt__,auto_psv)) _INT1Interrupt(void)
 +
{
 +
    // Effacement du bit d'interruption
 +
    IFS1bits.INT1IF = 0;
 +
}
 +
 +
 +
// Traitement de l'IT 0
 +
void __attribute__((__interrupt__,auto_psv)) _INT0Interrupt(void)
 +
{
 +
    // Effacement du bit d'interruption
 +
    IFS0bits.INT0IF = 0;
 +
}
 +
 +
 +
 +
/*
 +
* Handler de l'IT timer
 +
*/
 +
void __attribute__((__interrupt__, auto_psv)) _T1Interrupt( void )
 +
{
 +
    // Effacement du bit d'interruption.
 +
    IFS0bits.T1IF = 0;
 +
}
 +
 +
 +
// Handler de l'IT ADC.
 +
// Elle est générée toutes les deux phases de sampling.
 +
// Le buffer contient donc 2x2 échantillons (2 par canal).
 +
void __attribute__((interrupt, no_auto_psv)) _ADCInterrupt(void)
 +
{
 +
    // On lit les valeurs et on les place dans les buffers.
 +
    // (Les valeurs sont placées dans des emplacements
 +
    // contigues, donc sur une valeur réelle puis sur une valeur
 +
    // complexes. Elles seront déplacées plus tard.)
 +
    nb_samples--;
 +
    *(p_int_ch0+nb_samples) = ADCBUF0;
 +
    *(p_int_ch1+nb_samples) = ADCBUF1;
 +
    nb_samples--;
 +
    *(p_int_ch0+nb_samples) = ADCBUF2;
 +
    *(p_int_ch1+nb_samples) = ADCBUF3;
 +
 +
    LED1 = ~LED1;
 +
    // On arrête le timer lorsque tous les échantillons ont été obtenus.
 +
    if ( ! nb_samples )
 +
        T3CONbits.TON = 0;
 +
 +
    // Acquittement de l'interruption.
 +
    IFS0bits.ADIF = 0;
 +
 +
 +
}
 +
 +
//-----------------------------------------------------------------------------
 +
// Programme principal
 +
//-----------------------------------------------------------------------------
 +
void setup_globals()
 +
{
 +
    int i;
 +
    for ( i =0; i < MAX_DELAYS; i++)
 +
        delays[i]= 1.0;
 +
 +
}
 +
 +
//-----------------------------------------------------------------------------
 +
// Programme principal
 +
//-----------------------------------------------------------------------------
 +
 +
int main()
 +
{
 +
 +
    // Configuration des ports d'I/O
 +
    setup_ports();
 +
 +
    // Configuration des lignes séries
 +
    setup_serials();
 +
 +
    // Configuration de l'ADC
 +
    setup_adc();
 +
 +
    // Configuration des interruptions
 +
    //setup_it();
 +
 +
    // Configuration du timer "ligne"
 +
    setup_timers();
 +
 +
    // Initialisation des variables globales (si si...)
 +
    setup_globals();
 +
 +
    while(1) {
 +
        LED0 = ~LED0;
 +
        do_sampling();
 +
 +
        while( nb_samples );
 +
 +
      do_gcc();
 +
 +
        // __delay_ms(100);
 +
    }
 +
}
 +
 +
 +
 +
// Transmet une chaine de caractère sur le port série
 +
void print ( const char * msg)
 +
{
 +
    while (*msg)
 +
    {
 +
        // Attente de disponibilité du buffer
 +
        // 1 = buffer full
 +
        while ( U2STAbits.UTXBF );
 +
        // Envoi du caractère
 +
        U2TXREG = *msg;
 +
        msg++;
 +
    }
 +
}
 +
 +
// Démarre une séquence d'échantillonnage (63 valeurs))
 +
void do_sampling( void )
 +
{
 +
    nb_samples = NB_SAMPLES;
 +
    T3CONbits.TON = 1;  // Démarrer le timer de conversion
 +
}
 +
 +
 +
void do_gcc( void )
 +
{
 +
    char msg[40];
 +
    int i;
 +
  float filtered_delay = 0.0;
 +
 +
        // Conversion des échantillons en flottants entre 0 et 1.
 +
        for ( i=NB_SAMPLES-1; i>0  ; i--)
 +
        {
 +
            // Partie réelle.
 +
            data[0][i] = ((float) *(p_int_ch0+i)) / 1023.0;
 +
            data[1][i] = ((float) *(p_int_ch1+i)) / 1023.0;
 +
 +
        }
 +
 +
        // Calcul de la FFT sur des échantillons réels.
 +
        // data doit contenir 2*N valeurs flottantes.
 +
        // La fonction retourne N valeurs complexes.
 +
        rfft(&data[0][0], NB_SAMPLES/2, FFT_FORWARD);
 +
        rfft(&data[1][0], NB_SAMPLES/2, FFT_FORWARD);
 +
 +
        // On ne poursuit le calcul que si la puissance est suffisante.
 +
      if (maxpwr(0) > PWR_THRESHOLD)
 +
        {
 +
            // Calcul du conjugué de fft(sig2)
 +
            for ( i=0;i<NB_SAMPLES/2; i++)
 +
                    data[1][i*2+1] = -data[1][i*2+1];
 +
 +
            // Calcul de la GCC : [fft(sig1)*.conj(fft(sig2))];
 +
            for ( i=0;i<NB_SAMPLES/2; i++)
 +
            {
 +
              float tmp1 = data[0][i*2]*data[1][i*2]-data[0][i*2+1]*data[1][i*2+1];
 +
              float tmp2 = data[0][i*2]*data[1][i*2+1]+data[1][i*2]*data[0][i*2+1];
 +
              data[0][i*2] = tmp1;
 +
              data[0][i*2+1] = tmp2;
 +
            }
 +
 +
            // Calcul de la transformée inverse
 +
            cfft(&data[0][0], NB_SAMPLES/2,FFT_INVERSE);
 +
 +
            // Normalisation dans [0.0, 1.0]
 +
          normalize(0);
 +
 +
          // Filtrage
 +
          delays[delays_ind] = data[0][2];
 +
          delays_ind = ( delays_ind + 1) & (MAX_DELAYS-1);
 +
          for ( i = 0; i < MAX_DELAYS ; i++ )
 +
              filtered_delay += delays[i];
 +
          filtered_delay  = filtered_delay / (float) MAX_DELAYS;
 +
 +
          // Affichage de la courbe
 +
          // dump_data(0);
 +
 +
          // Affichage du décalage (100 est au centre)
 +
          show_pos((int)(filtered_delay*70.0));
 +
        }
 +
}
 +
 +
// Retourne la puissance (carrée) maximale du signal complexe.
 +
float maxpwr( int ch )
 +
{
 +
    int i;
 +
 +
    // Calcul du max
 +
    float pwr, maxpwr = FLT_MIN;
 +
    for ( i = 1; i< (NB_SAMPLES/2); i++)
 +
    {
 +
            pwr=data[ch][i*2]*data[ch][i*2]+data[ch][i*2+1]*data[ch][i*2+1];
 +
 +
            if ( pwr > maxpwr )
 +
            {
 +
                    maxpwr = pwr;
 +
            }
 +
    }
 +
    return maxpwr;
 +
}
 +
 +
// Affiche le résultat de la FFT sous forme d'histogramme
 +
void dump_data( int channel )
 +
{
 +
 +
    int col, line;
 +
 +
    print("\33[2J");
 +
 +
    for ( line= 32; line>=0; line--)
 +
    {
 +
      for (col=1; col< NB_SAMPLES/2; col++)
 +
      {
 +
          float val = line / 32.0 ;
 +
            if  ( data[channel][col<<1] >=  val )
 +
                print("#");
 +
            else
 +
                print(" ");
 +
      }
 +
      print("\n\r");
 +
    }
 +
}
 +
 +
 +
// Retourne la position sous la forme d'une chaine
 +
// pos est comprise entre 0 et 70.
 +
// ------------<>----
 +
void show_pos ( int pos )
 +
{
 +
    char  msg[74];
 +
    int i = 0;
 +
   
 +
 +
    for ( i = 0; i < pos ; i++ )
 +
        msg[i]=' ';
 +
    msg[pos]='#';
 +
    msg[pos+1]='\r';
 +
    msg[pos+2]='\n';
 +
  msg[pos+3]=0;
 +
    print(msg);
 +
}
 +
/* Normalise les valeurs (réelles) du canal */
 +
void normalize( int channel )
 +
{
 +
    int i, imax, imin = 0;
 +
    double vmax = FLT_MIN;
 +
    double vmin = FLT_MAX;
 +
    for ( i =0; i<NB_SAMPLES/2;i++)
 +
    {
 +
        if ( data[channel][i*2] > vmax )
 +
        {
 +
            imax = i;
 +
            vmax = data[channel][i*2];
 +
        }
 +
        else
 +
        if ( data[channel][i*2] < vmin )
 +
        {
 +
            imin = i;
 +
            vmin = data[channel][i*2];
 +
        }
 +
    }
 +
 +
    if ( vmax != vmin )
 +
        for ( i =0; i<NB_SAMPLES/2;i++)
 +
            data[channel][i*2] = (data[channel][i*2]-vmin) / (vmax-vmin);
 +
 +
 +
}

Revision as of 16:34, 21 April 2014

Le code C de test de la GCC

Le code de la version (préliminaire est donné ci-après) :

// (Eric)

// La fréquence d'horloge est fosc= 7.42MHz x 16 (PLL) =118.72MHz // Le temps de cycle est fcy = fosc/4, soit :

  1. define FCY 29680000UL
  1. include <xc.h>
  2. include <libpic30.h>
  3. include <dsp.h>
  4. include <stdio.h>
  1. include <float.h>
  2. include "chuck_fft.h"
  3. include "fft_num_rec.h"

//----------------------------------------------------------------------------- // Configuration du chip //-----------------------------------------------------------------------------

// Horloge interne à 7.37Mhz, x16 par la PLL # 120Mhz // soit environ 30 MIPS (il y a 4 tics par cycle instruction) _FOSC(CSW_FSCM_OFF & FRC_PLL16); _FWDT(WDT_OFF); /* Watch dog Timer OFF */ _FBORPOR(PBOR_OFF ); /* Brown Out OFF, MCLR Enabled */ _FGS(CODE_PROT_OFF); /* Code Protect OFF */



// Seuil à partir duquel on fait le calcul de position (puissance au carré)

  1. define PWR_THRESHOLD 0.0

// Nombre total d'échantillons. // Attention : le buffer contient NB_SAMPLES valeurs réelles // qui vont donner NB_SAMPLES / 2 valeurs complexes après FFT.

  1. define NB_SAMPLES 128

//----------------------------------------------------------------------------- // Définition des fonctions locales //-----------------------------------------------------------------------------


// Transmet une chaine de caractère sur le port série. static void print (const char * msg);

// Démarre une séquence d'échantillonnage (63 valeurs)) void do_sampling( void );

// Effectue le calcul de corrélation void do_gcc( void );

// Affiche le résultat de la FFT sous forme d'histogramme void dump_data( int channel );

// Normalise dans [0,1] les valeurs complexes à partie imaginaire // nulle. void normalize( int channel );

// Retourne la puissance (carrée) maximale du signal complexe. float maxpwr( int channel);

// Affiche la position par un "#". // La position est comprise entre 0 et 70. void show_pos ( int pos ) ;

//----------------------------------------------------------------------------- // Définition des variables globales internes //-----------------------------------------------------------------------------

// Compteur d'échantillons. unsigned char nb_samples=0;

// Les délais calculés par la GCC doivent être filtrés. // Nombre de délais pris en compte pour le filtrage par moyenne glissante. // Doit être une puissance de 2.

  1. define MAX_DELAYS 4

// Variables utilisées pour le filtrage des délais float delays[MAX_DELAYS]; // Les délais mesurés sur les n derniers cycles; int delays_ind = 0; // L'index dans le buffer.

//----------------------------------------------------------------------------- // Définition des variables globales externes //-----------------------------------------------------------------------------

//----------------------------------------------------------------------------- // Le signal. //-----------------------------------------------------------------------------

// La variable "data" contient les NB_SAMPLES échantillons réels en entrée // et les NB_SAMPLES/2 valeurs complexes en sortie de la FFT. float data[2][NB_SAMPLES];

// Utilisés pour naviguer dans le tableau data. static unsigned int * p_int_ch0 = (unsigned int *) & data[0][0]; static unsigned int * p_int_ch1 = (unsigned int *) & data[1][0];

//----------------------------------------------------------------------------- // Définition des ports //----------------------------------------------------------------------------- // Attention : la modification d'un port de sortie doit utiliser LAT et non PORT // car si on utilise PORT, le compilo. génère un READ-MODIFY-WRITE qui va // entrainer la modification des bits AUTRES que celui que l'on veut modifier...

  1. define LED0 LATEbits.LATE0
  2. define LED1 LATEbits.LATE1

//----------------------------------------------------------------------------- // Setup ports //----------------------------------------------------------------------------- // PORT B // - D0 : --- // - D1 : --- // - D2 : <= SOUND 1 IN (Analog input) // - D3 : <= SOUND 2 IN (Analog input) // - D4 : --- // - D5 : --- // - D6 : --- // - D7 : --- // - D8 : == // PORT C // - D0 : --- // - D1 : --- // - D2 : --- // - D3 : --- // - D4 : --- // - D5 : --- // - D6 : --- // - D7 : --- // PORT D // - D0 : --- // - D1 : --- // - D2 : --- // - D3 : --- // - D4 : --- // - D5 : --- // - D6 : --- // - D7 : --- // PORT E // - D0 : => LED 1 // - D1 : => LED 2 // - D2 : --- // - D3 : --- // - D4 : --- // - D5 : --- // - D6 : --- // - D7 : --- // - D8 : --- // PORT F // - D0 : --- // - D1 : --- // - D2 : --- // - D3 : --- // - D4 : U2RX // - D5 : U2TX => Vers PC via convertisseur RS232 TTL <=> USB // - D6 : --- // - D7 : ---

// Attention : un bit à 1 dans TRIS<X> signifie "ENTREE" void setup_ports() { // Tous les ports à 0 PORTB=0; PORTC=0; PORTD=0; PORTE=0; PORTF=0;

// Positionnement de la direction des ports (par défaut en entrée)

 	TRISB = 0xFFFF;
 	TRISC = 0xFFFF;
 	TRISD = 0xFFFF;

TRISE = 0xFFFF;

           TRISEbits.TRISE0=0; // LED 0
           TRISEbits.TRISE1=0; // LED 1
 	TRISF = 0xFFFF;

}

/*

* Configuration des lignes séries
*/

void setup_serials() {

   // Configuration 8 N 1
   U2MODEbits.PDSEL = 0;
   U2MODEbits.STSEL = 0;
   // Baud Rate Generator (BRG) à 15
   // soit :
   // Fcy = 7.37e6 x 16 ) / 4
   // Bds = Fcy / (16 x (BRG+1)) = 115156 # 115200 bds
    U2BRG = 15;
   // Activation du port no 2 (broches 28=RX, 27=TX)
   U2MODEbits.UARTEN=1;
   U2STAbits.UTXEN=1;

}


/*

* Configuration des timers
*/

void setup_timers() {

   // Configuration du timer de conversion de l'ADC
   T3CONbits.TCKPS = 0b0; // Prescaler 1/1
   T3CONbits.TCS = 0 ;     // Internal clock = Tosc/4
   TMR3 = 0;
   PR3 = 295;  // Cette valeur correspond à une fréquence de 100Khz :
               // fCy/295 = 7.37e6 x 16 /4 / 295 = 100000

}

/*

* Configuration de l'ADC .
*/ 

void setup_adc() {

   // Inhibition de l'ADC
   ADCON1bits.ADON = 0;
   // Configuration en entrée analogique de AN2 et AN3
   ADPCFGbits.PCFG2 = 0;
   ADPCFGbits.PCFG3 = 0;
   // Configuration des références de tension :
   ADCON2bits.VCFG= 0b0; 	// References de tension AVDD / AVSS
   // Configuration des temps d'échantillonnage
   // TAD=TCYC/2(ADCS+1))
   ADCON3bits.ADCS=63;
   ADCON3bits.SAMC=31;
   ADCON3bits.ADRC= 0;         // Utilisation de l'horloge système.
   ADCON1bits.SIMSAM = 0b01;	// Simultaneous sampling
   ADCON1bits.SSRC = 0b010;	// Conversion trigger sur le timer 3
   ADCON1bits.ASAM = 0b1;	// L'échantillonnage est automatique après fin
                               // de la conversion
   ADCON1bits.FORM = 0b0;	// Représentation des valeurs en entier.


   // Configuration des entrées des samplers (MUXA)
   ADCHSbits.CH123NA = 0;  // CH1, CH2, CH3 negative input is VREF-
   ADCHSbits.CH123SA = 1 ; // CH1 positive input is AN3, CH2 positive input
                           // is AN4, CH3 positive input is AN5
   ADCHSbits.CH0NA = 0;    // CH0 negative input is VREF-
   ADCHSbits.CH0SA = 2;    // CH0 positive input is AN2
   ADCSSL = 0b0;
   ADCON2bits.CHPS = 0b01; // Convert channels 0 and 1
   ADCON2bits.ALTS = 0;    // MUX A only
   ADCON2bits.CSCNA = 0;   // Do not scan inputs
   ADCON3bits.ADRC=0b0;
   ADCON2bits.BUFM = 0;    // 1 seul groupe de 16 buffers
   ADCON2bits.SMPI = 1;    // Interruption après deux conversions,
                           // Les résultats sont donc dans ADCBUF0..3 puisqu'on
                           // échantillonne ch0 et ch1.
   // Activation de l'ADC
   ADCON1bits.ADON = 1;
   // Autoriser les interruptions sur ADC
   IEC0bits.ADIE = 1;

}

/*

* Configuration des ITs externes 
*/

void setup_it() {

   // Aucune it externe.

}


// Traitement de l'IT 1 void __attribute__((__interrupt__,auto_psv)) _INT1Interrupt(void) {

   // Effacement du bit d'interruption
   IFS1bits.INT1IF = 0;

}


// Traitement de l'IT 0 void __attribute__((__interrupt__,auto_psv)) _INT0Interrupt(void) {

   // Effacement du bit d'interruption
   IFS0bits.INT0IF = 0;

}


/*

* Handler de l'IT timer
*/

void __attribute__((__interrupt__, auto_psv)) _T1Interrupt( void ) {

   // Effacement du bit d'interruption.
   IFS0bits.T1IF = 0;

}


// Handler de l'IT ADC. // Elle est générée toutes les deux phases de sampling. // Le buffer contient donc 2x2 échantillons (2 par canal). void __attribute__((interrupt, no_auto_psv)) _ADCInterrupt(void) {

   // On lit les valeurs et on les place dans les buffers.
   // (Les valeurs sont placées dans des emplacements
   // contigues, donc sur une valeur réelle puis sur une valeur
   // complexes. Elles seront déplacées plus tard.)
   nb_samples--;
   *(p_int_ch0+nb_samples) = ADCBUF0;
   *(p_int_ch1+nb_samples) = ADCBUF1;
   nb_samples--;
   *(p_int_ch0+nb_samples) = ADCBUF2;
   *(p_int_ch1+nb_samples) = ADCBUF3;
   LED1 = ~LED1;
   // On arrête le timer lorsque tous les échantillons ont été obtenus.
   if ( ! nb_samples )
       T3CONbits.TON = 0;
   // Acquittement de l'interruption.
   IFS0bits.ADIF = 0;


}

//----------------------------------------------------------------------------- // Programme principal //----------------------------------------------------------------------------- void setup_globals() {

   int i;
   for ( i =0; i < MAX_DELAYS; i++)
       delays[i]= 1.0;

}

//----------------------------------------------------------------------------- // Programme principal //-----------------------------------------------------------------------------

int main() {

   // Configuration des ports d'I/O
   setup_ports();
   // Configuration des lignes séries
   setup_serials();
   // Configuration de l'ADC
   setup_adc();
   // Configuration des interruptions
   //setup_it();
   // Configuration du timer "ligne"
   setup_timers();
   // Initialisation des variables globales (si si...)
   setup_globals();
   while(1) {
       LED0 = ~LED0;
       do_sampling();
       while( nb_samples );
      do_gcc();
       // __delay_ms(100);
   }

}


// Transmet une chaine de caractère sur le port série void print ( const char * msg) {

   while (*msg)
   {
       // Attente de disponibilité du buffer
       // 1 = buffer full
       while ( U2STAbits.UTXBF );
       // Envoi du caractère
       U2TXREG = *msg;
       msg++;
   }

}

// Démarre une séquence d'échantillonnage (63 valeurs)) void do_sampling( void ) {

   nb_samples = NB_SAMPLES;
   T3CONbits.TON = 1;  // Démarrer le timer de conversion

}


void do_gcc( void ) {

   char msg[40];
   int i;
  float filtered_delay = 0.0;
       // Conversion des échantillons en flottants entre 0 et 1.
       for ( i=NB_SAMPLES-1; i>0  ; i--)
       {
           // Partie réelle.
           data[0][i] = ((float) *(p_int_ch0+i)) / 1023.0;
           data[1][i] = ((float) *(p_int_ch1+i)) / 1023.0;
       }

       // Calcul de la FFT sur des échantillons réels.
       // data doit contenir 2*N valeurs flottantes.
       // La fonction retourne N valeurs complexes.
       rfft(&data[0][0], NB_SAMPLES/2, FFT_FORWARD);
       rfft(&data[1][0], NB_SAMPLES/2, FFT_FORWARD);
       // On ne poursuit le calcul que si la puissance est suffisante.
      if (maxpwr(0) > PWR_THRESHOLD)
       {
           // Calcul du conjugué de fft(sig2)
           for ( i=0;i<NB_SAMPLES/2; i++)
                   data[1][i*2+1] = -data[1][i*2+1];
           // Calcul de la GCC : [fft(sig1)*.conj(fft(sig2))];
           for ( i=0;i<NB_SAMPLES/2; i++)
           {
              float tmp1 = data[0][i*2]*data[1][i*2]-data[0][i*2+1]*data[1][i*2+1];
              float tmp2 = data[0][i*2]*data[1][i*2+1]+data[1][i*2]*data[0][i*2+1];
              data[0][i*2] = tmp1;
              data[0][i*2+1] = tmp2;
           }
           // Calcul de la transformée inverse
           cfft(&data[0][0], NB_SAMPLES/2,FFT_INVERSE);
           // Normalisation dans [0.0, 1.0]
          normalize(0);
          // Filtrage
          delays[delays_ind] = data[0][2];
          delays_ind = ( delays_ind + 1) & (MAX_DELAYS-1);
          for ( i = 0; i < MAX_DELAYS ; i++ )
              filtered_delay += delays[i];
          filtered_delay  = filtered_delay / (float) MAX_DELAYS;
          // Affichage de la courbe
          // dump_data(0);
          // Affichage du décalage (100 est au centre)
          show_pos((int)(filtered_delay*70.0));
       }

}

// Retourne la puissance (carrée) maximale du signal complexe. float maxpwr( int ch ) {

   int i;
   // Calcul du max
   float pwr, maxpwr = FLT_MIN;
   for ( i = 1; i< (NB_SAMPLES/2); i++)
   {
           pwr=data[ch][i*2]*data[ch][i*2]+data[ch][i*2+1]*data[ch][i*2+1];
           if ( pwr > maxpwr )
           {
                   maxpwr = pwr;
           }
   }
   return maxpwr;

}

// Affiche le résultat de la FFT sous forme d'histogramme void dump_data( int channel ) {

   int col, line;
   print("\33[2J");
   for ( line= 32; line>=0; line--)
   {
     for (col=1; col< NB_SAMPLES/2; col++)
      {
         float val = line / 32.0 ;
           if  ( data[channel][col<<1] >=  val )
               print("#");
           else
               print(" ");
     }
     print("\n\r");
   }

}


// Retourne la position sous la forme d'une chaine // pos est comprise entre 0 et 70. // ------------<>---- void show_pos ( int pos ) {

   char  msg[74];
   int i = 0;
   
   for ( i = 0; i < pos ; i++ )
       msg[i]=' ';
   msg[pos]='#';
   msg[pos+1]='\r';
   msg[pos+2]='\n';
  msg[pos+3]=0;
   print(msg);

} /* Normalise les valeurs (réelles) du canal */ void normalize( int channel ) {

   int i, imax, imin = 0;
   double vmax = FLT_MIN;
   double vmin = FLT_MAX;
   for ( i =0; i<NB_SAMPLES/2;i++)
   {
       if ( data[channel][i*2] > vmax )
       {
           imax = i;
           vmax = data[channel][i*2];
       }
       else
       if ( data[channel][i*2] < vmin )
       {
           imin = i;
           vmin = data[channel][i*2];
       }
   }
   if ( vmax != vmin )
       for ( i =0; i<NB_SAMPLES/2;i++)
           data[channel][i*2] = (data[channel][i*2]-vmin) / (vmax-vmin);


}

Personal tools