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

Présentation


Lire et écrire des données sur un µc en utilisant la cam OpenMV ? c’est tout à fait possible

Dans un premier temps, il faut “caler”, ou dirais-je rendre la communication I2C compatible entre la cam et le PIC pour arriver en sorte à ce que la cam puisse écrire des données sur le PIC qui une fois reçues, ce dernier les déposeras tour à tour dans un tableau (array) (tableau de 8×1) qu’on nommera Buffer[8][1].


Une bonne configuration entre la cam OpenMV et le PIC18F4550 est avant tout l’adressage. Oui sans adresse côté PIC il sera impossible de communiquer avec ce dernier. Pour plus de détails sur comment le configurer en mode esclave, vous pouvez vous rendre dans cette rubrique PIC18F4550 (esclave) – OpenMV (maître) – mode I2C.


Pour faire “simple”, si vous configurez votre cam OpenMV avec pour adresse cAdrr = 0x02, il faudra configurer le PIC avec cAdrr = 0x04 (ajout de 1bit à droite donc décalage vers la gauche pour le PIC18F4550 !! – 0x02 << 1 donne 0x04).
ou
si vous configurez votre cam OpenMV avec cette fois-ci pour adresse cAdrr = 0x02 >> 1 (suppression de 1 bit à droite cette fois-ci réalisé au niveau de la cam, décalage à droite !, ce qui donne 0x01), alors côté PIC 18F4550 laisser cAdrr = 0x02).

C’est cette histoire de décalage qui va permettre de rendre compatible la cam OpenMV avec le PIC (plusieurs tests sont situé un peu plus bas pour voir ensemble le principe c’est beaucoup plus parlant)..

Mode Lecture/Ecriture – Cam OpenMV vers PIC18F4550


Nous allons aborder le code côté cam OpenMV en Python code réalisé pour l’écriture et la lecture.

MAÎTRE – Programmation Python – Cam OpenMV STM32F765VI ARM

# Maître – OpenMV I2C – Lecture/Ecriture – Python – Electronique71.com

from pyb import I2C
import utime

i2c = I2C(2) # creation du bus I2C
i2c.init(I2C.MASTER, baudrate=100000) # initialisation du maître sur 100Khz

# 0x02 >> 1 : +1 bit à droite (décalage vers la gauche de l'adresse donne 0x04 pour PIC)
cAdrr = 0x02 >> 1
# si cAdrr = 0x02 côté cam OpenMV alors mettre cAdrr = 0x04 côté PIC18F4550 pour compatibilité !

utime.sleep_ms(500)# On attend un peu la fin de l'initialisation du bus I2C.

# Vérifie si l'esclave répond à cette adresse:
# -> renvoi True si l'esclave répond
# -> renvoi False si l'escalve ne répond pas
validation = i2c.is_ready(cAdrr)

if (validation == True):

    Buffer = bytearray(8)  # Création du Buffer (1 octet = 8bits)
    print("Nettoyage Buffer !! -> " + str(i2c.recv(Buffer,cAdrr)))

    while (True):

        # Ecriture
        i2c.send(0x00, addr = cAdrr)  # bit 0

        utime.sleep_ms(500) # -> Temp Min : utime.sleep_us(50)
        i2c.send(0x01, addr = cAdrr)  # bit 1

        utime.sleep_ms(500) # -> Temp Min : utime.sleep_us(50)
        i2c.send(0x02, addr = cAdrr)  # bit 2

        utime.sleep_ms(500) # -> Temp Min : utime.sleep_us(50)
        i2c.send(0x03, addr = cAdrr)  # bit 3

        utime.sleep_ms(500) # -> Temp Min : utime.sleep_us(50)
        i2c.send(0x04, addr = cAdrr)  # bit 4

        utime.sleep_ms(500) # -> Temp Min : utime.sleep_us(50)
        i2c.send(0x05, addr = cAdrr)  # bit 5

        utime.sleep_ms(500) # -> Temp Min : utime.sleep_us(50)
        i2c.send(0x06, addr = cAdrr)  # bit 6

        utime.sleep_ms(500) # -> Temp Min : utime.sleep_us(50)
        i2c.send(0x07, addr = cAdrr)  # bit 7

        # Lecture
        utime.sleep_ms(500) # -> Temp Min : utime.sleep_us(50)
        print(i2c.recv(Buffer,cAdrr))

        break # Supprimer "break" pour boucle en continue !

elif (validation == False):
    print("PIC 18F4550 non reconnu")

Fonctionnement
Niveau programmation Python, je vous laisse vous rendre sur ces deux liens pour explications détaillés :
PIC18F4550 (esclave) – OpenMV (maître) – mode lecture – I2C
PIC18F4550 (esclave) – OpenMV (maître) – mode ecriture – I2C


Terminal OpenMV
Ci-dessous, une capture des données situées dans le buffer du PIC18F4550


ESCLAVE – Programmation MikroC – PIC18F4550

// Esclave – PIC18F4550 – Lecture/Ecriture – MikroC – Electronique71.com

const cAdrr = 0x02; // cAdrr = 0x02 correspond à l'adresse de l'esclave
// Si cAdrr = 0x04 côté PIC alors mettre cAddr = 0x02 côté cam OpemMV pour compatibilité !

unsigned char iCount_Ecriture;
unsigned char iCount_Lecture;
unsigned char Data;
unsigned char VideBuffer;

// Tableau 2 dimensions pour envoyer donner vars cam OpenMV
unsigned char Buffer[8][1] = {
                                {0x00},  // bit 0
                                {0x00},  // bit 1
                                {0x00},  // bit 2
                                {0x00},  // bit 3
                                {0x00},  // bit 4
                                {0x00},  // bit 5
                                {0x00},  // bit 6
                                {0x00},  // bit 7
                              };

// Tableau 1 dimension pour envoyer donner vars cam OpenMV
//unsigned char Buffer[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};

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)
    {
      if (BF_bit == 1)
      {
        // Lecture -> Esclave vers Maître
        SSPBUF = Buffer[0][iCount_Lecture]; // Ajout Buffer pour lecture
        ++iCount_Lecture;
      }
    }
    else if (SSPSTAT.R_W == 0)
    {
      // Ecriture -> Maître vers Esclave
      Data = iCount_Ecriture >> 2;
      Buffer[0][Data] = SSPBUF; // On ajoute les données dans un tableau
      LATD = Buffer[0][Data]; // On affiche les données sur le PORTD
      ++iCount_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

  ADCON1.VCFG0 = 0;  // Bien penser à desactiver les tensions de références !
  ADCON1.VCFG1 = 0;

  TRISA = 0xFF;      // Config Entrée PORTA -> (RA0 à RA7)
  PORTA = 0x00;
  LATA = 0x00;

  TRISB = 0x3F;      // Config les broches du PORTB - RB0 à RB5 comme entrée (SDA/SCL)
  PORTB = 0x00;
  LATB = 0x00;

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

  TRISE = 0x00;      // Config MCLR
  PORTE = 0x00;
  LATE = 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'interruption à 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

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

  iCount_Ecriture = 0;

  iCount_Lecture = 0;

  Data = 0;

  VideBuffer = SSPBUF;  // On vide le Buffer correctement !

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

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

  while (1)
  {
    if ((P_bit == 1) && (Data >= 8))
    {
      iCount_Ecriture = 0;  // On remet à "0" le comptage de l'écriture
      iCount_Lecture = 0;   // On remet à "0" le comptage de lecture
      Data = 0;             // et on receommence le cycle !
      VideBuffer = SSPBUF;  // on vide correctement le Buffer !
    }

    if ((P_bit == 1) && (iCount_Lecture >= 8))
    {
      iCount_Ecriture = 0;  // On remet à "0" le comptage de l'écriture
      iCount_Lecture = 0;   // On remet à "0" le comptage de lecture
      Data = 0;             // et on receommence le cycle !
      VideBuffer = SSPBUF;  // on vide correctement le Buffer !
    }

    // Lecture du tableau et affichage des données sur le PORTD
    if (PORTA.B0 == 1){ LATD = Buffer[0][0]; }

    if (PORTA.B1 == 1){ LATD = Buffer[0][1]; }

    if (PORTA.B2 == 1){ LATD = Buffer[0][2]; }

    if (PORTA.B3 == 1){ LATD = Buffer[0][3]; }

    if (PORTB.B2 == 1){ LATD = Buffer[0][4]; }

    if (PORTB.B3 == 1){ LATD = Buffer[0][5]; }

    if (PORTB.B4 == 1){ LATD = Buffer[0][6]; }

    if (PORTB.B5 == 1){ LATD = Buffer[0][7]; }

  }
}

Fonctionnement
Niveau programmation MikroC, je vous laisse vous rendre sur ces deux liens pour explications détaillés :
PIC18F4550 (esclave) – OpenMV (maître) – mode lecture – I2C
PIC18F4550 (esclave) – OpenMV (maître) – mode ecriture – I2C

Schéma


Changement d’adresse



Comme évoqué dans la présentation, J’ai réalisé différents tests (8 au total) avec d’autres adresses à savoir de bien respecter que le bit0 doit être à un état logique bas “0”. Pour ne pas compliquer, je fais un décalage à gauche uniquement côté du PIC et non de la cam OpenMV (voir ci-dessous les différentes adresses)

Test Adresse OpenMV (cAdrr) Adresse 18F4550 (cAdrr) Compatibilité
1 0x04 (100b) 0x08 (1000b) OK
2 0x10 (10000b) 0x20 (100000b) OK
3 0x14 (10100b) 0x28 (101000b) OK
4 0xF0 (11110000b) 0xE0 (11100000b) OK
5 0xAA (10101010b) 0x54 (01010100b) OK
6 0x80 (10000000b) 0x00 (00000000b) NOK
7 0x40 (01000000b) 0x80 (10000000b) OK
8 0x6C (01101100b) 0xD8 (11011000b) OK

Comme vous pouvez le constater, il suffit de rajouter un “0” tout à droite, ce qui décale l’octet à gauche et donc supprime le dernier chiffre tout à gauche.

Test sur platine EasyPIC V7


Oui !! L’envoi des données via la cam OpenMV sont récupéré par les interruptions du PIC18F4550 afin qu’il affiches sur le PORTD ces données. l’affichage se réalise sur le PORTD de ma platine EasyPICV7, les leds s’allumes par comptage binaire de 0 à 7.


Le câblage est réalisés sur le PORTC broche RC3(SCL) vers RB1(SCL du PIC18F4550) et RC4(SDA) vers RB0(SDA du PIC18F4550). En effet ce pont entre le PORTC permet de ramener les résistances de 4k7 sur le PORTB où sont reliés les broches SDA et SCL du PIC18F4550 situé sur la platine EasyPicV7. Ne pas oublier de placer les switchs (SW4) RC3 et RC4 en postion “ON” afin de mettre en circulation les résistances PULL-UP

Pas de photo désolé mais vous avez le code et le schéma c’est le principal ;-).

Historiques


15/01/2021
-1er mise à disposition