par , 29/04/2020 à 21h41 (1290 Affichages)
Partie 4 - Programmation de la carte esclave, test de la communication I2C
L’API en langage C du bloc SCB (Serial Communication Block) est très bien documentée chez Infineon/Cypress : PSoC 4 Serial Communication Block (SCB).
Pour les échanges I2C entre maître et esclave, deux buffers pour la lecture (ReadBuffer) et l’écriture (WriteBuffer) doivent être configurés.
La structure des données échangées est simple (pas de code de début ou fin de trame, pas de somme de contrôle d’intégrité du paquet échangé).
Lors d’une transaction, le Raspberry Pi (maïtre) pourra transférer 2 octets vers la carte esclave PSoC 4, à récupérer dans le buffer WriteBuffer : un code couleur (1 : rouge, 2 : vert, 3 : bleu) suivi de l’intensité de la couleur choisie entre 0 et 255. Par exemple, la séquence 0x01 suivi d’un 0xFF signifie qu’il faut allumer la composante rouge au maximum (les autres composantes restent inchangées).
En lecture, le Raspberry Pi (maître) pourra connaître en une seule transaction l’état des composantes RVB en lisant le contenu transféré du buffer ReadBuffer : 3 octets contenant respectivement les valeurs entre 0 et 255 des composantes Rouge, Vert, et Bleu respectivement.
On choisit une configuration au démarrage de la carte PSoC, par exemple R=0x00, V=0xFF et B=0x00 pour la LED allumée en vert.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ...
/* buffers I2CSlave en lecture et écriture */
uint8 i2cReadBuffer [RD_BUFFER_SIZE];
uint8 i2cWriteBuffer[WR_BUFFER_SIZE];
...
/* Led verte allumée initialement */
PWM_Red_WriteCompare(LED_OFF); i2cReadBuffer [0] = LED_OFF;
PWM_Green_WriteCompare(LED_ON); i2cReadBuffer [1] = LED_ON;
PWM_Blue_WriteCompare(LED_OFF); i2cReadBuffer [2] = LED_OFF;
/* Initialisation des buffers et démarrage de l'esclave I2C */
I2CS_I2CSlaveInitReadBuf (i2cReadBuffer, RD_BUFFER_SIZE);
I2CS_I2CSlaveInitWriteBuf(i2cWriteBuffer, WR_BUFFER_SIZE);
I2CS_Start();
... |
Dans la boucle principale (polling), l’API permet de consulter en permanence l’état des buffers (position du pointeur symbolisée par la petite flèche bleue sur le schéma ci-dessus) et donc de connaître le statut des transferts (notamment s’ils sont complétés ou non) :
1 2 3 4 5 6 7 8
| /* Le maître (RPi) a-t-il fini de transférer les données
dans le buffer WriteBuffer ? (écriture maïtre vers esclave ) */
if (0u != (I2CS_I2CSlaveStatus() & I2CS_I2C_SSTAT_WR_CMPLT))
{
/* Le paquet reçu par l'esclave a-t-il la bonne taille ? */
if (WR_BUFFER_SIZE == I2CS_I2CSlaveGetWriteBufSize())
{
... |
Le code complet et commenté :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
| #include <project.h>
/* Constantes LED */
#define LED_ON (0xFFu)
#define LED_OFF (0x00u)
/* Constantes codes couleur */
#define RED (0x01u)
#define GREEN (0x02u)
#define BLUE (0x03u)
/* Taille des buffers, et taille du paquet */
#define WR_BUFFER_SIZE (0x02u)
#define RD_BUFFER_SIZE (0x03u)
/* Initialisation variable erreur détectée */
uint8 errorDetected = 0u;
/* buffers I2CSlave en lecture et écriture */
uint8 i2cReadBuffer [RD_BUFFER_SIZE];
uint8 i2cWriteBuffer[WR_BUFFER_SIZE];
/*******************************************************************************
* Gestionnaire d'erreur
*******************************************************************************/
void HandleError(void)
{
/* Désactiver les interruptions globales */
CyGlobalIntDisable;
/* Boucle infinie */
while(1){}
}
/*******************************************************************************
* Gestion des buffers en lecture et écriture
*******************************************************************************/
static void HandleBuffers(void)
{
errorDetected = 0u;
/* Le maître (RPi) a-t-il fini de transférer les données
dans le buffer WriteBuffer ? (écriture maïtre vers esclave ) */
if (0u != (I2CS_I2CSlaveStatus() & I2CS_I2C_SSTAT_WR_CMPLT))
{
/* Le paquet reçu par l'esclave a-t-il la bonne taille ? */
if (WR_BUFFER_SIZE == I2CS_I2CSlaveGetWriteBufSize())
{
uint8_t color = i2cWriteBuffer[1]; /* intensité couleur entre 0 et 255 */
switch (i2cWriteBuffer[0]) { /* 1er octet du buffer=code couleur */
/* Activation de la couleur choisie */
case RED :
PWM_Red_WriteCompare(color);
break;
case GREEN :
PWM_Green_WriteCompare(color);
break;
case BLUE :
PWM_Blue_WriteCompare(color);
break;
default :
errorDetected = 1;
}
}
/* erreur si donnée invalide */
else
{
errorDetected = 1;
}
/* Mise à jour du buffer ReadBuffer */
i2cReadBuffer[0] = (uint8) PWM_Red_ReadCompare();
i2cReadBuffer[1] = (uint8) PWM_Green_ReadCompare();
i2cReadBuffer[2] = (uint8) PWM_Blue_ReadCompare();
/* Réinitialisation du buffer WriteBuffer et de son statut
Le pointeur est repositionné en début de tableau */
I2CS_I2CSlaveClearWriteBuf();
(void) I2CS_I2CSlaveClearWriteStatus();
}
/* Le maître a-t-il lu le contenu du buffer ReadBuffer ? */
if (0u != (I2CS_I2CSlaveStatus() & I2CS_I2C_SSTAT_RD_CMPLT))
{
/* Réinitialisation du buffer ReadBuffer et de son statut */
I2CS_I2CSlaveClearReadBuf();
(void) I2CS_I2CSlaveClearReadStatus();
}
}
/*****************************************************************************
* main : démarrage des composants, gestion de l'I2C
******************************************************************************/
int main()
{
/* Démarrage des générateurs de signaux PWM pour la led RVB */
PWM_Red_Start();
PWM_Green_Start();
PWM_Blue_Start();
/* Led verte allumée initialement */
PWM_Red_WriteCompare(LED_OFF); i2cReadBuffer [0] = LED_OFF;
PWM_Green_WriteCompare(LED_ON); i2cReadBuffer [1] = LED_ON;
PWM_Blue_WriteCompare(LED_OFF); i2cReadBuffer [2] = LED_OFF;
/* Initialisation des buffers et démarrage de l'esclave I2C */
I2CS_I2CSlaveInitReadBuf (i2cReadBuffer, RD_BUFFER_SIZE);
I2CS_I2CSlaveInitWriteBuf(i2cWriteBuffer, WR_BUFFER_SIZE);
I2CS_Start();
/* Activation des interruptions globales */
CyGlobalIntEnable;
/* Surveillance permanente des buffers */
for (;;)
{
HandleBuffers();
if(errorDetected == 1)
{
//HandleError();
}
}
} |
Comment tester la communication I2C avec la carte PSoC 4 configurée en esclave I2C ?
Les concepteurs de la carte ont eu la bonne idée d’implémenter une interface USB-I2C pour permettre la communication avec un PC qui jouera le rôle de maître via la connexion USB.
Sur le PC, l’outil Bridge Control Panel fourni avec l’EDI simulera le Raspberry Pi (maître) en permettant d’échanger des trames I2C (mais aussi des trames série ou SPI) avec la carte PSoC esclave.
Dans la fenêtre d’édition, des lignes de commande, chacune correspondant à une transaction I2C en écriture (‘w’ pour write) ou en lecture (‘r’ pour read), terminée par un stop (le ‘p’ en fin de commande).
La première ligne r 08 x x x p permet de réclamer trois octets (les ‘x’) au composant esclave à l’adresse 0x08.
Plus bas, la réponse r 08+ 00+ FF+ 00+ p de l’esclave, avec les trois composantes Rouge=0x00, Vert=0xFF et Bleu=0x00 conformément à la programmation de l’esclave, et correspondant à la configuration au démarrage de la carte avec sa LED allumée en vert.
Ensuite, avec les trois lignes :
1 2 3
| w 08 01 ff p
w 08 03 80 p
w 08 02 40 p |
On configure les couleurs, dans l’ordre :
- rouge (code couleur=0x01, intensité=0xFF)
- bleu (code couleur=0x03, intensité=0x80)
- vert (code couleur=0x02, intensité=0x40)
Cette combinaison allumera notre LED RVB d’un magnifique magenta.
Et si après celà, on requiert une dernière fois les composantes RVB :
La réponse est bien conforme :
La communication maître-esclave est maintenant fonctionnelle. L’étape suivante va être de confier le rôle du maître à la carte Raspberry Pi.