Ejemplos IIC QE128QRUG

De Wikitronica
Saltar a: navegación, buscar

Los ejemplos aquí mostrados están disponibles en el sitio web de Freescale.

Proyecto del IIC: Configuración de Maestro.

En esta aplicación, dos pines son usados para trabajar con el protocolo del IIC. Uno de ellos es el PTH7, el cual es el pin de datos del protocolo de IIC. El segundo es el PTH6, el pin para el reloj.

Las funciones del IIC MASTER PROYECT son las siguientes:

  • main: Es un ciclo infinito en el cual se manda un byte, el cual funciona como contador, y espera que ocurra la interrupción del IIC.
  • MCU_init: Se deshabilita el “watchdog” de la inicialización del MCU y se habilita el módulo del reloj del IIC.
  • GPIO_init: Se configuran los puertos PTE como las salidas, y los puertos PTH7 y PTH6 como entrada.
  • IIC_init: Se configura el módulo de IIC.
  • IIC_ISR: Configuración de la rutina de interrupción del IIC.
  • Delay: Retardos.

La Configuración del "Maestro", configura el MCU para trabajar como “maestro” y usa el protocolo del IIC para mandar un byte, que funciona como contador, al esclavo. La cuenta del contador se muestra en los ocho LEDS del microcontrolador.

La siguiente parte del código corresponde a la inicialización del MCU. Estas instrucciones deshabilitan al “watchdog”, habilitan la opción de “reset” y el Background Pin. El System Option Register 1 (SOPT1) es usado para la inicialización del MCU. El SCGC1 y el SCGC2 son registros usados para ahorrar energía, aquí el reloj de los puertos periféricos puede desactivarse. En este ejemplo, solo el reloj del módulo del IIC está activo y los “relojes” de otros puertos periféricos están desactivados.

void MCU_init(void){ 
 SOPT1 = 0x23; // Watchdog deshabilitado. Stop Mode habilitado. Background Pin habilitado.
               // Habilitado el pin de "reset".
 SCGC1 = 0x08; // Habilitado el pin del reloj del módulo de IIC.
}

Las siguientes líneas de código corresponden a la configuración del General Purpose Input/Output. Está parte configura las direcciones para los puertos PTE y PTH. Ocho LEDs están conectados al puerto PTE, por lo que este esta configurado como la salida. El puerto PTH6 y el PTH7 están configurados como salidas también. Estos dos pines corresponden al Serial Clock (SCL) y a la Serial Data (SDA).

void GPIO_Init(void) {
 PTHPE = 0xC0; // Habilita Pull ups en los pines PTH7 y PTH6.
 PTEDD = 0xFF; // Configura los pines PTE como salidas
 PTED = 0x00; // Coloca 0's en los puertos PTE
}

Lo siguiente corresponde a La inicialización del IIC usando el QE MCU. Aquí Se configura el modulo para que trabaje como “maestro”. El MCU trabaja con una velocidad de transmisión de 4 MHz, La tasa de baudios del IIC puede ser calculada de La siguiente manera:

IIC tasa de baudios = velocidad de transmisión (Hz) / (mul * Divisor de SCL); IIC tasa de baudios = 4000000 / (1 * 32); IIC tasa de baudios = 125000;

La tasa de baudios de este ejemplo es 125000 porque el módulo ICS no está configurado y el MCU trabaja con su velocidad por defecto (4MHz).

void IIC_Init (void) {
 IIC2F = 0x09; // Multiplica por un factor de 1. Divisor SCL de 32.
 IIC2C1 = 0xC0; // Habilita el módulo de IIC y las interrupciones.
}

La siguiente es la función de retardos, usada antes de que el MCU comience a mandar el siguiente byte (luego de enviar el contador) al esclavo. Esta función sólo se usa para observar los cambios que ocurren en los LEDs.

void Delay (int16 c) {
 int16 i = 0;
 for (i; i<=c; i++) {
 }
}

Ahora se presenta la función principal. Se incluyen las funciones antes mencionadas y se habilitan todas las interrupciones. En el ciclo infinito, el IIC envía un byte contador al esclavo. La función de retardo es llamada entre cada transferencia de bytes.

void main(void) {
 MCU_Init(); // Función que inicializa el MCU.
 GPIO_Init(); // Función que inicializa los puertos del MCU.
 IIC_Init(); // Función que inicializa el módulo de IIC.
 EnableInterrupts; // Habilita las interrupciones.
 for(;;) {
   Delay(60000);
   PTED = counter;
   counter++;
   if (PTHD_PTHD7 == 0) {
     while (PTHD_PTHD7 == 0); // Espera mientras el pin es bajo.
     while (IIC2C1_MST == 1); // Espera mientras el IIC esta detenido.
     MasterTransmit(1,1); // Inicializa la transmisión.
   }
   else {
   }
   while (IIC2C1_MST == 1); // Espera mientras el IIC está detenido.
   Master_Receive();
 }  // ciclo infinito.
    // Asegurarse de nunca salir de esta función.
} 

Las siguientes funciones son usadas cuando el IIC es configurado como “maestro”:

void Master_Read_and_Store(void) {
 if (rec_count == num_to_rec) {
  last_byte_to_rec = 2;
 }
 IIC_Rec_Data[rec_count] = IIC2D;
 rec_count++;
}
void Master_Transmit(uint8 a, uint8 b) {
// Esta función inicia la transmisión. 
 last_byte = 0; // Inicializa.
 count = 0;
 bytes_to_trans = a; // Selecciona el número de bytes a transferir.
 num_to_rec = b;
 IIC2C1_TX = 1; // Establece un bit TX para el ciclo llave.
 IIC2C1_MST = 1; // Establece un bit Maestro para generar la señal de "start".
 IIC2D = 0xAA; // Envia la llave de datos LSB, la cual es R o W para el esclavo.
} 
void Master_Receive() {
 rec_count = 0;
 last_byte_to_rec = 0;
 last_byte = 0;
 count = 0;
 num_to_rec = 0;
 IIC2C1_TXAK = 0;
 IIC2C1_TX = 1; // Set TX bit for Address cycle
 IIC2C1_MST = 1; // Set Master Bit to generate a Start
 add_cycle = 1; // This variable sets up a master rec in the ISR
 IIC2D = 0xAB; // Send Address data LSB is R or W for Slave
} 

La siguiente, es la rutina del IIC. Estas rutinas manejan al maestro y al esclavo en ambos modos, como transmisor y receptor. Si el dispositivo está funcionando como maestro, basta con seguir la lógica del maestro. En cambio, si el dispositivo está trabajando como esclavo, basta con que siga la lógica del esclavo.

interrupt VectorNumber_iicx void IIC_ISR(void) {
    // IIC interrupt vector number = 17 (S08)
    // IIC interrupt vector number = 79 (V1)
  IIC2S_IICIF = 1; // Clear Interrupt Flag
  if (IIC2C1_MST){ // Master or Slave?
/***************************** Master **********************************/
    if (IIC2C1_TX) { // Transmit or Receive?
/**************************** Transmit *********************************/
     if (last_byte) { // Is the Last Byte?
      IIC2C1_MST = 0; // Generate a Stop
     }
      else if (last_byte != 1) {
       if (IIC2S_RXAK) { // Check for ACK
        IIC2C1_MST = 0; // No ACk Generate a Stop
       }
       else if (!IIC2S_RXAK) {
        if (add_cycle) { // Is Address Cycle finished? Master done addressing Slave?
         add_cycle = 0; // Clear Add cycle
         IIC2C1_TX = 0; // Switch to RX mode
         IIC2D; // Dummy read from Data Register
        }
        else if (add_cycle !=1) {
         IIC2D = counter; // Transmit Data
         count++;
         if (count == bytes_to_trans) {
          last_byte = 1;
         }
        }
       }
      }
    }
    else {
/**************************** Receive **********************************/
     if (last_byte_to_rec == 1) {
      IIC2C1_MST = 0; // Last byte to be read?
      Master_Read_and_Store();
     }
     else if (last_byte_to_rec == 2){ // Second to last byte to be read?
      last_byte_to_rec = 1;
      IIC2C1_TXAK = 1; // This sets up a NACK
      Master_Read_and_Store();
     }
     else {
      Master_Read_and_Store();
     }
    }
  }
  else {
/***************************** Slave ***********************************/
   if (IIC2S_ARBL) {
    IIC2S_ARBL = 1;
    if (IIC2S_IAAS) { // Chequea las coincidencias en la llave.
     count = 0;
     SRW();
    }
   }
   else {
    if (IIC2S_IAAS) { // No se pierde el arbitraje.
    count = 0;
    SRW();
    }
    else {
     if (IIC2C1_TX) { // Chequa el rec ACK
      if (!IIC2S_RXAK) { // ACK recibido.
       IIC2D = IIC_TX_Data[count];
       count++;
      }
      else {
       IIC2C1_TX = 0;
       IIC2D;
      }
     }
     else {
      Slave_Read_and_Store();
     }
    }
   }
  }
} 

Esta función es utilizada para inicializar el proceso de transferencia de datos. Se inicializan algunas variables. Se establece el bit maestro (MST) y se genera una señal de inicio, de modo que el proceso de comunicación comience a partir de ese momento. Luego se envía la llave del esclavo.

void Master_Transmit(uint8 a, uint8 b) {
  last_byte = 0;
  count = 0;
  bytes_to_trans = a; // Número de bytes a transferir.
  num_to_rec = b; // Numero de bytes a almacenar.
  IIC2C1_TX = 1; // Set TX bit for Address cycle
  IIC2C1_MST = 1; // Set Master Bit to generate a Start
  IIC2D = 0xAA; // Send Address data LSB is R or W for Slave
}

Esta función es usada para leer la data recibida desde el dispositivo esclavo y para almacenar dicha información en el arreglo llamado IIC_Rec_Data array. En este ejemplo sólo se usa el primer byte.

void Master_Read_and_Store(void) {
  if (rec_count == num_to_rec) {
    last_byte_to_rec = 2;
  }
  IIC_Rec_Data[rec_count] = IIC2D;
  rec_count++;
}

Esta función es usada para inicializar el proceso de recepción y almacenamiento en el MCU. Se inicializan algunas variables y se establece el bit MST para generar la señal de entrada.

void Master_Receive() {
  rec_count = 0;
  last_byte_to_rec = 0;
  last_byte = 0;
  count = 0;
  num_to_rec = 0;
  IIC2C1_TXAK =0;
  IIC2C1_TX = 1; // Establece un bit TX  para la llave del ciclo.
  IIC2C1_MST = 1; // Establece un bit Maestro para generar el comienzo.
  add_cycle = 1; // Esta variable establece un rec Maestro en el ISR
  IIC2D = 0xAB; // Envía la llave de datos LSB, R o W para el esclavo.
} 



Proyecto del IIC: Configuración de Esclavo.

Este proyecto es similar al proyecto del IIC Maestro. Este ejemplo muestra como configurar el MCU como esclavo. El ISR utilizado es el mismo, al igual que las funciones utilizadas. Para información mas detallada de los códigos visite la pagina web www.freescale.com

Esta función es usada cuando el dispositivo esta trabajando como esclavo y es necesario saber si el dispositivo esta realizando un “dummy read” o escribe datos al maestro.

El “dummy read” no es una verdadera lectura del bus I2C, pero es una lectura del registro IICD en el bloque del IIC. No será visto en el bus o en cualquier especificación del I2C porque es interna al diseño del bloque de hardware I2C.


void SRW(void) {
  if (IIC2S_SRW) {    // Chequea por Slave Rec o si transmite
    IIC2C1_TX = 1;      // Configurar el bit Tx para tramsmitir
    IIC2D = IIC_TX_Data[count];
    count++;
  }
  else {

    IIC2C1_TX = 0;
    IIC2D; // Dummy read

  }
} 

Esta función lee datos del buffer del IIC y lo guarda en el arreglo IIC_Rec_Data. En este ejemplo solo se utiliza el primer byte de este arreglo.

void Slave_Read_and_Store(void) {
  if (rec_count == num_to_rec) {
    last_byte_to_rec = 2;
  }
  IIC_Rec_Data[rec_count] = IIC2D;
  rec_count++;
  if (rec_count == num_to_rec) {
    rec_count = 0;
  }
}

Contributors

DanielaVa