Dernière mise à jour le 09/01/2021

Présentation


Comment utiliser un microcontrôleur en mode esclave (slave en anglais) en utilisant uniquement les interruptions? comment utiliser le “Clock stretching ” ou en français ce qui se traduit par “étirement de l’horloge”? comment les données arrivent dans le buffer et comment le microcontrôleur peut renvoyer des données en mode lecture lorsque le 8ème bit envoyé par le maitre est à l’état haut (“1” logique) – c’est ce que vous voulez connaître? et bien vous vous trouvez au bon endroit.

Soft_I2C Logiciel (Software) ou I2C Matériel (Hardware) ?


Bonne question? mais qu’est ce que cela veux bien dire ?
Pour faire simple:


I2C Logiciel (Software) : Lorsque nous parlons de I2C Logiciel c’est que votre microcontrôleur ne possède pas les broches SDA et SDL alors il faut trouver une parade afin de créer ces 2 broches pour la communication par la méthode logiciel (Software) en programmant quelques lignes de code supplémentaires. (On utilise la routine Soft_I2C de MikroC).


I2C Matériel (Hardware) : Lorsque nous parlons de I2C Matériel, c’est que votre microcontrôleur possède les broches SDA et SDL. (On utilise la routine I2C1 de MikroC)


Voilà la différence entre les deux !! pas compliquer non? avec ou sans broches SDA et SDL il est tout à fait possible de communiquer par la liaison I2C mais je vous conseille si vous devez réaliser un programme un peu plus complexe en utilisant des interruptions, vérifier le Buffer, ou autres de vous garantir que le PIC que vous utilisez soit bien équipé des broches SDA/SDL.

Réglages du PIC18F4550


Avant de se lancer dans la programmation du PIC18F4550, il faut avant toutes choses commencer à savoir ce que l’on désire réaliser en I2C pour que notre PIC puisse jouer le rôle d’esclave. Le PIC18F4550 comporte sur ces broches RB0(SDA) et RB1(SCL) la possibilité de réaliser une liaison I2C, et c’est donc ces 2 broches que nous allons utiliser afin de pouvoir communiquer avec le monde exterieur. En consultant Dans le datasheet (ou doc technique) du PIC18F4550, il faut se rendre au chapitre nommé “Master Synchronoux Serial Port” (MSSP) ou on y trouve 3 autres rubriques qui sont:
– Controle Registres
– SPI Mode
– I2C Mode (Ah? interressant! , c’est donc ce mode que nous là que nous allons utiliser).
Le module MSSP en mode I2C peut être utilisé soit en mode 7 bits soit en mode 10 bits. Pour ma part je vais utiliser en mode 7 bits que nous utilisons en grande majorité.
En ce qui concerne les broches RB0 pour l’horloge série (SCL) et RB1 pour les données série (SDA), nous devons configurer ces broches comme des entrées en définissant les bits TRISB (là encore ceci est très bien spécifié au niveau du datasheet. Vous verrez un peu plus bas au niveau de la programmation que chaque lignes sont détaillées pour explication.
Ce qui va nous intéresser particulièrement ce sont les interruptions ou nous passerons du temps pour bien comprendre la mécanique interne alors commençons sans plus tarder!

(Schéma qui va nous servir pour la réalisation des transmissions de données)

Interruptions

Les données qui émanes du maitre arrives dans un ordres bien précis qui sont en 1er un octet correspondant à l’adressage qui pour moisera 0xA8 (j’ouvre une parenthèse mais si vous utiliser plusieurs PIC sur la même liaison I2C il faut que le maitre distribues les données au microcontrôleurs correspondant – prenez exemple sur un facteur lorsqu’il distribue le courrier il faut une adresse précise pour chaque personne afin que le facteur puisse retrouver à qui il doit déposer le courrier dans la boite au lettres  et bien c’est la même chose pour l’adresse du PIC,  et c’est ce 1er octet qui le détermine je ferme la parenthèse et reprenons). En ce qui concerne le 2ème octet, je vais l’utiliser à ce que l’esclave puisse envoyer l’information au maitre ou bien à ce qu’il puisse afficher l’information sur le PORTD (des leds seront ou pas allumées en fonction de chaque bits afin de voir ce qui a été envoyé par le maitre). Vous savez quoi ??! on fera les 2 un envoi pour le maitre et un affichage au niveau des leds sur le PORTD.


Comment ça fonctionne niveau interruption? c’est là que nous allons voir ça de plus prêt.  Le fonctionnement est le suivant, lorsque le maitre envoie un 1er octet (8bits) qui correspond à l’adressage, le bit de poids faible en l’occurrence le bit 0 permet de savoir si nous somme en lecture ou en écriture. “1” pour la lecture et “0” pour l’écriture tout simplement. Ensuite les octets du bit 1 au bit 7 quant à eux sont l’adresse (oui car le 1er octet envoyé bit0 à bit7 est l’adresse il ne faut surtout pas l’oublier !). On peut représenter l’envoi des données comme ceci:


Diagramme en bloc

Les bits vont arrivés de la part du maitre 1 à 1 sur la broche RB1 (SDA) qui vont se réfugier tranquillement dans le registre SSPSR. Lorsque SSPSR sera rempli des 8bits, il y aura une comparaison avec le registre SSPADD qui correspond à l’adresse de mon PIC que j’ai déja renseigné par la valeur 0xA8 ce qui donne en binaire “10101000b” si SSPSR est égale à SSPADD alors une interruption survient et aussitôt les 8bits sont déplacé dans le buffer nommé SSPBUF qui va pouvoir être lu pas compliqué non? On vérifie si SSPSR correspond à l’adresse SSPADD et si c’est ok alors on peut lire,  sinon cas contraire rien ne se passe.

Quelle adresse choisir?

Voilà une bonne question. Une adresse ne ce choisi pas au hasard, car il faut respecter le protocole I2C qui énonce que le bit de poids faible (bit0) celui-ci sert à 2 états soit logique “1” pour lecture soit logique “0” pour écriture. En fonction du bit de poids faible bit0, l’esclave réagira ou non avec un bit d’acquittement nommé ACK.


Ainsi l’adresse 0xA8 = 10101000b donne ceci en écriture et l’adresse 0xA9 = 10101001b donne ceci en lecture et vous remarquerez que le bit0 change d’état si nous somme en lecture ou en écriture. vous aimerez utiliser une autre adresse comme par exemple l’adresse 0x02 = 00000010b (écriture) donne 0x03 = 00000011b (lecture). Un dernier pour la route ? 0x78 = 01111000b (
écriture) donne 0x79 = 01111001b (lecture) pas compliqué non ? pour ma part j’utilise toujours l’adresse en tant qu’écriture.

Exemple 1 – Reconnaissance adresse cAdrr = 0x02 de l’esclave…


Seule l’adresse 0x02 est reçue par le PIC18F4550 et non les autres ainsi la broche RD1 est à l’état logique “1” de couleur rouge

// Verification adresse 0x02 – MikroC – Electronique71.com

const cAdrr = 0x02; // correspond à l'adresse de l'esclave

void interrupt() // On contrôle chaque interruptions
{
  if (PIR1.SSPIF == 1) // si SSPSTAT = SSPDR alors SSPIF = 1
  {
    LATD = SSPBUF;     // On affiche l'adresse

    SSPCON1.CKP = 1;   // On relâche l'horloge pour lancer la suite

    PIR1.SSPIF = 0;    // On remet à zéro le drapeau d'interruption et on attend la prochaine !
  }
}

void init()
{

  ADCON1 = 0xFF;     //  On configure toutes les broches en numérique (0 ou 1)

  ADCON0.ADON = 0;   // On désactive le module de convertisseur analogique numérique

  CMCON = 0x07;      // On désactive le mode comparateur

  TRISB = 0x03;      // config les broches du PORTB - RB0 et RB1 comme entréed (SDA/SCL)e
  PORTB = 0x00;
  LATB = 0x00;

  TRISD = 0x00;      // Configuration PORTD en sortie pour la lecture
  PORTD = 0x00;
  LATD = 0x00;

  INTCON.GIE = 1;    // On active les interruptions globales 
  INTCON.PEIE = 1;   // On active les interruptions périphériques 
 
  PIE1.SSPIE = 1;    // On active le MSSP ( Module port série synch principal I2C ou SPI) 
  PIR1.SSPIF = 0;    // On met le drapeau d'interrutpion à zéro pour commencer 
 
  SSPCON1.SSPEN = 1; // On active les broches RB0 et RB1 en mode SDA et SCL
 
  // On active le mode 7 bits (0 à 7 = 8 bits) avec interruptions sur bit Start et Bit Stop 
  SSPCON1.SSPM0 = 0;
  SSPCON1.SSPM1 = 1;
  SSPCON1.SSPM2 = 1;
  SSPCON1.SSPM3 = 1;

  SSPADD = cAdrr;    // Configuration de l'adresse de l'esclave du PIC 18F4550

  SSPSTAT.SMP = 1;   //  vitesse de communication 100 Khz (standard)

  SSPCON2.SEN = 1;   // On active l'étirement de l'horloge

  Delay_ms(100);     // On attend un peu la fin de l'initialisation
}

void main()
{
  init(); // Initialisation du PIC18F4550

  while (1)
  {
    // On ne fait rien ...
  }
}


Debugger I2C – Test Proteus

Pour les tests et le principe de fonctionnement je vous laisse vous rendre sur ce lien d’explication Debugger I2C

Ci-dessous le code a copier pour test sous proteus

// Différentes adresses pour test
{SEQUENCE001=S 0xA8 N P}
{SEQUENCE002=S 0xA9 N P}
{SEQUENCE003=S 0x02 N P}


Conclusion

Le code ci-dessus en MikroC + le code du Debugger I2C de proteus montre uniquement que le PIC18F4550 en mode esclave réagira uniquement sur l’adresse 0x02 et non sur les adresse 0xA8 ou 0xA9. Une fois l’adresse correspondante reçue, il affichera celle-ci sur le PORTD c’est d’ailleurs ce que vous voyer au niveau du schéma electronique la broche RD1 est à l’état logique haut (+5V) car c’est bien l’adresse qui correspond à celle que nous avons renseigné dans le SSPADD.

On va maintenant s’interesser sur le principe de comment envoyer (si le maître demande de lire les données de l’esclave) et afficher des données (si le maître demande d’écrire des données sur l’esclave).

Exemple 2 – Ecriture/lecture adresse cAdrr = 0x02 réponse esclave…


Ecriture


Regardons déjà un 1er exemple sur l’écriture, le maitre va envoyer le 1er octet qui correspond à l’adresse (S 02 A = S 0x02 A = S 00000010b A) et tout de suite après il va enchainer avec le 2ème octets qui correspond aux données que nous allons vouloir écrire (0x05 = 00000101b). Ainsi le PORTD met à l’état logique haut RD0 et RD2.

1er octet validé à mis à l’état logique haut RD1.
2ème octet tout de suite dans la foulée a mis à l’état logique haut RD0 et RD2 (c’est pour cette raison que nous avons pas eu le temps de voir RD1 à l’état logique haut car l’interruption pour le 1er octet a été levée rapidement).


Lecture


Regardons maintenant ce que cela donne en mode lecture. Nous avons cette fois-ci toujours la même adresse sauf que le bit0 est à l’état logique “1” cela donne 0x03 = 00000011b(lecture). Dans cette configuration, c’est l’esclave qui va renvoyer ses données au maître car c’est le maitre qui réclame la lecture – la couleur bleu représente l’esclave et en rose le maître. L’esclave a envoyé comme données 0xF0 = 11110000b, et à la fin de l’envoie des données, le maîtres génère un bit d’acquittement  “Nak”en signalant qu’il à bien reçu ses données.

Ces lignes de code ci-dessous qui peuvent être copiés collés (c’est fait pour d’ailleurs ;-)) vont vous permettre de configurer votre PIC18F4550 en mode esclave. Je vous laisse le soin de modifier la variable ‘cAdrr’ pour modifier l’adresse de votre esclave.

// Ecriture/lecture adresse cAdrr = 0x02 – MikroC – Electronique71.com

const cAdrr = 0x02; // correspond à l'adresse de l'esclave

void interrupt() // On contrôle chaque interruptions
{
  if (PIR1.SSPIF == 1)
  {
    // SSPSTAT.R_W  -> bit0 = 1: Lecture  ou  bit0 = 0: Ecriture
    if (SSPSTAT.R_W == 1)
    {
      // Lecture -> Esclave vers Maître
      SSPBUF = 0xF0;   // Données sont ajoutée dans le buffer pour la lecture
    }
    else if (SSPSTAT.R_W == 0)
    {
      // Ecriture -> Maître vers Esclave
      LATD = SSPBUF;   // Affichage des données envoyée par le maitre pour ecriture
    }

  }

    SSPCON1.CKP = 1; // On relache l'horloge pour lancer la suite
    PIR1.SSPIF = 0;  // On remet à zéro le drapeau d'interruption et on attent la prochaine !
}

void init()
{

  ADCON1 = 0xFF;      //  On configure toutes les broches en numérique (0 ou 1)

  ADCON0.ADON = 0;   // On désactive le module de convertisseur analogique numérique

  CMCON = 0x07;      // On désactive le mode comparateur

  TRISB = 0x03;      // config les broches du PORTB - RB0 et RB1 comme entrée (SDA/SCL)
  PORTB = 0x00;
  LATB = 0x00;

  TRISD = 0x00;      // Configuration PORTD en sortie pour la lecture
  PORTD = 0x00;
  LATD = 0x00;

  INTCON.GIE = 1;    // On active les interruptions globales 
  INTCON.PEIE = 1;   // On active les interruptions périphériques 
 
  PIE1.SSPIE = 1;    // On active le MSSP ( Module port série synch principal I2C ou SPI) 
  PIR1.SSPIF = 0;    // On met le drapeau d'interrutpion à zéro pour commencer 
 
  SSPCON1.SSPEN = 1; // On active les broches RB0 et RB1 en mode SDA et SCL
 
  // On active le mode 7 bits (0 à 7 = 8 bits) avec interruptions sur bit Start et Bit Stop 
  SSPCON1.SSPM0 = 0;
  SSPCON1.SSPM1 = 1;
  SSPCON1.SSPM2 = 1;
  SSPCON1.SSPM3 = 1;

  SSPADD = cAdrr;    // Configuration de l'adresse de l'esclave du PIC 18F4550

  SSPSTAT.SMP = 1;   //  vitesse de communication 100 Khz (standard)

  SSPCON2.SEN = 1;   // On active l'étirement de l'horloge

  Delay_ms(100);     // On attend un peu la fin de l'initialisation
}

void main()
{
  init(); // Initialisation du PIC18F4550

  while (1)
  {
    // On ne fait rien ...
  }
}


Debugger I2C – Test Proteus

Pour les tests et le principe de fonctionnement je vous laisse vous rendre sur ce lien d’explication Debugger I2C

Ci-dessous le code a copier pour test sous proteus

// -> Ecriture maître vers esclave
{SEQUENCE001=S 0x02 N 0x05 N P}
// -> Lecture maître de l’esclave
{SEQUENCE002=S 0x03 N P}
// -> 1er octet = 0x04 (mauvaise adresse pour l’ecriture)
{SEQUENCE003=S 0x04 N 0x05 N P}
// -> 1er octet = 0xA9 (mauvaise adresse pour la lecture)
{SEQUENCE004=S 0xA9 N P}


Conclusion

Niveau programmation “un peu” de changement .
– Ecriture : 0x02 = 00000010b donne bien une ecriture et le 2ème octet (0x05) va lui aussi être envoyé pour être écrit.
– Lecture : 0x03 = 00000011b donne bien une lecture, c’est en mode lecture que l’esclave va renvoyer ses données afin que le maître puisse les lires.
En faite que faisons nous exactement? (remonter un peu plus haut pour voir le “Diagramme bloc”).
On envoi sur la broche SDA, le 2ème octet 0x05 = 00000101b. Cet octet va donc aller se réfugier tranquillement dans le registre SSPSR. Une interruption survient et va remplir le registre SSPBUF (rien d’anormal niveau fonctionnement interne), Si vous regardez attentivement le Diagramme bloc vous avez “Read” et “Write” Read pour la lecture sur le BUS interne et Write pour l’ecriture sur le BUS interne c’est en fonction des états de “SSPSTAT.R_W”(ce bit agit seul et c’est lui qui vérifie les différents état du bit0 (bit de poid faible)) soit 1 pour la lecture dans ce cas il faut préparer le SSPBUF pour que celui-ci soit lu par le maître ou “SSPSTAT.R_W” qui va être à l’état 0 pour l’ecriture et dans ce cas nous affichons les données sur le PORTD envoyées par le maître . Je vous laisse lire à tête reposer le programme MikroC afin que vous compreniez bien le fonction en mode esclave.


Ce qu’il faut comprendre en I2C, c’est le bit de poids faible bit0 qui mène la danse. Ensuite l’adressage de PIC ne dois pas se terminer avec un bit0 = 1 mais un bit0 = 0. Ainsi, seul le maître décidera d’attribuer un “1” ou “0” logique pour faire les transmissions soit en lecture soit en écriture.

Test sur platine EasyPicV7


Non pas cette fois-ci…

Historiques


09/01/2021
-1er mise à disposition