Bienvenue aux nouveaux arrivants sur FantasPic !

- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.

--- L’équipe FantasPic ---
Forum général sur le langage C !

Modérateur : Jérémy

Problème de communication I2C bloquante
Superphénix
Débutant
Débutant
Messages : 54
Enregistré en : mars 2020

#1 Message par Superphénix » lun. 8 mai 2023 21:43 lien vers la Data-Sheet : Cliquez ici

Bonjour

C'est la première fois que je tente de créé une communication I2C. Je me suis inspiré des codes d'exemple que j'ai trouvé sur internet et que j'ai adaptés un peu à mon projet, et forcement ça ne marche pas du premier coup.
J'utilise un PIC18LF2620, et je veux le faire communiquer avec un capteur de type MS5837-02BA21

Voilà tout mon code :

Code : Tout sélectionner

#include <XC.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#pragma config OSC = ECIO6
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config BOREN = OFF
#pragma config MCLRE = OFF
#pragma config PBADEN = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config STVREN = OFF

#define _XTAL_FREQ 8000000
#define slave_write_address 0b11101100
#define slave_read_address  0b11101101
#define LED PORTCbits.RC5

unsigned short   C1=0, C2=0, C3=0, C4=0, C5=0, C6=0 ; // 16 Bits
__uint24         D1=0, D2=0 ;                         // 24 Bits
signed int       dT=0, TEMP=0 ;                       // 32 Bits , Utiliser var_inter64
signed long long OFF=0, SENS=0, var_inter64=0 ;       // 64 Bits
unsigned int     P=0 ;                                // 32 Bits , Utiliser var_inter64
signed int       OFFi=0 ;
signed long long Ti=0, SENSi=0, OFF2=0, SENS2=0  ;    // 64 Bits
signed short     TEMP2=0 ;                            // 16 Bits , Utiliser var_inter64
__uint24         P2=0 ;                               // 24 Bits , Utiliser var_inter64

//### FONCTIONS déclarations :
void I2C_Start(char) ;
void I2C_Ready(void) ;
char I2C_Write(unsigned char) ;
void I2C_Stop(void) ;
char I2C_Read(char) ;
void write_MS5837(unsigned char) ;
__uint24 read_MS5837(unsigned char, unsigned char) ;

int main(int argc, char** argv)
{
    TRISA   = 0b10000000 ;
    TRISB   = 0b00111100 ;
    TRISC   = 0b00011000 ;
    PORTA   = 0b00000000 ;
    PORTB   = 0b00000000 ;
    PORTC   = 0b00000000 ;
    ADCON1  = 0b00001111 ;
    INTCON2bits.RBPU = 0 ;
    //////// I2C :
    SSPSTATbits.SMP = 1 ;       // 1=Slew rate control disabled
    SSPSTAT=0b10000000 ;      // Slew rate disabled, other bits are cleared
    SSPCON1=0b00101000 ;        // Enable SSP port for I2C Master mode
    SSPCON2 = 0b00000000 ;
    SSPADD = 0b00010011 ;       // 19 = 100kHz  ,  CLK = FOSC/(4*(SSPADD+1
    PIE1bits.SSPIE = 1 ;      // Enable SSPIF interrupt
    PIR1bits.SSPIF = 0 ;
   
//### INITIALISATIONS :
    LED = 0 ;
   
    write_MS5837(0x1E) ;   // RESET
    C1 = read_MS5837(0b10100010, 2) ;   // C1
    C2 = read_MS5837(0b10100100, 2) ;   // C2
    C3 = read_MS5837(0b10100110, 2) ;   // C3
    C4 = read_MS5837(0b10101000, 2) ;   // C4
    C5 = read_MS5837(0b10101010, 2) ;   // C5
    C6 = read_MS5837(0b10101100, 2) ;   // C6
    D1 = read_MS5837(0x4A, 3) ;         // D1, OSR=8192
    D2 = read_MS5837(0x5A, 3) ;         // D2, OSR=8192
   
   
    return (EXIT_SUCCESS);
}

//####################################

void I2C_Start(char wr)
{   
    SSPCON2bits.SEN = 1 ;                       // Send start pulse
    while(SSPCON2bits.SEN) ;                    // Wait for completion of start pulse
    PIR1bits.SSPIF = 0 ;
    if(wr==0) I2C_Write(slave_write_address) ;  // Write slave device address with write=0 to communicate
    else      I2C_Write(slave_read_address) ;   // Read slave device address with read=1 to communicate
}

void I2C_Ready(void)
{
    while(!PIR1bits.SSPIF) ;                    // Wait for operation complete
    PIR1bits.SSPIF = 0 ;                        // Clear SSPIF interrupt flag
}

char I2C_Write(unsigned char data)
{
    I2C_Ready() ;                               
    SSPBUF = data ;                             // Write data to SSPBUF
    I2C_Ready() ;
    if(SSPCON2bits.ACKSTAT) return 1 ;          // Check for acknowledge bit
    else return 2 ;
}

void I2C_Stop(void)
{
    I2C_Ready() ;
    SSPCON2bits.PEN = 1 ;                       // Stop communication
    while(SSPCON2bits.PEN) ;                    // Wait for end of stop pulse
    PIR1bits.SSPIF = 0 ;
//    if(!SSPSTATbits.P) return 0 ;               // Check whether STOP is detected last. If not return 0 to indicate start failed
}

char I2C_Read(char flag)
{
    char buffer = 0 ;
    SSPCON2bits.RCEN = 1 ;                      // Enable receive
    while(!SSPSTATbits.BF) ;                    // Wait for buffer full flag which when complete byte received
    buffer = SSPBUF ;                           // Copy SSPBUF to buffer
    if(flag==0)
    {
        SSPCON2bits.ACKDT = 0 ;                 // Acknowledge data 1:NACK,0:ACK  // Send acknowledgment or negative acknowledgment after read to continue or stop reading
        SSPCON2bits.ACKEN = 1 ;                 // Enable ACK to send
        while(SSPCON2bits.ACKEN) ;
    }
    else
    {
        SSPCON2bits.ACKDT = 1 ;                 // Acknowledge data 1:NACK,0:ACK
        SSPCON2bits.ACKEN = 1 ;                 // Enable ACK to send
        while(SSPCON2bits.ACKEN) ;
    }
    I2C_Ready() ;
    return(buffer) ;
}

//####################################

void write_MS5837(unsigned char dat)
{
    I2C_Start(0) ;
    I2C_Write(dat) ;
    I2C_Stop() ;
}

__uint24 read_MS5837(unsigned char add, unsigned char seize)
{
    __uint24 dat=0, dat24 = 0 ;
    I2C_Start(0) ;
    write_MS5837(add) ;
    I2C_Start(1) ;
    if(seize==2)                            // READ C1-6
    {
        dat = I2C_Read(0) ;
        dat24 = dat<<8 ;
        dat = I2C_Read(1) ;
        dat24 = dat24 | dat ;
    }
    else if(seize==3)                       // READ Pression/Température
    {
        write_MS5837(0x00) ;                // ADC READ
        __delay_ms(20) ;                    // Conversion time
       
        dat = I2C_Read(0) ;
        dat24 = dat<<16 ;
        dat = I2C_Read(0) ;
        dat24 = dat24 | (dat<<8) ;
        dat = I2C_Read(1) ;
        dat24 = dat24 | dat ;
    }
    I2C_Stop() ;
    return dat24 ;
}


Pour l'instant tout ce que j'ai testé c'est rajouter un LED = 1 ; à différents endroits du code pour voir si ça bloque quelque part, et effectivement ça bloque dans I2C_Ready au niveau de while(!PIR1bits.SSPIF) ; mais je ne vois pas pourquoi...

Problème de communication I2C bloquante
satinas
Expert
Expert
Messages : 1262
Enregistré en : novembre 2015

#2 Message par satinas » mar. 9 mai 2023 08:26 lien vers la Data-Sheet : Cliquez ici

Bonjour Superphénix,
La fonction I2C_Ready() doit être employée lorsqu'on attend que SSPIF passe à 1, son nom serait plutôt I2C_Wait() ou I2C_WaitFinished(). Au démarrage SSPIF est à 0, normal, il passera à 1 pour signaler un évènement.
Si tu la mets en début de I2C_Write() sans avoir lancé une action, un envoi d'octet par exemple, tu vas attendre très, très longtemps :)

Code : Tout sélectionner

void I2C_Ready(void)
{
  while(!PIR1bits.SSPIF) ;                    // Wait for operation complete
  PIR1bits.SSPIF = 0 ;                        // Clear SSPIF interrupt flag
}

char I2C_Write(unsigned char data)
{
  I2C_Ready() ;                               
  SSPBUF = data ;                             // Write data to SSPBUF
  I2C_Ready() ;
  if(SSPCON2bits.ACKSTAT) return 1 ;          // Check for acknowledge bit
  else return 2 ;
}

void I2C_Start(char wr)
{   
  SSPCON2bits.SEN = 1 ;                       // Send start pulse
  while(SSPCON2bits.SEN) ;                    // Wait for completion of start pulse
  PIR1bits.SSPIF = 0 ;
  if(wr==0) I2C_Write(slave_write_address) ;  // Write slave device address with write=0 to communicate
  else      I2C_Write(slave_read_address) ;   // Read slave device address with read=1 to communicate
}

L'idéal est que la remise à 0 de SSPIF soit faite uniquement dans la fonction ready, d'autant plus qu'il est à 0 au reset. Dans ce cas il faut l'utiliser aussi pour détecter la fin du START, RESTART, STOP, voir le schéma d'une transaction I2C complète.

Problème de communication I2C bloquante
satinas
Expert
Expert
Messages : 1262
Enregistré en : novembre 2015

#3 Message par satinas » mar. 9 mai 2023 13:03 lien vers la Data-Sheet : Cliquez ici

Voilà ce que cela donne avec SSPIF utilisé à toutes les sauces.
Je n'ai testé que l'écriture sur un oled.

Code : Tout sélectionner

    // write data
    SSPCON2bits.SEN = 1;    I2C_WaitFinished(); // start
    SSPBUF = 0x78;          I2C_WaitFinished(); // envoi adresse + write
    if (!SSPCON2bits.ACKSTAT) {                 // adresse acquittée
      SSPBUF = 0x81;        I2C_WaitFinished(); // envoi data
    }
    SSPCON2bits.PEN = 1;    I2C_WaitFinished(); // stop

    // read data
    SSPCON2bits.SEN = 1;    I2C_WaitFinished(); // start
    SSPBUF = 0x79;          I2C_WaitFinished(); // envoi adresse + read
    if (!SSPCON2bits.ACKSTAT) {                 // adresse acquittée
      SSPCON2bits.RCEN = 1; I2C_WaitFinished(); // recevoir data
      buffer = SSPBUF;
      SSPCON2bits.ACKDT = 0;                    // 0:ACK 1:NACK
      SSPCON2bits.ACKEN = 1;I2C_WaitFinished(); // envoi ACK ou NACK
    }
    SSPCON2bits.PEN = 1;    I2C_WaitFinished(); // stop

Dans ton programme, pourquoi fais-tu SSPIE = 1, ce n'est pas nécessaire, SSPIF est indépendant de SSPIE. Le mécanisme qui lève les flags IF est actif en permanence. SSPIE permet juste de démarrer une routine d'interruption si SSPIF passe à 1.

Problème de communication I2C bloquante
Superphénix
Débutant
Débutant
Messages : 54
Enregistré en : mars 2020

#4 Message par Superphénix » ven. 12 mai 2023 21:55 lien vers la Data-Sheet : Cliquez ici

Merci !
Ça a résolut mon problème.
J'ai également rectifié read_MS5837()...
Du j'obtiens aussi les valeurs attendus :)

Code : Tout sélectionner

#include <XC.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#pragma config OSC = ECIO6
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config BOREN = OFF
#pragma config MCLRE = OFF
#pragma config PBADEN = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config STVREN = OFF

#define _XTAL_FREQ 8000000
#define slave_write_address 0b11101100
#define slave_read_address  0b11101101
#define LED PORTCbits.RC5

unsigned short   C1=0, C2=0, C3=0, C4=0, C5=0, C6=0 ; // 16 Bits
__uint24         D1=0, D2=0 ;                         // 24 Bits
signed int       dT=0, TEMP=0 ;                       // 32 Bits , Utiliser var_inter64
signed long long OFF=0, SENS=0, var_inter64=0 ;       // 64 Bits
unsigned int     P=0 ;                                // 32 Bits , Utiliser var_inter64
signed int       OFFi=0 ;
signed long long Ti=0, SENSi=0, OFF2=0, SENS2=0  ;    // 64 Bits
signed short     TEMP2=0 ;                            // 16 Bits , Utiliser var_inter64
__uint24         P2=0 ;                               // 24 Bits , Utiliser var_inter64

//### FONCTIONS déclarations :
void I2C_Start(char) ;
void I2C_Ready(void) ;
char I2C_Write(unsigned char) ;
void I2C_Stop(void) ;
char I2C_Read(char) ;
void write_MS5837(unsigned char) ;
__uint24 read_MS5837(unsigned char, unsigned char) ;

int main(int argc, char** argv)
{
    TRISA   = 0b10000000 ;
   TRISB   = 0b00111100 ;
   TRISC   = 0b00011000 ;
    PORTA   = 0b00000000 ;
    PORTB   = 0b00000000 ;
    PORTC   = 0b00000000 ;
    ADCON1  = 0b00001111 ;
    INTCON2bits.RBPU = 0 ;
    //////// I2C :
    SSPSTATbits.SMP = 1 ;       // 1=Slew rate control disabled
    SSPSTAT=0b10000000 ;      // Slew rate disabled, other bits are cleared
    SSPCON1=0b00101000 ;        // Enable SSP port for I2C Master mode
    SSPCON2 = 0b00000000 ;
    SSPADD = 0b00010011 ;       // 19 = 100kHz  ,  CLK = FOSC/(4*(SSPADD+1
    PIR1bits.SSPIF = 0 ;
 
    LED = 0 ;
   
    write_MS5837(0x1E) ;   // RESET
    C1 = read_MS5837(0b10100010, 2) ;   // C1
    C2 = read_MS5837(0b10100100, 2) ;   // C2
    C3 = read_MS5837(0b10100110, 2) ;   // C3
    C4 = read_MS5837(0b10101000, 2) ;   // C4
    C5 = read_MS5837(0b10101010, 2) ;   // C5
    C6 = read_MS5837(0b10101100, 2) ;   // C6
    D1 = read_MS5837(0x4A, 3) ;         // D1, OSR=8192
    D2 = read_MS5837(0x5A, 3) ;         // D2, OSR=8192

    return (EXIT_SUCCESS);
}

//####################################

void I2C_Start(char wr)
{   
    SSPCON2bits.SEN = 1 ;                       // Send start pulse
    while(SSPCON2bits.SEN) ;                    // Wait for completion of start pulse
    PIR1bits.SSPIF = 0 ;
    if(wr==0) I2C_Write(slave_write_address) ;  // Write slave device address with write=0 to communicate
    else      I2C_Write(slave_read_address) ;   // Read slave device address with read=1 to communicate
}

void I2C_Ready(void)
{
    while(!PIR1bits.SSPIF) ;                    // Wait for operation complete
    PIR1bits.SSPIF = 0 ;                        // Clear SSPIF interrupt flag
}

char I2C_Write(unsigned char data)
{
    SSPBUF = data ;                             // Write data to SSPBUF
    I2C_Ready() ;
    if(SSPCON2bits.ACKSTAT) return 1 ;          // Check for acknowledge bit
    else return 2 ;
}

void I2C_Stop(void)
{
    SSPCON2bits.PEN = 1 ;                       // Stop communication
    while(SSPCON2bits.PEN) ;                    // Wait for end of stop pulse
    PIR1bits.SSPIF = 0 ;
}

char I2C_Read(char flag)
{
    char buffer = 0 ;
    SSPCON2bits.RCEN = 1 ;                      // Enable receive
    while(!SSPSTATbits.BF) ;                    // Wait for buffer full flag which when complete byte received
    buffer = SSPBUF ;                           // Copy SSPBUF to buffer
    if(flag==0)
    {
        SSPCON2bits.ACKDT = 0 ;                 // Acknowledge data 1:NACK,0:ACK  // Send acknowledgment or negative acknowledgment after read to continue or stop reading
        SSPCON2bits.ACKEN = 1 ;                 // Enable ACK to send
        while(SSPCON2bits.ACKEN) ;
    }
    else
    {
        SSPCON2bits.ACKDT = 1 ;                 // Acknowledge data 1:NACK,0:ACK
        SSPCON2bits.ACKEN = 1 ;                 // Enable ACK to send
        while(SSPCON2bits.ACKEN) ;
    }
    I2C_Ready() ;
    return(buffer) ;
}

//####################################

void write_MS5837(unsigned char dat)
{
    I2C_Start(0) ;
    I2C_Write(dat) ;
    I2C_Stop() ;
}

__uint24 read_MS5837(unsigned char add, unsigned char seize)
{
    __uint24 dat=0, dat24=0 ;
    write_MS5837(add) ;
   
    if(seize==2)                            // READ C1-6
    {
        I2C_Start(1) ;
        dat = I2C_Read(0) ;
        dat24 = dat<<8 ;
        dat = I2C_Read(1) ;
        dat24 = dat24 | dat ;
    }
    else if(seize==3)                       // READ Pression/Température
    {
       __delay_ms(20) ;                    // Conversion time
        write_MS5837(0x00) ;                // ADC READ
        I2C_Start(1) ;
        dat = I2C_Read(0) ;
        dat24 = dat<<16 ;
        dat = I2C_Read(0) ;
        dat24 = dat24 | (dat<<8) ;
        dat = I2C_Read(1) ;
        dat24 = dat24 | dat ;
    }
    I2C_Stop() ;
    return dat24 ;
}


Retourner vers « Langage C »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 6 invités