VOR-008 sous projet I2C

De VoWiki
Aller à la navigation Aller à la recherche

AccueilNos ProjetsVOR-008

Com I2C pour Odo souris
IIC.JPG

VoLAB

Association VoRoBoTics

Date : 27/10/2015

Auteur : J.Soranzo

Relecteur :

Thème: Communication IIC, odométrie, souris optique

Projet : VOR008 plate-forme odométrique

Problématique

Dans le cadre du projet VOR008 implémenter un canal de communication entre un module capteur odométrique constitué d'un composant ADNS-2610 (des souris optiques) et un ARDUINO UNO (dans un premier temps puis d'un microcontrôleur Atmega88PA) et le contrôleur du robot (Atmega2560).

A terme le module capteur odométrique devrait être constitué de 2 ADNS2610 et d'un microcontrôleur avec un bus IIC (cela pourrait être par exemple un ATmega88)

J'aurais pu choisir une trame de longueur fixe entre le maître et l’esclave (le module capteur) constituée de 21 octets (+1 pour l'adresse du composant). Cette trame pourrait être : dxd, dyd, dxg, dyg, status avec dxd déplacement mesuré suivant l'axe X de la roue droite en unsigned long + checksum soit 5 octets répété 4 fois et terminé par un octet d'état. Les 4 checksum sont là pour éviter que le maître utilise un donnée non à jour.

(4+1)+(4+1)+(4+1)+(4+1)+1

Pour palier au problème des données pas à jour, on pourrait également imaginer un mécanisme dans l'esclave avec un booléen qui permet de remplir le tableau juste après une lecture du maître économie alors de 3 octets. La trame devient alors Status + dxd +dyd + dxg +dyg + checksum globale de la trame soit 18 octets +1.

Pour élever un peu le niveau et augmenter la polyvalence de cette étude, j'ai décidé d'essayer d'implémenter un protocole similaire à celui rencontré dans les EEPROM IIC.

La trame est de longueur variable. Le maître fourni d'abord l'adresse du composant puis l'adresse dans le composant et enchaîne un certain nombre quelconque de lectures (à sa convenance). L'esclave, ici notre EEPROM, place sur le bus, ses données au fur et à mesure des coups d'horloge en incrémentant automatiquement son pointeur d'adresse interne. Arrivé au bout de sa zone mémoire, elle recommence à l'adresse 0 à moins que le maître ait recommencé une nouvelle trame en fournissant une nouvelle adresse interne.

Répertoire de travail

00-ProjetsPerso\009-asservDCMotor\06-userDoc\articleAnexI2C

00-ProjetsPerso\009-asservDCMotor\01-maquettageFaisabilite\VOR8_ODOSOURIS_I2C pour le code

Plate-forme de développement

Développement sous Codeblock for ARDUINO

2 Arduino UNO connectés cf. manip de mise au point

Librairie ADSN-2610 : utilisation de la librairie toute faite de Martijn Thé

Code suivi sous git & github https://github.com/volab/VOR-008_ODOSOURIS_I2C.git

Manip de mise au point

Afin de mettre au point ce canal de communication et pour simplifier les manipulation, j'ai utilisé 2 ARDUINO UNO. Un en maître pour simuler la 2560 et un en escalve pour simuler le module capteur.

ManipMapIIC.JPG

Le maître est directement programmé via USBASP depuis codeblocks quant à l'esclave, il est programmé via son port série usb de manière classique.

La programmation du maître via cette méthode permet de laisser connecté sur son port série USB une fenêtre de terminal puTTY

Communication IIC version EEPROM

Phase1

IIC master

La librairie Wire.h qui implémente un objet wire qui ciomprend un certain nombre de méthodes est faite pour sauf que, on a 2 possibilités pour constituer les trame IIC en tant que maître.

Soit beginTransmission(id), write(), endTransmission()

C'est au moment du endTransmission que le bus est réellement piloté.

Soit requestFrom(id, nbrOctet) suivi de read() qui prend tout en charge.

(devant toutes ces méthodes on mets wire.) évidement.

Questionnement:

Comment faire une trame: idcomposant – adresseDansleComposant – lectures répétées ?

Il faudrait pouvoir mélanger les 2 possibilités:

beginTransmission(id) – write( adresseInterne) – requestFrom(id, nbrOctets) – endTransmission.

La réponse est disponible dans le playground Arduino dans l'interface avec une EEPROM I2C. Exemple:

    byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
    byte rdata = 0xFF;
    Wire.beginTransmission(deviceaddress);
    Wire.send((int)(eeaddress >> 8)); // MSB
    Wire.send((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress,1);
    if (Wire.available()) rdata = Wire.receive();
    return rdata;
  }
  // maybe let's not read more than 30 or 32 bytes at a time!
  void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
    Wire.beginTransmission(deviceaddress);
    Wire.send((int)(eeaddress >> 8)); // MSB
    Wire.send((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress,length);
    int c = 0;
    for ( c = 0; c < length; c++ )
      if (Wire.available()) buffer[c] = Wire.receive();
  }


Donc on fait begin(id) write(adresse) end() requestFrom(nombre), suivi côté maître du nombre de read() qui vont bien...

Ce n'est pas tout à fait le comportement souhaité. En effet, le requestFrom répète l'adresse du composant.

Il pourrait être envisageable de faire :

begin(id) write(adresse) read() read().... end()

Oui mais non :

« Reads a byte that was transmitted from a slave device to a master after a call to requestFrom() or was transmitted from a master to a slave. read() inherits from the Stream utility class. »

Extrait du référentiel de la librairie Wire sur le site Arduino.cc. Après un requestFrom() côté maître donc impossible de metrre read() à l'intérieur d'une trame.

IIC Slave

Dans le setup, on "register" les 2 routine de traitement. Une pour les requête en écriture et une pour les requête en lecture:

    Wire.onReceive(IIChandlerRec);
    Wire.onRequest(requestEvent);

Dans la boucle loop, on ne fait rien ! Ce sont les 2 routines de traitement qui font la majeur partie du traveille IIC.

void IIChandlerRec(int combien){
    Serial.print(combien);Serial.println(" octet recue");
    if (Wire.available()) regAdd = Wire.read();
}

et

void requestEvent(void){
        Wire.write(registres, 3); //envoi de seulement 3 octets pour les premier tests
}

Bug

Mode émulation d'une EEPROM, j'ai constaté un bug de fonctionnement.

L'escalve n'a pas le temps de retourner si les 2 trame sont trop rapporchées.

Delta entre les 2 trames 97us

Avec seulement onRequest cela fonctionne.

Avec 500us entre les 2 trames ça passe

Constat d'échec version EEPROM

Quand on comprend bien à la fois la mécanique de la librairie Wire et celle du bus I2C, on s’aperçoit que ce type d'implémentation (comportement d'une EEPROMI2C) est quasi impossible. Il faudrait pouvoir agir à un niveau très bas pour pouvoir injecter les octets sur le bus au fur et à mesure des coups d'horloge. Rappelons que l'esclave ne sait absolument pas combien d'octets vont être lu dans la trame et que le délais entre 2 octets et de seulement 10us à 20 us pas plus avec un bus à 100kHz.

Communication IIC version simplifiée

Phase 2

Dans cette version, la Trame est de longueur fixe avec 18 octets de données (16 + 1status + 1 checksum) et 19 octets pour la trame complète avec l'adresse du composant qui est transmise en premier.

Dans cette version, il n'y a qu'un trame onRequest de lecture des données de l'esclave vers le maître.

Durée de la trame : 19*10bits*10us= 1,9ms


0001.JPG LE premier octet de la trame est 5 (adresse du composant) puis 1C 34 20 en hexa



Intégration avec la souris optique

ADSN2610 de chez AGILENT


ADNS2610 importantFeatures.JPG Caractéristique Importante

83ms/image

ADNS2610 deltayRegister.JPG

400dpi soit 400points pour 2,54cm soit pour 127 points (valeur maximum des 2 registres):

8mm !

Question : quelle est la vitesse maximum à ne pas dépasser si on fait une lecture toute les 10us

En lecture pleine vitesse: on est a 255us/ registre 1ms pour les 4

0,008m => 1x10-3s en théorie on peu mesurer du 8m/s (pour information VOR008 ne dépasse pas le 1,77ms

Ce calcul est erroné:

En effet pour lire un octet il faut constituer un trame de 2 octets (cf. Datasheet ADNS)

Il faut donc 2 fois plus de temps pour lire les 4 registres. Donc vitesse max 4m/s.


0002.JPG Trames du capteur avec le code ci-après.

Code d'acquisition des données capteur

 uint8_t OptiMouse::readRegister(uint8_t address)
 {
   int i = 7;
   uint8_t r = 0;

   // Write the address of the register we want to read:
   pinMode (_sdioPin, OUTPUT);
   for (; i>=0; i--)
   {
     digitalWrite (_sclkPin, LOW);
     digitalWrite (_sdioPin, address & (1 << i));
     digitalWrite (_sclkPin, HIGH);
   }

   // Switch data line from OUTPUT to INPUT
   pinMode (_sdioPin, INPUT);

   // Wait a bit...
   delayMicroseconds(100);

   // Fetch the data!
   for (i=7; i>=0; i--)
   {
     digitalWrite (_sclkPin, LOW);
     digitalWrite (_sclkPin, HIGH);
     r |= (digitalRead (_sdioPin) << i);
   }
   delayMicroseconds(100);

   return r;
 }

Extrait de la lib:

/* OptiMouse.cpp - Part ofoptical mouse sensor library for Arduino

Copyright (c) 2008 Martijn The. All right reserved.

http://www.martijnthe.nl/

  • /

Annexes

UNO pinout

Uno A4 (SDA), A5 (SCL)

328p27, 28

Wire.h

Begin() ou begin(address) : avec une adresse c'est côté slave

requestFrom(address, quantity) ou Wire.requestFrom(address, quantity, stop)

beginTransmission(address) Subsequently, queue bytes for transmission with the write()

endTransmission() ou Wire.endTransmission(stop)

stop : boolean. true envoie un stop, libérant le bus. false envoie un restart et garde le bus actif.

write(value), write(string) ou write(data, length)

data: an array of data to send as bytes

available()

read()

onReceive(handler) : permet d'avoir un handler côté slave.

onRequest()


ADNS2610 mouse

400DPI

soit 400points pour 2,54cm

soit 1pt pour 25,4mm/400

Relevés oscilloscope

IMAG001.jpg IMAG002.jpg
Trame IIC sans résiatance de rappel au 5V sur SCL et SDA Les même Trame avec.

Fichiers sources

Sources odt du présent document dans sa version originale.

Les images qui vont avec.

Le même fichier en pdf

Et le code sous github https://github.com/volab/VOR-008_ODOSOURIS_I2C.git

Licence

Ce document est mise à disposition selon les termes de la Licence Creative Commons Attribution 4.0 International.

CC88x31.jpgPaternité 'by' :L'œuvre peut être librement utilisée, à la condition de l'attribuer à l'auteur en citant son nom.


Note aux auteurs de documents du VoLAB, Vous avez la possibilité de changer de licence. Mais ce serait bien de rester libre et ouvert. Encore une fois ceci est une recommandation et pas une obligation.

Bibliographie

webographie

http://fr.wikipedia.org/wiki/Licence_Creative_Commons


http://www.martijnthe.nl/2009/07/interfacing-an-optical-mouse-sensor-to-your-arduino/


https://www.arduino.cc/en/Reference/Wire

Rédaction en langue française

Partant du constat de terrain qu'une énorme masse d'information concernant les sujets qui nous intéressent comme entre autres l'impression 3D n'étaient disponibles que dans la langue de Shakespeare et que de nombreuses personnes dans notre entourage ne maîtrisaient pas la dite langue et soucieux de diffuser encore plus l'information, nous avons pris le parti, au VoLAB, de rédiger nos documents de préférence en langue française.

VoLAB

Un mot sur le VoLAB. VoLAB est un fablab implanté à environ 30km au nord-ouest de Paris dans la commune de Vauréal dans l'agglomération de Cergy Pontoise. Il est animé par l'association VoRoBoTics.

Site internet www.vorobotics.com