Autor Tema: [SOLUCIONADO]Problema con driver y protocolo i2C por software en C18  (Leído 2833 veces)

0 Usuarios y 3 Visitantes están viendo este tema.

Desconectado Thulsa Doom

  • PIC24F
  • *****
  • Mensajes: 771
    • https://electronicadicto.wordpress.com/
Buenas a todos, pues resulta que he estado desarrollando un driver para leer la temperatura de un termómetro digital DS1621 en el compilador C18.
la implementación del protocolo I2C es por software utilizando las librerías de C18 creadas por Microchip para éste fin.
El driver funciona a medias, no funciona por completo, si puedo leer el byte más alto pero el bajo no y la verdad es que no sé que puede estar mal, este mismo código lo implemento con la librería por hardware y no hay problema.

el código es el siguiente:

Código: [Seleccionar]
/* Funsión que lee el valor de los registros TH y TL en una resolución de 0.50 ºC*/

float read_temp_normal_precision(unsigned char address){  // Returns degrees ºC (0 a 257)


   unsigned char ReadTemp_TH, ReadTemp_TL, ReadCounter;

   float ReadTemp;


   //Read Temperature (AAh)

 SWStartI2C();
 SWWriteI2C(0x90 | (address<<1));   //Establecemos la comunicación como escritura
 SWAckI2C();
 SWWriteI2C(0xAA);   //Enviamos el comando  
 SWAckI2C();
 SWRestartI2C();   //Reseteamos el protocolo, sin esto no funciona la                lectura
 SWWriteI2C(0x91 | (address<<1)); //Establecemos la lectura de registro de temperatura del DS1621
 SWAckI2C();
 ReadTemp_TH = SWReadI2C();
 SWAckI2C();       //El Master envía el bit ACK
 ReadTemp_TL = SWGetcI2C();
 SWNotAckI2C();      //El master envía el bit NOACK
 SWStopI2C();

   //Código donde se unen los dos byts en un float  

 ReadTemp = ReadTemp_TH;

     if(ReadTemp_TL == 0b10000000)
      {
       ReadTemp += 0.5;
      }

     return(ReadTemp);  

}

Si alguien puede probarlo y me da su opinión.
Si hace falta que suba el proyecto entero no tienen nada más que decirlo.
Gracias de antemano por la ayuda

EDITADO: Para mayor información, así creo que me pueden ayudar más, subo una imagen de la trama de señales entre el pic y el DS1621


« Última modificación: 10 de Enero de 2013, 10:12:54 por Thulsa Doom »
Más códigos y desarrollos en https://electronicadicto.wordpress.com/ date una vuelta y curiosea un rato...

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Problema con driver y protocolo i2C por software en C18
« Respuesta #1 en: 09 de Enero de 2013, 11:48:33 »
  No utilizo C18 y tampoco conozco sus rutinas... ahora, veo en tu programa que en un caso utilizas SWReadI2C() (cuando lees el byte alto) y cuando lees el byte bajo utilizas SWGetI2C(). ¿Hay alguna diferencia entre dichas funciones? ¿Tal vez allí esté el problema?
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado Thulsa Doom

  • PIC24F
  • *****
  • Mensajes: 771
    • https://electronicadicto.wordpress.com/
Re: Problema con driver y protocolo i2C por software en C18
« Respuesta #2 en: 09 de Enero de 2013, 12:56:42 »
  No utilizo C18 y tampoco conozco sus rutinas... ahora, veo en tu programa que en un caso utilizas SWReadI2C() (cuando lees el byte alto) y cuando lees el byte bajo utilizas SWGetI2C(). ¿Hay alguna diferencia entre dichas funciones? ¿Tal vez allí esté el problema?

No, no tiene que ver, eso fue un error al colgar el código, estuve probando cosillas y se me quedo así pero las dos funciones hacen exactamente lo mismo.
según veo en el simulador proteus se supone que después de leer el primer byte tiene que generar un bit Ack y lo que genera es un NotAck y la verdad es que no sé por que, el mismo código implementado con las librerías por hardware funciona perfecto
Más códigos y desarrollos en https://electronicadicto.wordpress.com/ date una vuelta y curiosea un rato...

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Problema con driver y protocolo i2C por software en C18
« Respuesta #3 en: 09 de Enero de 2013, 15:12:53 »
¿Existe una única función para el manejo de las respuestas (ACK)? Quiero decir, ¿se utiliza la misma función tanto cuando se trata de una respuesta del dispositivo como cuando se trata de una respuesta del master?

  Pregunto porque entre byte alto y byte bajo es el master quien tiene que responder con ACK, y veo que utilizas la misma función en el caso de una respuesta por parte del dispositivo como en el caso del master
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado Thulsa Doom

  • PIC24F
  • *****
  • Mensajes: 771
    • https://electronicadicto.wordpress.com/
Re: Problema con driver y protocolo i2C por software en C18
« Respuesta #4 en: 09 de Enero de 2013, 20:02:43 »
¿Existe una única función para el manejo de las respuestas (ACK)? Quiero decir, ¿se utiliza la misma función tanto cuando se trata de una respuesta del dispositivo como cuando se trata de una respuesta del master?

  Pregunto porque entre byte alto y byte bajo es el master quien tiene que responder con ACK, y veo que utilizas la misma función en el caso de una respuesta por parte del dispositivo como en el caso del master

Eso es lo que me he estado preguntando pero las únicas funciones que hay en la librería son esas no hay nada más y en el manual no pone nada o yo no lo veo.
subo una captura del manual donde se muestran las funciones del protocolo


Cuando esto mismo lo implemento con la librerías i2c por hardware no hace falta poner los ack en todo el código si no los dos del master al final, pero si lo hago así en el de software, no funciona bien y dan datos erróneos

Tal y cómo está ahora si me captura bien el byte más alto y me da el valor de temperatura pero el byte bajo no me lo captura bien y no puedo tener la resolución de 0,5ºC
Más códigos y desarrollos en https://electronicadicto.wordpress.com/ date una vuelta y curiosea un rato...

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Problema con driver y protocolo i2C por software en C18
« Respuesta #5 en: 10 de Enero de 2013, 00:09:46 »
  Por lo que entiendo, las funciones sirven para generar el estado de "respuesta" y "no respuesta".
  Eso debería ser cuando tu master quiera responder o no al dispositivo. Lo extraño también es que debas utilizarlas cuando es el turno del dispositivo de responder o no.

  Quiero decir que, en teoría, no debería estar, por ejemplo, el primer "SWAckI2C()" ya que en ese momento es el dispositivo quien tiene que responder y no el master.

  Tengo unas rutinas de I2C por soft para HiTEch y me comuniqué con memorias y otros dispositivos sin problemas y sólo usaba mis funciones de ACK cuando era el master quien tenía que responder.


  Pregunta al margén, ¿Estás utilizando las resistencias de tipo pull-up de proteus para el bus I2C? No tienen que ser del tipo genérica sino del tipo pull-up sino te puede dar cualquier clase de conflictos el proteus.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado Thulsa Doom

  • PIC24F
  • *****
  • Mensajes: 771
    • https://electronicadicto.wordpress.com/
Re: Problema con driver y protocolo i2C por software en C18
« Respuesta #6 en: 10 de Enero de 2013, 06:50:22 »
 Por lo que entiendo, las funciones sirven para generar el estado de "respuesta" y "no respuesta".
  Eso debería ser cuando tu master quiera responder o no al dispositivo. Lo extraño también es que debas utilizarlas cuando es el turno del dispositivo de responder o no.

  Quiero decir que, en teoría, no debería estar, por ejemplo, el primer "SWAckI2C()" ya que en ese momento es el dispositivo quien tiene que responder y no el master.

  Tengo unas rutinas de I2C por soft para HiTEch y me comuniqué con memorias y otros dispositivos sin problemas y sólo usaba mis funciones de ACK cuando era el master quien tenía que responder.


  Pregunta al margén, ¿Estás utilizando las resistencias de tipo pull-up de proteus para el bus I2C? No tienen que ser del tipo genérica sino del tipo pull-up sino te puede dar cualquier clase de conflictos el proteus.

Pues coincido con usted, es más cuando implemento el i2c por hardware no utilizo los Ack si no los dos del final como muestra la captura del datasheet del fabricante y va perfecto.
Pero si lo intento hacer por software el resultado es nefasto y haga lo que haga el penúltimo Ack lo envío como un NotAck.
cuelgo el código modificado para dejarlo más claro.
Código: [Seleccionar]
/* Funsión que lee el valor de los registros TH y TL en una resolución de 0.50 ºC*/

float read_temp_normal_precision(unsigned char address){  // Returns degrees ºC (0 a 257)


   unsigned char ReadTemp_TH, ReadTemp_TL;

   float ReadTemp;


   //Read Temperature (AAh)

 SWStartI2C();
 SWWriteI2C(0x90 | (address<<1));   //Establecemos la comunicación como escritura
 SWWriteI2C(0xAA);   //Enviamos el comando  
 SWRestartI2C();   //Reseteamos el protocolo, sin esto no funciona la                lectura
 SWWriteI2C(0x91 | (address<<1)); //Establecemos la lectura de registro de temperatura del DS1621
 ReadTemp_TH = SWReadI2C();
 SWAckI2C();       //El Master envía el bit ACK
 ReadTemp_TL = SWGetcI2C();
 SWNotAckI2C();      //El master envía el bit NOACK
 SWStopI2C();

   //Código donde se unen los dos byts en un float  

 ReadTemp = ReadTemp_TH;

     if(ReadTemp_TL == 0b10000000)
      {
       ReadTemp += 0.5;
      }

     return(ReadTemp);  

}

Y si implemento el código tal cual está como en la parte de arriba, el penúltimo Ack lo envía cómo un NotAck y el último lo envía como un Ack debiendo der un NotAck, ósea que lo invierte
Cuelgo una captura de la ventana i2c del proteus, donde se puede ver en el recuadro rojo un ciclo de lectura del dispositivo DS1621
 


es más he implementado esto en un chip físico y tengo el mismo resultado que en el proteus, no sé si será problema de velocidad del bus que al igual va más rápido de lo que soporta, pero claro eso me pasa en simulación tanto como en hardware real, No entiendo nada  :shock:

A su otra pregunta, Si estoy utilizando resistencias de pull-ups, pues he utilizado las propias del chip en el puerto B, y otras como resistencias normales tanto como las de pull-ups del proteus y el resultado es el mismo.

En el montaje por hardware al principio no me funcionaba pero era por culpa de las resistencias, las añadí y se le saco el problema
« Última modificación: 10 de Enero de 2013, 07:00:27 por Thulsa Doom »
Más códigos y desarrollos en https://electronicadicto.wordpress.com/ date una vuelta y curiosea un rato...

Desconectado Thulsa Doom

  • PIC24F
  • *****
  • Mensajes: 771
    • https://electronicadicto.wordpress.com/
Re: Problema con driver y protocolo i2C por software en C18
« Respuesta #7 en: 10 de Enero de 2013, 10:12:32 »
Pues bueno, quiero comunicar que he solucionado el problema, no sé si será de la manera correcta pero funciona perfecto.
explico:
Pues al ver que los dos últimos Ack se comportaban de igual manera, y viendo el código del protocolo, este definía por igual el SWAckI2C con el SWNotAckI2c, decidí forzar el estado del bit creando una nueva rutina.
la nueva rutina la llame swacki2c_prueba y lo que he hecho es cambiar el estado del bit de salida, en la imagen muestro como.



lo que he hecho es sutituir el comando original DATA_HIGH por el DATA_LOW

sustituir la nueva función por la bieja de esta menra:
Código: [Seleccionar]
/* Funsión que lee el valor de los registros TH y TL en una resolución de 0.50 ºC*/

float read_temp_normal_precision(unsigned char address){  // Returns degrees ºC (0 a 257)


   unsigned char ReadTemp_TH, ReadTemp_TL, ReadCounter;

   float ReadTemp;


   //Read Temperature (AAh)

 SWStartI2C();
 SWWriteI2C(0x90 | (address<<1));   //Establecemos la comunicación como escritura
 SWAckI2C();
 SWWriteI2C(0xAA);   //Enviamos el comando 
 SWAckI2C();
 SWRestartI2C();   //Reseteamos el protocolo, sin esto no funciona la                lectura
 SWWriteI2C(0x91 | (address<<1)); //Establecemos la lectura de registro de temperatura del DS1621
 SWAckI2C();
 ReadTemp_TH = SWReadI2C();
 SWAckI2C_prueba();       //El Master envía el bit ACK
 ReadTemp_TL = SWGetcI2C();
 SWNotAckI2C();      //El master envía el bit NOACK
 SWStopI2C();

   //Código donde se unen los dos byts en un float 

 ReadTemp = ReadTemp_TH;

     if(ReadTemp_TL == 0b10000000)
      {
       ReadTemp += 0.5;
      }

     return(ReadTemp); 

}

y el resultado queda tal que así:



Cómo podemos apreciar en la imagen, lo que está en el recuadro rojo es una lectura de la temperatura del DS1621 y lo que está en el recuadro verde es el cambio de estado del bit ACK, antes estaba en NotAck y ahora está en Ack
Más códigos y desarrollos en https://electronicadicto.wordpress.com/ date una vuelta y curiosea un rato...