Utilisation de l'I2C sur des PIC série 16F
Posté : 04 sept. 2009, 12:30
Je vous propose ce petit exposé, pour vous faire partager le résultat de mes travaux en ce qui concerne l'utilisation de l'I2C sur des pics de la série 16F, et en particulier le 16F690.
Le bus I2C
Petit rappel sur ce dont on parle !
Le bus I2C (Inter Integrated Circuit Bus) est une norme (issue de Philips) numérique qui permet de faire "dialoguer" des composants de type circuits intégrés : processeurs, mémoire, afficheur....une large gamme d'équipements sont aujourd'hui "de type I2C".
Ce bus est de type "bus série" à deux fils : c'est un bus car il utilise deux fils, c'est une transmission sérielle car tous les bits sont transmis sur un seul fil.
On a donc un fil pour la DATA (appelé SDA) et un fil pour l'HORLOGE (appelé SCK).
Ce bus est de type maitre / esclave : un des composants pilote les autres, dirige les opérations (le maitre), les esclaves se contentant de 'répondre présent' quant on les sollicite. En particulier, le maitre est responsable de la génération de l'unique horloge, ainsi que du contrôle des transactions dans leur ensemble.
C'est un bus utilisé en mode "question / réponse" : le maitre ouvre une transaction désignant un esclave, lui envoi une commande, et attend immédiatement une réponse (si données demandées) ou tout au moins un acquitement de la prise en compte de la commande.
C'est un bus qui peut accueillir plusieurs composants en parallèle, chacun (les esclaves) disposant d'une ADRESSE (sur 7 bits, donc 128 possibilités).
Enfin c'est un bus qui peut avoir une longueur variable, mais qui est contraint par des charactéristiques techniques précises. Sa vitesse maximale de transmission (horloge variable, pouvant aller jusqu'à 100 Khz) et la capacitance maxi définie par la norme (400 pF environ) permettent de s'adapter à pas mal de situations...sans pour autant permettre tout et n'importe quoi ! Il existe des déclinaisons plus récentes qui autorisent l'horloge à monter à 400 Khz, et l'adressage à être étendu à 10 bits.
L'I2C pour faire quoi ?
Dans mon projet, je dois mettre en relation 5 micro-controleurs, l'un pilotant les 4 autres. Pourquoi autant ? Parce que chaque esclave se charge de gérer un équipement autonome, placé à 3 mètres d'une centrale de pilotage. Cette dernière gère la cohérence de l'ensemble et une programmation (voir le post à ce sujet dans les réalisations).
L'utilisation d'un PIC comme ceux d'une série 24 peut aussi amener le besoin de l'I2C : ces pics n'ont pas d'eeprom, et il faut leur en adjoindre une externe...via I2C !
Est-ce que les PIC sont tous pareils pour utiliser I2C ?
NON !
Les petits modèles (début de la série 16F notamment) ne peuvent pas directement être utilisés pour cela...bien qu'en fait cela reste possible via 2 ports que l'on programmerai enterrement à la main...mais dans ce cas on a pas d'assistance du processeur.
Dans les modèles plus gros, on a tout d'abord une grande partie de la gamme qui dispose d'un port SSP. Ce port permet d'utiliser le bus I2C mais, dans ce cas précis, il n'assiste réellement le programmeur que pour un fonctionnement esclave. La mise en oeuvre d'un mode maitre reste possible, mais il faut se le faire à la main !
Pour pouvoir avoir une gestion hardware complète d'I2C, il faut un PIC qui dispose d'un port MSSP minimum, comme par exemple la plupart des PICs de la série 18F.
Reste que la mise en œuvre du mode maitre n'est pas si compliqué que cela...mais est artisanale et imprécise en l'absence d'un port MSSP (mais elle marche !)
Mise en oeuvre du mode ESCLAVE (pic 16F690)
Le 16F690 utilise deux entrées du port B pour gérer l'I2C : B4 et B6.
Ces deux pins doivent recevoir une configuration particulière pour gérer les signaux : il faut les mettre en mode "INPUT", sans aucune option. A NOTER : le PIC, lors du reset, active par défaut tous les convertisseurs analogiques / numériques. Le 16F690 en comporte pas moins de 12, et le port B4 est justement...le douxième ! Il faut donc penser à désactiver les convertisseurs sinon B4 restera inopérant malgré l'activation du module SSP (j'ai cherché longtemps avant de trouver ce point de détail !)
En C (compilateur HiTec C), ça se traduit comme cela :
Ensuite il faut configurer le module SSP en mode I2C esclave. Je prend ici le mode 7 bits d'adressage sans interruption sur STOP / START. Ca donne ça :
Une fois qu'on a fait ça, l'esclave doit être en mesure de recevoir des datas. A noter le fait qu'on décale l'adresse d'un bit dans le registre...mais ça dépend aussi de "comment le maitre est codé". Je veux dire par là que certains codes de pilotage considère l'adressage sur 8 bits, avec une adresse READ et une adresse WRITE pour un même chip...alors qu'en fait l'adresse est sur 7 bits mais qu'un bit est transmis AVEC l'adresse pour indiquer le sens du transfert...ce qui donne "un peu comme une double adresse sur 8 bits".
Pour recevoir les données, le plus simple c'est d'utiliser l'interruption du port SSP. Exemple d'activation de cette interruption :
Dès lors, on va recevoir des interruptions quand un octet est présent dans le flux, si l'adresse de transfert correspond à la notre :
A noter dans ce code l'importance de lire systématiquement le registre SSPBUF quand le bit BF (buffer full) est positionné, car sans cela, le hardware se met en erreur. Donc même si on n'utilise pas la donnée, il faut lire SSPBUF. Si on ne le fait pas, à la transmission de l'octet suivant par le master, le hardware va se placer en overload (SSPOV). Il déclenche une interruption mais on perd un octet...et le port SSP s'arrete. Il faut le reconfigurer / relancer le dialogue. C'est une situation d'erreur manifeste.
Le bus I2C
Petit rappel sur ce dont on parle !
Le bus I2C (Inter Integrated Circuit Bus) est une norme (issue de Philips) numérique qui permet de faire "dialoguer" des composants de type circuits intégrés : processeurs, mémoire, afficheur....une large gamme d'équipements sont aujourd'hui "de type I2C".
Ce bus est de type "bus série" à deux fils : c'est un bus car il utilise deux fils, c'est une transmission sérielle car tous les bits sont transmis sur un seul fil.
On a donc un fil pour la DATA (appelé SDA) et un fil pour l'HORLOGE (appelé SCK).
Ce bus est de type maitre / esclave : un des composants pilote les autres, dirige les opérations (le maitre), les esclaves se contentant de 'répondre présent' quant on les sollicite. En particulier, le maitre est responsable de la génération de l'unique horloge, ainsi que du contrôle des transactions dans leur ensemble.
C'est un bus utilisé en mode "question / réponse" : le maitre ouvre une transaction désignant un esclave, lui envoi une commande, et attend immédiatement une réponse (si données demandées) ou tout au moins un acquitement de la prise en compte de la commande.
C'est un bus qui peut accueillir plusieurs composants en parallèle, chacun (les esclaves) disposant d'une ADRESSE (sur 7 bits, donc 128 possibilités).
Enfin c'est un bus qui peut avoir une longueur variable, mais qui est contraint par des charactéristiques techniques précises. Sa vitesse maximale de transmission (horloge variable, pouvant aller jusqu'à 100 Khz) et la capacitance maxi définie par la norme (400 pF environ) permettent de s'adapter à pas mal de situations...sans pour autant permettre tout et n'importe quoi ! Il existe des déclinaisons plus récentes qui autorisent l'horloge à monter à 400 Khz, et l'adressage à être étendu à 10 bits.
L'I2C pour faire quoi ?
Dans mon projet, je dois mettre en relation 5 micro-controleurs, l'un pilotant les 4 autres. Pourquoi autant ? Parce que chaque esclave se charge de gérer un équipement autonome, placé à 3 mètres d'une centrale de pilotage. Cette dernière gère la cohérence de l'ensemble et une programmation (voir le post à ce sujet dans les réalisations).
L'utilisation d'un PIC comme ceux d'une série 24 peut aussi amener le besoin de l'I2C : ces pics n'ont pas d'eeprom, et il faut leur en adjoindre une externe...via I2C !
Est-ce que les PIC sont tous pareils pour utiliser I2C ?
NON !
Les petits modèles (début de la série 16F notamment) ne peuvent pas directement être utilisés pour cela...bien qu'en fait cela reste possible via 2 ports que l'on programmerai enterrement à la main...mais dans ce cas on a pas d'assistance du processeur.
Dans les modèles plus gros, on a tout d'abord une grande partie de la gamme qui dispose d'un port SSP. Ce port permet d'utiliser le bus I2C mais, dans ce cas précis, il n'assiste réellement le programmeur que pour un fonctionnement esclave. La mise en oeuvre d'un mode maitre reste possible, mais il faut se le faire à la main !
Pour pouvoir avoir une gestion hardware complète d'I2C, il faut un PIC qui dispose d'un port MSSP minimum, comme par exemple la plupart des PICs de la série 18F.
Reste que la mise en œuvre du mode maitre n'est pas si compliqué que cela...mais est artisanale et imprécise en l'absence d'un port MSSP (mais elle marche !)
Mise en oeuvre du mode ESCLAVE (pic 16F690)
Le 16F690 utilise deux entrées du port B pour gérer l'I2C : B4 et B6.
Ces deux pins doivent recevoir une configuration particulière pour gérer les signaux : il faut les mettre en mode "INPUT", sans aucune option. A NOTER : le PIC, lors du reset, active par défaut tous les convertisseurs analogiques / numériques. Le 16F690 en comporte pas moins de 12, et le port B4 est justement...le douxième ! Il faut donc penser à désactiver les convertisseurs sinon B4 restera inopérant malgré l'activation du module SSP (j'ai cherché longtemps avant de trouver ce point de détail !)
En C (compilateur HiTec C), ça se traduit comme cela :
Code : Tout sélectionner
// Coupure potentielle des interruptions sur changement de A et B
RABIE = 0;
RABIF = 0;
// Configuration du port A en input, par défaut
PORTA = 0;
TRISA = 0;
// Désactivation des convertisseurs A/N
ADCON0 = 0;
ADCON1 = 0;
ANSEL = 0;
ANSELH = 0;
// Configuration du port B en input sur B4 et B6
PORTB = 0;
IOCB = 0;
WPUB = 0;
TRISB = 0b01010000;
Code : Tout sélectionner
#define SLAVE_ADDRESS 0x20
// Désactive le SSP et reset les registres
SSPEN = 0;
SSPSTAT = 0;
SSPBUF = 0;
SSPOV = 0;
BF = 0;
// Active le mode 7 bits esclave sans interruption START / STOP
SSPCON = 0b00000110;
CKP = 1;
// Défini l'adresse du SLAVE
SSPADD = SLAVE_ADDRESS << 1;
// Active le module SSP
SSPEN = 1;
Pour recevoir les données, le plus simple c'est d'utiliser l'interruption du port SSP. Exemple d'activation de cette interruption :
Code : Tout sélectionner
SSPIF = 0;
SSPIE = 1;
PEIE = 1;
ei();
Code : Tout sélectionner
void interrupt monInterruption(void)
{
if ((SSPIE) && (SSPIF))
{
if (BF)
{
// Ici, on a reçu un octet, peu importe lequel
unsigned char value = SSPBUF;
BF = 0;
// Adresse ou donnée ?
if (DA)
{
// Octet de données...le traiter !
if (!RW)
{
// C'est une écriture, donc on RECOIT des octets depuis le master
}
else
{
// C'est une lecture...on va devoir envoyer des données au master
}
}
else
{
// Octet d'adresse...normalement c'est NOTRE propre adresse, sauf si on a mis un masque qui autorise un ensemble d'adresses
}
}
}
}