Rotinas para interface I²C


Continuaremos hoje com o tópico anterior, tendo o todo conceito em vista, devemos avançar para a implementação, serão ao todo seis rotinas simples (i2c_Ini(), i2c_Start(), i2c_RepeatedStart(), i2c_Stop(), i2c_Write(BYTE), i2c_Read(ACKTYPE)) que farão parte de nossa biblioteca i2c, com toda a inicialização, leitura e escrita no dispositivo,  segue abaixo a implementação destas rotinas com as respectivas descrições.

Função: i2c_Ini()
Propósito: Inicializa a configuração dos registradores do modulo I²C
Parâmetros: Nenhum
Descrição: O modulo é habilitado setando o bit I2CEN(I2CCON<15>), então o modulo ira liberar os pinos SDA e SCL, colocando o barramento no modo ocioso. A lógica de funcionamento para mestre e escravo é ativada simultaneamente e irão responder ao software e eventos no  barramento. As funções mestre irão permanecer em estado ocioso até que o software setar um bit de controle que gere um evento mestre. Habilitamos Entrada/Saída do I²C, configuramos a interrupção e ajustamos o baud rate para operar como mestre no barramento.

void i2c_Ini(void)
{
    // Configura os pinos SCL1/SDA1 como open-drain
    //ODCGbits.ODCG2 = 1;
    //ODCGbits.ODCG3 = 1;
   
    // IFS1 - Interrupt Flag Status register 1
    //               _______________________________________________________________
    // Upper Byte   |U2TXIF |U2RXIF |INT2IF | T5IF  | T4IF  | OC4IF | OC3IF |DMA21IF|
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   | IC8IF | IC7IF | AD2IF |INT1IF | CNIF  | ----- |MI2C1IF|SI2C1IF|
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    // MI2C1IF - I2C1 Master events                   Interrupt Flag status bit
    //
    // limpa o flag de interrupcao do I²C1
    IFS1bits.MI2C1IF = 0;
   

    // IPC4 - Interrupt Priority Control register 4
    //               _______________________________________________________________
    // Upper Byte   | ----- |       CNIP<2:0>       | ----- | ----- | ----- | ----- |
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   | ----- |      MI2C1<2:0>       | ----- |      SI2C1<2:0>       |
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    // MI2C1<2:0> - I²C Master Events Interrupt Priority bits
    //          011 = prioridade de interrupcao eh 3
    //
//    IPC4bits.MI2C1IP = 3;

    // IEC1 - Interrupt Enable Control register 1
    //               _______________________________________________________________
    // Upper Byte   |U2TXIE |U2RXIE |INT2IE | T5IE  | T4IE  | OC4IE | OC3IE |DMA2IE |
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   | IC8IE | IC7IE | AD2IE |INT1IE | CNIE  | ----- |MI2C1IE|SI2C1IE|
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    // MI2C1IE - I2C1 Master events                   Interrupt Enable bit
    //
    // habilita a interrupcao mestre do I²C1
//    IEC1bits.MI2C1IE = 1;

    // Setando o baud rate
    //
    // a seguinte equacao eh usada para calcular o valor de recarga
    // do gerador da taxa de comunicacao:
    //
    //            /  Fcy         Fcy    \.
    //  I2CBRG = |  ------ - ----------- | - 1
    //            \  Fscl     1.111.111 /
    //
    // desejamo comunicar a 400kHz, entaum os valores seraoh:
    //
    //  Fcy = 40 MHz
    //  Fscl = 400 kHz
    //
    //            /  40.000.000     40.000.000 \.
    //  I2CBRG = |  ------------ - ------------ | - 1
    //            \   400.000        1.111.111 /
    //
    //  I2CBRG = (100 - 36 ) - 1
    //
    //  I2CBRG = 63
    //
    I2C1BRG = 63;

    //
    // I2C1CON - I²C 1 CONtrol register
    //               _______________________________________________________________
    // Upper Byte   | I2CEN | ----- |I2CSIDL| SCLREL| IPMIEN|  A10M | DISSLW|  SMEN |
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   |  GCEN | STREN | ACKDT | ACKEN | RCEN  |  PEN  | RSEN  |  SEN  |
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    // assegura que estah com o valores zerados
    I2C1CON = 0;

    //  A10M: 10-bit Slave Address bit
    //      0 = I2CxADD eh o endereco escravo de  7-bit
    //
    I2C1CONbits.A10M  = 0;

    //  SCLREL: SCLx Release Control bit
    //      1 = Libera o pulso  SCLx
    //      0 = Mantem pulso baixo do SCLx (esticar pulso)
    //          Se STREN = 0:
    //              Bit eh R/S (ou seja, soh pode escrever '1' para liberar o pulso.
    //              Hardware limpa no inicio da transmissao do escravo.
    //
    //  STREN: SCLx Clock Stretch Enable bit
    //      Usado em conjuncao com o bit SCLREL.
    //      1 = Habilita o software ou esticamento do pulso de recepcao
    //      0 = Desabilita o software ou esticamento do pulso de recepcao
    //
    // libera a linha de pulso
    I2C1CONbits.SCLREL = 1;

    // desabilita o o I²C para funcionar como escravo
    I2C1ADD = 0;
    I2C1MSK = 0;


    //  I2CEN: I2Cx Enable bit
    //      1 = Habilita o modulo I²Cx e configura os pinos SDAx e SCLx como porta seriais
    //
    I2C1CONbits.I2CEN = 1;
    IFS1bits.MI2C1IF = 0;
}           



Função: i2c_Start()
Propósito:  Condição de inicio para usar o protocolo do barramento I²C
Parâmetros: Nenhum
Descrição: Após o barramento estar em estado ocioso, uma transição de alto para baixo da linha SDA, enquanto o relógio SCL estiver alto, determina uma condição de inicio. Todos os dados transferidos devem começar com a condição de inicio.

void i2c_Start(void)
{
    //
    // I2C1CON - I²C 1 CONtrol register
    //               _______________________________________________________________
    // Upper Byte   | I2CEN | ----- |I2CSIDL| SCLREL| IPMIEN|  A10M | DISSLW|  SMEN |
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   |  GCEN | STREN | ACKDT | ACKEN | RCEN  |  PEN  | RSEN  |  SEN  |
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    //  SEN: Start Condition Enable bit (quando o I²C opera como mestre)
    //      1 = Inicia condicao de inicio nos pinos SDAx e SCLx.
    //      Hardware limpa no final da sequencia de inicio do mestre
    //      0 = Condicao de inicio nao estah em progresso
    //
    // Start Condition
    I2C1CONbits.SEN = 1;

    // IFS1 - Interrupt Flag Status register 1
    //               _______________________________________________________________
    // Upper Byte   |U2TXIF |U2RXIF |INT2IF | T5IF  | T4IF  | OC4IF | OC3IF |DMA21IF|
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   | IC8IF | IC7IF | AD2IF |INT1IF | CNIF  | ----- |MI2C1IF|SI2C1IF|
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    // MI2C1IF - I2C1 Master events                   Interrupt Flag status bit
    //
    // espera pelo fim do START
    while (!IFS1bits.MI2C1IF);
   
    // limpa o flag
    IFS1bits.MI2C1IF = 0;
}


Função: i2c_RepeatedStart()
Propósito:  Condição de inicio repetido para usar o protocolo do barramento I²C
Parâmetros: Nenhum
Descrição: O Modulo joga o pino SCL para baixo. Quando o modulo amostra o pino SCL baixo, irá liberar o pino SDA pela contagem de um baud rate(Tbrg). Quando o gerador de baud rate esgota o tempo, se a amostra do pino SDA for alta, o modulo libera o pino SCL. Quando o modulo amostrar o pino SCL alto, o gerador de baud rate recarrega e inicia a contagem. Os pinos SDA e SCL devem ser amostrados alto por um Tbgr. Esta ação é seguida pela declaração do pino SDA para baixo por um Tbgr enquanto o pino SCL estiver alto.

void i2c_RepeatedStart(void)
{
    //
    // I2C1CON - I²C 1 CONtrol register
    //               _______________________________________________________________
    // Upper Byte   | I2CEN | ----- |I2CSIDL| SCLREL| IPMIEN|  A10M | DISSLW|  SMEN |
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   |  GCEN | STREN | ACKDT | ACKEN | RCEN  |  PEN  | RSEN  |  SEN  |
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    //  RSEN: Repeated Start Condition Enable bit (quando o I²C opera como mestre)
    //      1 = Inicia condicao de inicio repetido nos pinos SDAx e SCLx.
    //       Hardware limpa no final da sequencia de inicio repetido do mestre
    //      0 = Condicao de inicio repetido nao estah em progresso
    //
    // Start Condition
    I2C1CONbits.RSEN = 1;

    // IFS1 - Interrupt Flag Status register 1
    //               _______________________________________________________________
    // Upper Byte   |U2TXIF |U2RXIF |INT2IF | T5IF  | T4IF  | OC4IF | OC3IF |DMA21IF|
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   | IC8IF | IC7IF | AD2IF |INT1IF | CNIF  | ----- |MI2C1IF|SI2C1IF|
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    // MI2C1IF - I2C1 Master events                   Interrupt Flag status bit
    //
    // espera pelo fim do REPEATED START
    while (!IFS1bits.MI2C1IF);
   
    // limpa o flag
    IFS1bits.MI2C1IF = 0;
}


Função: i2c_Stop()
Propósito: Condição de parada ao termino dos dados enviados no barramento
Parâmetros: Nenhum
Descrição: Uma transição de baixo para alto da linha SDA enquanto a linha de relógio SCL estiver alta determina uma condição de parada. Toda a transferência de dados deve terminar com a condição de parada.

void i2c_Stop(void)
{
    //
    // I2C1CON - I²C 1 CONtrol register
    //               _______________________________________________________________
    // Upper Byte   | I2CEN | ----- |I2CSIDL| SCLREL| IPMIEN|  A10M | DISSLW|  SMEN |
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   |  GCEN | STREN | ACKDT | ACKEN | RCEN  |  PEN  | RSEN  |  SEN  |
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    //
    //  PEN: Stop Condition Enable bit (quando o I²C opera como mestre)
    //      1 = Inicia a condicao de parada nos pinos SDAx e SCLx.
    //          Hardware limpa no final da sequencia de parada do mestre
    //      0 = Condicao de parada nao estah em progresso
    //
    //
   
    // Stop Condition
    I2C1CONbits.PEN = 1;
   
    // espera pelo fim do STOP
    while (!IFS1bits.MI2C1IF);
   
    // limpa o flag
    IFS1bits.MI2C1IF = 0;
}


Função: i2c_Write(BYTE)
Propósito:  Enviar um byte pelo barramento I²C
Parâmetros: btData - Informação a ser transmitida pela I²C
Retorno: 1 - Recebeu confirmação do dispositivo (ACK), 0 - O dispositivo escravo não respondeu.
Descrição: Para cada byte de dado transmitido pelo mestre, o escravo deve confirmar cada um com o ACK.

BOOL i2c_Write(BYTE btData)
{
    // IWCOL: Write Collision Detect bit
    //1 = Tentativa de escrever no registrador I2CxTRN falhou pq o modulo I²C estava ocupado.
    //0 = Sem colisao
    //Hardware setado por uma escrita em I2CxTRN enquanto ocupado(limpo por software).
    //
    //while (I2C1STATbits.IWCOL);
   
    // envia o dado
    I2C1TRN = btData;

    // espera pelo fim do Operacao de escrita
    while (!IFS1bits.MI2C1IF);
   
    // limpa o flag
    IFS1bits.MI2C1IF = 0;

    // I2C1STAT - I²C1 STATus register
    //               _______________________________________________________________
    // Upper Byte   |ACKSTAT| TRSTAT| ----- | ----- | ----- |  BCL  | GCSTAT| ADD10 |
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   | IWCOL | I2COV |  D_A  |   P   |   S   |  R_W  |  RBF  |  TBF  |
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
    //  ACKSTAT: Acknowledge Status bit
    //      (quando o I²C opera como mestre, aplicavel durante a transmissao do mestre)
    //      1 = recebido do escravo um NACK
    //      0 = recebido do escravo um ACK
    //       Hardware setado ou limpo ao fim da confirmacao do escravo.
    //
    // se o ACK nao retornou, indica erro
    if (I2C1STATbits.ACKSTAT)
        return FALSE;
    else
        return TRUE;    
}


Função: i2c_Read(BYTE)
Propósito: Ler o dado no barramento I²C passado pelo dispositivo escravo.
Parâmetros: ackType - Tipo de confirmação a ser enviado(ACK ou NACK).
Retorno: O byte lido do dispositivo escravo
Descrição: Para cada byte que o escravo transmitir para o mestre, deve ser confirmado com ACK, o ultimo byte transmitido pelo escravo, o mestre deve enviar um NACK, para encerrar a transmissão.

BYTE i2c_Read(ACKTYPE ackType)
{
    //
    // I2C1CON - I²C 1 CONtrol register
    //               _______________________________________________________________
    // Upper Byte   | I2CEN | ----- |I2CSIDL| SCLREL| IPMIEN|  A10M | DISSLW|  SMEN |
    //              |__15___|__14___|__13___|__12___|__11___|__10___|___9___|___8___|
    //               _______________________________________________________________
    // Lower Byte   |  GCEN | STREN | ACKDT | ACKEN | RCEN  |  PEN  | RSEN  |  SEN  |
    //              |__ 7___|___6___|___5___|___4___|___3___|___2___|___1___|___0___|
    //
   
    BYTE btInfo;
   
    //RCEN: Receive Enable bit (quando o I²C opera como mestre)
    //1 = Habilita a recepcao do I²C. Hardware limpa ao final do oitavo bit do byte recebido
    I2C1CONbits.RCEN = 1;

    // espera pela indicacao de dado recebido
    while (!IFS1bits.MI2C1IF);
   
    // limpa o flag
    IFS1bits.MI2C1IF = 0;

    // recebe o dado
    btInfo = I2C1RCV;

    //  ACKDT: Acknowledge Data bit (quando o I²C opera como mestre, aplicavel durante a recepcao)
    //      Valor que sera transmitido quando o software inciar uma sequencia de confirmacao.
    //      1 = Envia NACK durante a confirmacao
    //      0 = Envia  ACK durante a confirmacao
    //
    // seleciona a confirmacao passada para a funcao (ACK ou NACK)
    I2C1CONbits.ACKDT = ackType;     

    //ACKEN: Acknowledge Sequence Enable bit
    //1 = Incia a sequencia de confirmacao nos pinos SDAx e SCLx e transmite o bit de dados ACKDT.
    //   Hardware limpa ao final da sequencia de confirmacao do mestre.
    //
    // envia a confirmacao escolhida
    I2C1CONbits.ACKEN = 1;

    // espera pela transmissao da confirmacao
    while (!IFS1bits.MI2C1IF);
   
    // limpa o flag
    IFS1bits.MI2C1IF = 0;


    return btInfo;
}

               Com isso finalizamos a rotinas necessárias para comunicar com um dispositivo I²C, lembre-se de incluir no arquivo de cabeçalho do projeto a seguinte declaração.

typedef enum tagACKTYPE
        {
            ACK,
            NACK
        } ACKTYPE;


void i2c_Ini();
void i2c_Start();
void i2c_RepeatedStart();
void i2c_Stop();
BOOL i2c_Write(BYTE);
BYTE i2c_Read(ACKTYPE);

               E na próxima parte iremos comunicar o microcontrolador com outro dispositivo pela I²C.

Um comentário:

  1. é né publicou um artigo científico?
    inventou mentiras sobre mim em f2
    você pediu a professora de f2 para abrir mais vagas para você
    e você ainda quer prejudicar quem quer aprender a matéria
    foi hipócrita em gnosia 2
    criticou tanto quem faltou uma aula e faltou todas as aulas do último bloco de gnosia 2
    deu uma de malandro em tec1
    pediu a monitora a rayssa arrais para fazer a prova prática com a outra turma
    só para ter mais tempo para estudar
    colocou em f3 e agora publicou um artigo científico
    aquele laboratório de fitoquimica e farmacognosia deve ser uma porcaria para aceitar alguém como você
    a Suzana deve estar muito desesperada para aceitar alguém como você como aluna de IC
    também o fitofar aceitou a Ana Beatriz de Lima como aluna de IC
    não dá para esperar muita coisa de um laboratório
    que aceita a Ana Beatriz de Lima como aluna de IC
    é por isso que eu queria ser expulso da faculdade
    pelo menos se eu fosse expulso da faculdade
    eu não precisaria ver alguém desonesta com você se dando bem na faculdade
    enquanto eu que sou tão dedicado a faculdade nunca tive uma oportunidade de fazer ic na área de quimica
    agora você está trabalhando na merck
    será que o pessoal da merck sabe quem você é de verdade?
    também um lugar que aceitou a Gabriela Santana Andrade como funcionaria
    não deve ser um bom lugar para trabalhar
    você é igualzinha a Gabriela Santana Andrade
    vocês duas não prestam
    o pior é que você é bonita
    o que você tem de bonita
    você tem de malvada

    ResponderExcluir