Autor Tema: Problema con el I2C  (Leído 2687 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Tiri

  • PIC10
  • *
  • Mensajes: 6
Problema con el I2C
« en: 17 de Junio de 2011, 09:12:59 »
Buenas,

llevo un mes detras de un problema y me estoy volviendo loco. Leo perfectamente un RTC con el bus I2C si solo hago esto, pero al augmentar mi código y implementar el ADC con DMA se me corrompe la lectura del RTC y me repite datos o directamente leo 0xFF, cuando ni de coña tendria que leer esto.

Mi archivo de Inicializacion es el siguiente:


#include <p33FJ64GP204.h>
#include "comu.h"


void Inicialitzacio(void)
{
   //********************************************************************************************
   //INICIO PINES
   //********************************************************************************************
       
   PIN21_CLK_0 = 0;                     

   AD1PCFGLbits.PCFG2 = 1;                  

   //********************************************************************************************
   
   PIN22_DAT_0 = 0;                     

   AD1PCFGLbits.PCFG3 = 1;                  

       ETC ETC....

   
   //********************************************************************************************
   //CONFIGURACION PERIFERICOS
   //********************************************************************************************
   
   RPINR18bits.U1CTSR = 0b10011;
   RPINR18bits.U1RXR = 0b10110;
   RPOR6bits.RP12R = 0b00011;
   RPOR7bits.RP15R = 0b00100;
   RPOR0bits.RP0R = 0b01000;
   RPOR0bits.RP1R = 0b00111;

   //********************************************************************************************
   //CONFIGURACION DEL SPI MODO MASTER
   //********************************************************************************************

   SPI1CON1bits.SPRE = 0b000;      
   SPI1CON1bits.PPRE = 0b11;      
   SPI1CON1bits.MSTEN = 1;         
   SPI1CON1bits.MODE16 = 0;      
   SPI1STATbits.SPIROV = 0;      
   SPI1CON1bits.SMP = 1;         
   SPI1STATbits.SPIEN = 1;         
   SPI1CON1bits.DISSDO = 0;      
   SPI1CON1bits.DISSCK = 0;      
   SPI1CON1bits.CKE = 1;         
//   SPI1CON1bits.CKP = 1;         

   //********************************************************************************************
   //CONFIGURACION DEL TIMER1               250 ms // 419.424 ms
   //********************************************************************************************

   T1CONbits.TON = 0;                      
   T1CONbits.TCS = 0;                      
   T1CONbits.TGATE = 0;                   
   T1CONbits.TCKPS = 0b11;
   T1CONbits.TSIDL = 0;   
   TMR1 = 0x00;          
   PR1 = 39062;          
   IPC0bits.T1IP = 0x001;    
   IFS0bits.T1IF = 0;       
   IEC0bits.T1IE = 1;       
   T1CONbits.TON = 1;      
      
   //********************************************************************************************
   //CONFIGURACIO DEL TIMER2               1 ms
   //********************************************************************************************
   
   T2CONbits.TON = 0;       
   T2CONbits.T32 = 0;      
   T2CONbits.TCS = 0;       
   T2CONbits.TGATE = 0;    
   T2CONbits.TCKPS = 0b00;   
   T2CONbits.TSIDL = 0;   
   TMR2 = 0x00;          
   PR2 = 40000;          
   IPC1bits.T2IP = 0x001;    
   IFS0bits.T2IF = 0;       
   IEC0bits.T2IE = 1;       
   T2CONbits.TON = 1;      

   //********************************************************************************************
   //CONFIGURACIO DEL TIMER3               500 us
   //********************************************************************************************

   T3CONbits.TON = 0;       
   T3CONbits.TCS = 0;       
   T3CONbits.TGATE = 0;    
   T3CONbits.TCKPS = 0b00;   
   T3CONbits.TSIDL = 0;   
   TMR3 = 0x00;          
   PR3 = 20000;          
   IPC2bits.T3IP = 0x001;    
   IFS0bits.T3IF = 0;       
   IEC0bits.T3IE = 1;       
   T3CONbits.TON = 1;      

   //********************************************************************************************
   //CONFIGURACIO DEL TIMER4               250 us
   //********************************************************************************************

   T4CONbits.TON = 0;       
   T4CONbits.TCS = 0;       
   T4CONbits.TGATE = 0;    
   T4CONbits.TCKPS = 0b00;   
   T4CONbits.TSIDL = 0;   
   TMR4 = 0x00;          
   PR4 = 800;          
   IPC6bits.T4IP = 0x001;    
   IFS1bits.T4IF = 0;       
   IEC1bits.T4IE = 1;       
   T4CONbits.TON = 1;      

   //*********************************************************************************************
   //CONFIGURACIO DEL DMA
   //*********************************************************************************************

   DMA0CONbits.AMODE = 2;         // Configure DMA for Peripheral indirect mode
   DMA0CONbits.MODE  = 2;         // Configure DMA for Continuous Ping-Pong mode
   
   DMA0PAD=(volatile unsigned int)&ADC1BUF0;
   DMA0CNT = 31;               

   DMA0REQ = 13;

   DMA0STA = __builtin_dmaoffset(BufferA);      
   DMA0STB = __builtin_dmaoffset(BufferB);

   IFS0bits.DMA0IF = 0;         //Clear the DMA interrupt flag bit
        IEC0bits.DMA0IE = 1;         //Set the DMA interrupt enable bit
   IPC1bits.DMA0IP = 0b001;

   DMA0CONbits.CHEN=1;

   //*********************************************************************************************
   //CONFIGURACIO DEL ADC
   //*********************************************************************************************

   AD1CON1bits.FORM = 0;      // Data Output Format: Signed Fraction (Q15 format)
   AD1CON1bits.SSRC = 7;      // Sample Clock Source: GP Timer starts conversion
   AD1CON1bits.ASAM = 1;      // ADC Sample Control: Sampling begins immediately after conversion
   AD1CON1bits.AD12B = 0;      // 10-bit ADC operation

   AD1CON2bits.ALTS = 1;      // Alternate Input Sample Mode Select Bit
   AD1CON2bits.CHPS = 0;      // Converts CH0
   AD1CON3bits.ADRC = 0;      // ADC Clock is derived from Systems Clock
   AD1CON3bits.ADCS = 63;      // ADC Conversion Clock Tad=Tcy*(ADCS+1)= (1/40M)*64 = 1.6us (625Khz)
                        // ADC Conversion Time for 10-bit Tc=12*Tab = 19.2us   

   AD1CON1bits.ADDMABM = 0;    // DMA buffers are built in scatter/gather mode
   AD1CON2bits.SMPI = 1;      // SMPI Must be programmed to 1 for this case
   AD1CON4bits.DMABL = 4;      // Each buffer contains 16 words

        AD1CHS0bits.CH0SA = 0;      // MUXA +ve input selection (AIN4) for CH0
   AD1CHS0bits.CH0NA = 0;      // MUXA -ve input selection (Vref-) for CH0

   AD1CHS0bits.CH0SB=1;      // MUXB +ve input selection (AIN5) for CH0
   AD1CHS0bits.CH0NB=0;      // MUXB -ve input selection (Vref-) for CH0

        AD1PCFGLbits.PCFG0 = 0;      // AN0 as Analog Input
        AD1PCFGLbits.PCFG1 = 0;      // AN1 as Analog Input      
 
        IFS0bits.AD1IF = 0;         // Clear the A/D interrupt flag bit
        IEC0bits.AD1IE = 0;         // Do Not Enable A/D interrupt
        AD1CON1bits.ADON = 1;      // Turn on the A/D converter

   //*********************************************************************************************
   //CONFIGURACION DEL CN
   //*********************************************************************************************

   CNEN1bits.CN6IE = 1;
   CNEN1bits.CN7IE = 1;
   CNEN1bits.CN1IE = 1;
   IEC1bits.CNIE = 1; // Enable CN interrupts
   IFS1bits.CNIF = 0; // Reset CN interrupt   

}

Bien, entonces cuando comento el T4+DMA+ADC no se me corrompe el I2C. El T4 comentado solo si se corrompe, el ADC comentado solo también, el DMA comentado solo también, DMA + ADC comentado también, el T4 + ADC no lo hace, el T4 + DMA tampoco lo hace y así infinidad de combinaciones que he ido probando y cada vez hacen que todo sea mas absurdo, sin sentido, y termine por perder la cabeza.

También si lo tengo todo SIN comentar, pero con las interrupciones CON TODO comentado (menos el borrar el flag de la interrupción) TAMBIÉN se corrompe.

Para solucionarlo de una forma chapuza hago que lea tantas veces como sea necesario el RTC hasta que los bits de control sean los que tengan que ser, y algunas veces lo lee una vez, otras dos, tres etc pero esta no es la solución elegante, solo una chapuza

Ya no se que mas probar... Y problema de hardware no es, ya que he provado con otra placa de mi compañero que funciona correctamente y hace lo mismo. Creo que el problema es de configuración, ya que el código en si del I2C es el que da Microchip y me funciona sin el T4, DMA y ADC

Alguien se le acude que puede ser??

Espero un rayo de luz a mi proyecto con ansias

Muchas gracias
 

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Problema con el I2C
« Respuesta #1 en: 18 de Junio de 2011, 03:00:22 »
¿Puedes publicar también las rutinas de lectura del RTC?, ¿haces estas lecturas por soft o por hard?, ¿es posible que salten interrupciones durante la comunicación I2C?

Desconectado Tiri

  • PIC10
  • *
  • Mensajes: 6
Re: Problema con el I2C
« Respuesta #2 en: 18 de Junio de 2011, 09:15:42 »
Buenas,

Muchas gracias de antemano.

Bien, te adjunto el archivo I2CC.c y I2CC.h que son los que se ocupan de la lectura del RTC (PCF8583T). El main.c tal y como lo tengo con todo comentado es el siguiente:

_FOSCSEL(FNOSC_FRCPLL & IESO_OFF)    
_FOSC(FCKSM_CSECME & OSCIOFNC_ON)    
_FWDT(FWDTEN_OFF)             
_FPOR(ALTI2C_OFF)
_FICD(ICS_PGD2 & JTAGEN_OFF)      

I2C_DRIVERS i2c = I2C_INICI_DRIVERS;
I2C_DADES i2c_escriu;
I2C_DADES i2c_llegeix;

RTC *RtcDat;
char RtcTime[10];

int main(void)
{

   PLLFBD = 0x0029;  //M=43                           //Fosc = Fin (7,37MHz) * ( M / ( N1 * N2 ) )
   CLKDIVbits.PLLPRE = 0x0000;  //N1=2                     //Fcy = Fosc / 2      Fcy = 39613750      Fcy -> 40MHz
   CLKDIVbits.PLLPOST = 0x0000;  //N2=2

   // Initiate Clock Switch to Internal FRC with PLL (NOSC = 0b001)
   __builtin_write_OSCCONH(0x01);
   __builtin_write_OSCCONL(0x01);
   // Wait for Clock switch to occur
   while (OSCCONbits.COSC!= 0b001);
   // Wait for PLL to lock
   while(OSCCONbits.LOCK!= 1) {};

   Inicialitzacio(); // Aqui es donde tengo todo lo del post anterior

   if ( (RtcDat = ( void *)malloc( 2 * sizeof( RTC) * sizeof(char)))==NULL)   //en RtcDat pongo los datos del RTC
      Nop();

   i2c.inici(&i2c);
   i2c_llegeix.buffer = buff;
   i2c_llegeix.numero = MIDA_BUFFER;
   i2c_llegeix.adresa = 0x00;
   i2c_llegeix.localitzacio = 0x00;
   i2c.dades = &i2c_llegeix;
   i2c.comando = I2C_LLEGEIX;
   i2c.driver(&i2c);

   while(1)
   {   

        ReadRTC(RtcDat);     //Todo esto lo hago cada 100 ms con un contador que incremento con la interrupcion del timer1

   if( ((RtcDat->Control&0xFC)!=0) || (((RtcDat->bits.day&0x0F)==0)&&(RtcDat->bits.tenday==0)) || ((RtcDat->bits.month==0)&&(RtcDat->bits.tenmonth==0)) || (RtcDat-             >bits.data3!=0xAE) || (RtcDat->bits.data0!='2'))   
            {
               ERRORI2C
            }
   ChkRTC(RtcDat);
   TimeToAscii(RtcTime);

        }
}

char WriteRTC( void *Rtc)
{
   // Initialise I2C Data object for Write operation
 
    i2c_escriu.buffer = Rtc;
   i2c_escriu.numero = sizeof(RTC);
    i2c_escriu.adresa = 0x00;
    i2c_escriu.localitzacio = 0x00;
   i2c.dades=&i2c_escriu;
   i2c.comando = I2C_ESCRIURE;   

   while(i2c.comando != I2C_IDLE)
     {   
      i2c.driver(&i2c);
   }

   return 0;
}

char ReadRTC( void *Rtc)
{
   UINT16 timeout;
   timeout = -1;
   ClrWdt();

    i2c_llegeix.buffer = Rtc;
    i2c_llegeix.numero = sizeof(RTC);
    i2c_llegeix.adresa = 0x00;            // adreça del log, ultims 16 bytes
    i2c_llegeix.localitzacio = 0x00;
   i2c.dades=&i2c_llegeix;
   i2c.comando = I2C_LLEGEIX;

   while(i2c.comando != I2C_IDLE)
     {
      i2c.driver(&i2c);
   }
   
   if ( !timeout)
      return -1;
   else
      return 0;
}

char ChkRTC( void *Rtc)
{
   
   char rtcerror=0;
   
   if ( ((RtcDat->Control&0xFC)!=0) || (((RtcDat->bits.day&0x0F)==0)&&(RtcDat->bits.tenday==0)) || ((RtcDat->bits.month==0)&&(RtcDat->bits.tenmonth==0)) || (RtcDat->bits.data3!=0xAE) || (RtcDat->bits.data0!='2'))
//   if ((RtcDat->Control&0xFC)!=0)
   {

      RtcDat->Control=0;
      RtcDat->bits.tenmin=0;
      RtcDat->bits.min=0;
      RtcDat->bits.tenhour=0;
      RtcDat->bits.hour=0;
      RtcDat->bits.tensec=0;
      RtcDat->bits.sec=0;
      RtcDat->bits.tenday=0;
      RtcDat->bits.day=1;
      RtcDat->bits.tenmonth=0;
      RtcDat->bits.month=1;
      RtcDat->bits.year=1;
      RtcDat->bits.ampm=1;
      RtcDat->bits.hourform=1;
      RtcDat->bits.dayweek=1;
      RtcDat->bits.timerday=0;
      RtcDat->bits.alarmcontrol=0;
      RtcDat->bits.alarm100sec=0;
      RtcDat->bits.alarm10sec=0;
      RtcDat->bits.alarmsec=0;
      RtcDat->bits.alarmmin=0;
      RtcDat->bits.alarmdate=0;
      RtcDat->bits.alarmhour=0;
      RtcDat->bits.alarmmonth=0;
      RtcDat->bits.alarmtimer=0;
   
      RtcDat->bits.data0='2';
      RtcDat->bits.data1='0';
      RtcDat->bits.data2='1';
      RtcDat->bits.data3=0xAE;

      rtcerror=1;

      WriteRTC(RtcDat);

   }

   return rtcerror;
}


char TimeToAscii( char *Time)
{
   Time[0]='0'+(RtcDat->bits.tenhour&0x03);   
   Time[1]='0'+(RtcDat->bits.hour&0x0f);   
   Time[2]=Time[5]=':';
   Time[3]='0'+(RtcDat->bits.tenmin&0x07);   
   Time[4]='0'+(RtcDat->bits.min&0x0f);      
   Time[6]='0'+(RtcDat->bits.tensec&0x07);   
   Time[7]='0'+(RtcDat->bits.sec&0x0f);      
   Time[8]=0;
   return 0;
}

Entonces en mi archivo comun.h tengo la estructura del RTC

typedef union
{
   UCHAR8   Control __PACKED;   
//   UCHAR8   Data[20] __PACKED;
    struct __PACKED
    {
      UCHAR8   Control;   
      UCHAR8   Time[15];   
      UCHAR8   Data[4];   
    } byte;
    struct __PACKED   
   {
        UINT8 TimerFlag:1;
        UINT8 AlarmFlag:1;
          UINT8 AlarmEnable:1;
        UINT8 MaskFlag:1;
        UINT8 Mode:2;
        UINT8 HoldCount:1;
        UINT8 StopCount:1;

        UINT8 sec100:4;
        UINT8 sec10:4;

        UINT8 sec:4;
        UINT8 tensec:4;

        UINT8 min:4;
        UINT8 tenmin:4;

        UINT8 hour:4;
        UINT8 tenhour:2;
        UINT8 ampm:1;
        UINT8 hourform:1;

        UINT8 day:4;
        UINT8 tenday:2;
        UINT8 year:2;

        UINT8 month:4;
        UINT8 tenmonth:1;
        UINT8 dayweek:3;

        UINT8 timerday:8;
        UINT8 alarmcontrol:8;
        UINT8 alarm100sec:4;
        UINT8 alarm10sec:4;
        UINT8 alarmsec:8;
        UINT8 alarmmin:8;
        UINT8 alarmhour:8;
        UINT8 alarmdate:8;
        UINT8 alarmmonth:8;
        UINT8 alarmtimer:8;
        UINT8 data0:8;
        UINT8 data1:8;
        UINT8 data2:8;
        UINT8 data3:8;
 
   } bits;
} RTC; //_TYPE;


Con lo de la lectura del RTC si la hago por software o por hardware, aqui me has pillado, yo creia que solo había una manera de hacerlo, pero supongo que con los nuevos datos que te doy lo sabras sin problema.

Con lo de las prioridades también lo pensé y estuve modificando las prioridades y poniendo a la interrupción del I2C la mas alta (7), pero tampoco me funciono.

Con este código y las interrupciones sin absolutamente nada me salta al error del I2C.

Muchas gracias por tu tiempo y colaboración.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Problema con el I2C
« Respuesta #3 en: 18 de Junio de 2011, 13:02:25 »
Pues he estado mirando el código y me pierdo, siento no poder serte de ayuda.
Lo que más chocante me ha resultado es ese DISI #10 que deshabilita interrupciones por 10 ciclos, aunque no sé si estará relacionado con tu problema.

Desconectado Tiri

  • PIC10
  • *
  • Mensajes: 6
Re: Problema con el I2C
« Respuesta #4 en: 20 de Junio de 2011, 06:25:20 »
Buenas Nocturno,

gracias igualmente. Este es mi primer proyecto y código con el mundo de los PIC, y supongo que aunque programes no quiere decir que sepas programar bien.

He seguido haciendo pruebas, y he llegado a una "solución" que consiste simplemente en desactivar el DMA cuando voy a leer el RTC y volverlo a activar una vez terminado las funciones de lectura/escritura del RTC.

Lo que no se realmente es el origen del error, y mis opciones son que alguna variable del DMA se me desborde y me llene de basura los datos del RTC, o que salten interrupciones durante la comunicación I2C tal como dijiste...

Seguiré haciendo pruebas y si llego a alguna conclusión al final ya te comentaré, si no, lo dejare tal cual que ya llevo tiempo con este error... Si se te ocurre cualquier cosilla que pudiera provocar el error será de gran ayuda  :)

Gracias

Desconectado saimon

  • PIC10
  • *
  • Mensajes: 11
Re: Problema con el I2C
« Respuesta #5 en: 21 de Junio de 2011, 06:44:59 »
Segun veo en el código no tienes ninguna función asociada a la interrupción del DMA (o al menos no la has puesto). Intenta poner la interrupción para que ponga el flag a 0 despues de cada interrupción. A mi me pasó con la UART y creo que sin el DMA (pero no me acuerdo) de tal manera que cada x ciclos se metía en la interrupción y no me mandaba bien la información (creo que es un caso parecido). Otra cosa que puedes hacer es deshabilitar la interrupción del DMA si no la usas.