Ir ao conteúdo
  • Cadastre-se
Robson Manzoli Dos Santos

PIC 16f15376, mplab xpress, comunicação I2C

Posts recomendados

Boa tarde.

Estou começando a utilizar meu pic 16f15376 (ganhei em uma promoção da microchip há muito tempo). Eles criaram o módulo de programação "em nuvem" e estou tentando aprender a utilizar cada periférico do PIC. 

 

Tenho um display SSD1306 128x32 e mesmo sabendo qual o endereço, quis fazer uma função genérica para que o PIC encontre o endereço correto.

Outro detalhe é que estou tentando utilizar a própria biblioteca i2c gerada.

Mas, infelizmente não tive sucesso.

Disponibilizei todo o código que utilizo, caso alguém possa ajudar, agradeço. 

Abaixo, encontra-se uma tela com o resultado do programa. Ele executa até a linha de printf e quando manda a função i2c1write....trava.

resultado.thumb.jpg.504a27703d148fd467752ee86c39d8bf.jpg


 

mcc_generated_files.rar

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não vi o código. Estou economizando cliques do mouse. Publique o código se achar que deve.

Estude melhor a interface i2c e sua função i2cwrite. Talvez ela espere algum retorno que não ocorre. Verifique o hw.

 

15 horas atrás, Robson Manzoli Dos Santos disse:

há muito tempo

de fato pic é coisa do passado. Cogite avr ou st . Eu (eu) to na onda do esp32

 

E não queime a etapa do pisca led.

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Obrigado Isadora. Eu até quero evoluir para estes dispositivos novos, mas como eu ganhei esse pic, gostaria de tentar aprender a usá-lo. 

Eu tentei muitas vezes entender a função i2cwrite, mas como não consegui vim pedir ajuda.

O programa principal está aqui:

 

#include "mcc_generated_files/mcc.h"

#define botao   botao_PORT
 

void testadress(void)                          //função de busca de endereço

 

{   int adress=0, t=0;
char x;
    I2C1_MESSAGE_STATUS status;
    for (adress=0; adress<=0xFF ; adress++)
    {   t=0;
         printf ("Endereço: %d \n\r",adress);
        I2C1_MasterWrite(&x, 1, adress, &status);
            while(status == I2C1_MESSAGE_PENDING);
            {   if (t ==30)
               { t=0;
                 break;
               }
               t++;
            }   
        if (status == I2C1_MESSAGE_COMPLETE)
        {   printf ("Endereço: %d \n",adress);
            break;
        }
        if (adress == 0xFF )
            printf ("erro de endereço! \n\r");
    }
    return;
}

 

void main(void)
{
    // initialize the device
    SYSTEM_Initialize();

    
    while (1)
    {
        //EUSART Communication line configured in the MCC window.
        if (botao == 0)
         printf("Hello from MPLAB Xpress!\n\r"); //The printf command uses the STDIO library //to send strings via the EUASRT communication line. 
        testadress();
        
    }
}

 

//Essa é a função que o mplab fornece para usar o i2c 

 

void I2C1_MasterWrite(
                                uint8_t *pdata,
                                uint8_t length,
                                uint16_t address,
                                I2C1_MESSAGE_STATUS *pflag)
{
    static I2C1_TRANSACTION_REQUEST_BLOCK   trBlock;

    // check if there is space in the queue
    if (i2c1_object.trStatus.s.full != true)
    {
        I2C1_MasterWriteTRBBuild(&trBlock, pdata, length, address);
        I2C1_MasterTRBInsert(1, &trBlock, pflag);
    }
    else
    {
        *pflag = I2C1_MESSAGE_FAIL;
    }

}

 

 

// A declaração das estruturas criadas estão em outro arquivo....por isso mandei o programa completo.

 

Compartilhar este post


Link para o post
Compartilhar em outros sites
7 minutos atrás, Robson Manzoli Dos Santos disse:

  while(status == I2C1_MESSAGE_PENDING); //<--
            {   if (t ==30)
               { t=0;
                 break;
               }
               t++;
            }   

Numa análise superficial percebi o detalhe do ";". Tente removê-lo, observe o que mudou, entenda o porquê que a solução vem a caminho.

Você vai ter que analisar também seu hw bem como o datasheet dos dispositivos envolvidos.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Obrigado.

 

Retirei o ";" e surtiu o seguinte resultado.

Ele imprime todos os 256 endereços que estou escaneando. 

E fica nesse loop. Parece que a função i2cwrite não escreve na porta correta.
Vou reconferir o hardware e retorno.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom dia. Reconferi as ligações e repassei o passo a passo das funções.

Conectei o osciloscópio nas portas setadas com SCL e SDA e deixei a função de escrever byte dentro do loop.

Infelizmente, o osciloscópio não pegou nenhuma alteração (como havia pego no protocolo SPI que testei na outra vez).

Em anexo tem uma foto do hardware e da configuração das pinagens. 

Tentei debugar o programa, pois no teste que Isadora me indicou a fazer, simplesmente o programa passava direto pela função printf  (&adress)...até que o adress igualasse a 0xFF e depois retornava para o início do "while" principal. Enquanto isso, nas portas referentes ao SCL e SDA, não ouve nenhuma alteração.

 

Desde já agradeço a atenção. E desculpe-me se a dúvida/erro for besta...mas é que saturei as ideias de tanto fazer essas malditas funções predefinidas funcionarem (como funcionou o SPI).

 

20191015_085224.jpg

Compartilhar este post


Link para o post
Compartilhar em outros sites

Vejamos...

Sua função

Em 09/10/2019 às 11:39, Robson Manzoli Dos Santos disse:

SYSTEM_Initialize();

contempla também a inicialização da interface i2c? Os pinos RB0 e RB1 são os compartilhados pela i2c?

27 minutos atrás, Robson Manzoli Dos Santos disse:

o osciloscópio não pegou nenhuma alteração

Defina melhor "alteração". Dados e pulso de clock presentes?

O endereço "físico" do seu dispositivo está sendo coerente com o dado da função? Você sabe qual dado é este ou do que estou falando?... possivelmente o &address ... então varre tudo mesmo...Veja no seu dispositivo se ele é físico ou fixo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

void SYSTEM_Initialize(void)
{
    PMD_Initialize();
    PIN_MANAGER_Initialize();
    OSCILLATOR_Initialize();
    I2C1_Initialize();
    EUSART1_Initialize();
}

 

void I2C1_Initialize(void)
{
    i2c1_object.pTrHead = i2c1_tr_queue;
    i2c1_object.pTrTail = i2c1_tr_queue;
    i2c1_object.trStatus.s.empty = true;
    i2c1_object.trStatus.s.full = false;

    i2c1_object.i2cErrors = 0;

    // SMP High Speed; CKE disabled; 
    SSP1STAT = 0x00;
    // SSPEN enabled; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD_I2C; 
    SSP1CON1 = 0x28;
    // SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 100ns; AHEN disabled; 
    SSP1CON3 = 0x00;
    // SSPADD 3; 
    SSP1ADD = 0x03;
    
    // clear the interrupt flags
    PIR3bits.SSP1IF = 0;
    PIR3bits.BCL1IF = 0;
    
    // enable the interrupts
    PIE3bits.SSP1IE = 1;
    PIE3bits.BCL1IE = 1;
    
}
 

void PIN_MANAGER_Initialize(void)
{
    /**
    LATx registers
    */
    LATE = 0x00;
    LATD = 0x00;
    LATA = 0x00;
    LATB = 0x00;
    LATC = 0x00;

    /**
    TRISx registers
    */
    TRISE = 0x0F;
    TRISA = 0xFF;
    TRISB = 0xBF;
    TRISC = 0xFF;
    TRISD = 0xFF;

    /**
    ANSELx registers
    */
    ANSELD = 0xFF;
    ANSELC = 0xFF;
    ANSELB = 0x7C;
    ANSELE = 0x07;
    ANSELA = 0xEF;

    /**
    WPUx registers
    */
    WPUD = 0x00;
    WPUE = 0x00;
    WPUB = 0x03;
    WPUA = 0x10;
    WPUC = 0x00;

    /**
    ODx registers
    */
    ODCONE = 0x00;
    ODCONA = 0x00;
    ODCONB = 0x00;
    ODCONC = 0x00;
    ODCOND = 0x00;

    /**
    SLRCONx registers
    */
    SLRCONA = 0xFF;
    SLRCONB = 0xFF;
    SLRCONC = 0xFF;
    SLRCOND = 0xFF;
    SLRCONE = 0x07;

    /**
    INLVLx registers
    */
    INLVLA = 0xFF;
    INLVLB = 0xFF;
    INLVLC = 0xFF;
    INLVLD = 0xFF;
    INLVLE = 0x0F;

   
    
    
    SSP1CLKPPS = 0x08;   //RB0->MSSP1:SCL1;    
    RB1PPS = 0x16;   //RB1->MSSP1:SDA1;    
    RB6PPS = 0x0F;   //RB6->EUSART1:TX1;    
    RB0PPS = 0x15;   //RB0->MSSP1:SCL1;    
    SSP1DATPPS = 0x09;   //RB1->MSSP1:SDA1;    
    RX1DTPPS = 0x0F;   //RB7->EUSART1:RX1;    
}

 

Seria no "void PIN_MANAGER_Initialize(void)" a configuração do RB0 e RB1. 

 

"Alteração" seria mudança. Como eu envio várias vezes a função i2c1_write, eu imaginava que as saídas responsáveis pelo SCL e SDA alterariam com os envios de bytes.

 

Essa última dica, não compreendi muito bem. O endereço físico do meu dispositivo display, segundo o datasheet, seria 0x3C. Porém, eu quis fazer uma função genérica que ficasse buscando no barramento o endereço correto (caso eu encontrasse outro dispositivo que comunique usando i2c) e para testar a função i2c1_write. 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites
1 hora atrás, Robson Manzoli Dos Santos disse:

Seria no "void PIN_MANAGER_Initialize(void)" a configuração do RB0 e RB1. 

Se isso for uma afirmação é porque você já destrinchou e verificou né? E claro tais pinos são i2c né? Por acaso não está faltando pullups?

 

1 hora atrás, Robson Manzoli Dos Santos disse:

"Alteração" seria mudança

Ainda obscuro. Defina melhor "mudança". Fica fixo no nível ou não varia o dado - padrão de pulso fica igual independente do byte transmitido.

 

1 hora atrás, Robson Manzoli Dos Santos disse:

as saídas responsáveis pelo SCL e SDA alterariam com os envios de bytes

O scl é o mesmo: quadradinho. Já o sda cada byte tem o seu.

Introduction-to-I2C-Data-Transmission-Di

 

1 hora atrás, Robson Manzoli Dos Santos disse:

Essa última dica, não compreendi muito bem. O endereço físico do meu dispositivo display, segundo o datasheet, seria 0x3C. Porém, eu quis fazer uma função genérica que ficasse buscando no barramento o endereço correto (caso eu encontrasse outro dispositivo que comunique usando i2c) e para testar a função i2c1_write. 

caminho certo e aparentemente entendeu sim. Faça então o envio apenas do 0x3c váaaárias vezes. Em alguma o mc deve achar seu periférico: ele devolve o ack.

 

Me lembrei... certa feita pra memória 24c04 tive que enviar o i2cstart() e i2crepstart() - é apenas alguma condição nas linhas scl e sda - algumas vezes pro mc achar ela no barramento. Portanto verifique se seu dispositivo precisa desta "chacoalhada" pra ele devolver o sinal ack (baixa a linha sda) depois de receber o endereço

Compartilhar este post


Link para o post
Compartilhar em outros sites
1 hora atrás, Isadora Ferraz disse:

Se isso for uma afirmação é porque você já destrinchou e verificou né? E claro tais pinos são i2c né? Por acaso não está faltando pullups?

 

É, rsrs... eu vasculhei muito essas funções de inicialização, mas não encontrei erros. Eu coloquei resistores de pull-up e mesmo assim, dentro do programa eu habilitei os pull-ups do próprio microchip. 

 

1 hora atrás, Isadora Ferraz disse:

Ainda obscuro. Defina melhor "mudança". Fica fixo no nível ou não varia o dado - padrão de pulso fica igual independente do byte transmitido.

 

fica fixo no nível, fica igual independente do byte transmitindo (se é que ele ta transmitindo rsrs).

 

1 hora atrás, Isadora Ferraz disse:

caminho certo e aparentemente entendeu sim. Faça então o envio apenas do 0x3c váaaárias vezes. Em alguma o mc deve achar seu periférico: ele devolve o ack.

 

Me lembrei... certa feita pra memória 24c04 tive que enviar o i2cstart() e i2crepstart() - é apenas alguma condição nas linhas scl e sda - algumas vezes pro mc achar ela no barramento. Portanto verifique se seu dispositivo precisa desta "chacoalhada" pra ele devolver o sinal ack (baixa a linha sda) depois de receber o endereço

 

Já tentei só enviar o 0x3C, enviei qualquer lixo só para ver no osciloscópio as ondas do SCL e SDA, e mesmo assim ficou tudo inalterado. 

Eu vou olhar o datasheet do pic de novo....mas acredito que não precisaria dar a "chacoalhada" porque quando eu crio os periféricos, ele já fornece as funções pra ler e escrever.

Se possível, abre o meu projeto no próprio https://mplabxpress.microchip.com/mplabcloud/ide 

Aí você verá todas as funções amarradas e talvez enxergue algo que eu não tenha relatado

Compartilhar este post


Link para o post
Compartilhar em outros sites
55 minutos atrás, Robson Manzoli Dos Santos disse:

fica igual independente do byte transmitindo (se é que ele ta transmitindo

Não está né. Sequer programou os pinos como i2c corretamente

 

Não conheço este IDE. Nele não sei mas no mplab tinha (tem) uma função pra você ver o sinal... algo como logic analyser ou do gênero. Siga a pista pra ver se seu sinal sai ou pode se problema do seu circuito.

 

55 minutos atrás, Robson Manzoli Dos Santos disse:

ele já fornece as funções pra ler e escrever.

pois é. Este é um dilema de quem é adepto da "porta larga", caminho fácil mas pode te "conduzir à destruição". Uma porta estreita que geralmente recomendo é tentar entender o hw e fazer sua própria função na unha. Olha isso que fiz há muitos (e muitos) anos. É pro irmão mais velho do seu pic mas creio que a essência é a mesma.
 

/******************************************************************************************/
void i2c_waitForIdle()
{
while ((SSPCON2 & 0x1F) | RW ); // wait for idle and not writing (PIC18F252)
//while ((SSPCON2 & 0x1F) | STAT_RW ); // wait for idle and not writing (PIC16F876A)
}
/******************************************************************************************/
void i2c_start()
{
i2c_waitForIdle();
SEN=1;
}
/******************************************************************************************/
void i2c_repStart()
{
i2c_waitForIdle();
RSEN=1;
}
/******************************************************************************************/
void i2c_stop()
{
i2c_waitForIdle();
PEN=1;
}

unsigned char i2c_write( unsigned char i2cWriteData )
{
 i2c_waitForIdle();
 SSPBUF = i2cWriteData;
 return ( ! ACKSTAT  ); // function returns '1' if transmission is acknowledged
}

São as camadas mais elementares do sisteminha i2c. Perceba o minimalismo da função i2c_write() se comparada com a sua.

SSPCON2,SEN,RSEN,PEN,SSBUFF são apenas os nomes dos bits de registro e registros relacionados ao i2c. Se não tiver receio de sujar as mãos, dá uma olhadela no d.s. do seu mc e compare.

Abra algum programa de exemplo de i2c próprio pro seu mc - nem precisar ser pra este seu periférico - só pra ver os sinais.

 

No final você deve descobrir a cagadinha tipo... o ci não está gravando, esqueceu de alimentar, tá resetado, e coisas do gênero... Receba um cóqui!!!

Compartilhar este post


Link para o post
Compartilhar em outros sites
46 minutos atrás, Isadora Ferraz disse:

São as camadas mais elementares do sisteminha i2c. Perceba o minimalismo da função i2c_write() se comparada com a sua.

SSPCON2,SEN,RSEN,PEN,SSBUFF são apenas os nomes dos bits de registro e registros relacionados ao i2c

Sim...é bem mais trabalhoso, como se você tivesse no assembly rsrs.

Pois então, fazer "na unha" seria a minha última cartada. Quando todas as minhas tentativas de usar a função pronta estivesse se exaurido. Como está acontecendo rsrsr,. 

Vou seguir sua dica e buscar algum projeto que rode no meu microprocessador só pra eu confirmar as portas enviando os sinais de SDA e SCL.

 

Muito obrigado, caso eu encontre a solução, irei comentar aqui.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora





Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas publicações sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...