===== TD 1 Ethernet industriel : SPI, DAC et EEPROM ===== ===== DAC ===== ==== Etude du composant TLV5637 ==== Analyser la documentation du composant: [[http://www.ti.com/lit/ds/symlink/tlv5637.pdf|http://www.ti.com/lit/ds/symlink/tlv5637.pdf]] - A quoi sert le TLV5637 ? - Quelle interface de communication permet de connecter le TLV5637 à un micro-contrôleur - Donner les attributs de cette communication : simplex/duplex, connections, mode (0,1,2 ou 3), vitesse maximum, ordre des bits (MSb ou LSb first) - A quoi sert l'entrée/sortie REF du composant ? - Proposer un montage intégrant le TLV5637 pour la génération d'un signal avec une résolution de 2mv - Proposer un montage intégrant le TLV5637 pour la génération d'un signal avec une résolution de 3.2mv ==== Carte d'extension pour le TD ==== {{https://bvdp.inetdoc.net/files/iut/tp_dacspi/TPCOMDACSPI.png}} Schéma de la carte: {{https://bvdp.inetdoc.net/files/iut/tp_dacspi/schema.png}} fichiers eagle: https://bvdp.inetdoc.net/files/iut/tp_dacspi/carte-arduino-tlv56-8.sch et https://bvdp.inetdoc.net/files/iut/tp_dacspi/carte-arduino-tlv56-8.brd La carte d'extension utilisée pour ce TP permet de connecter le composant TLV5637 (ou TLV5626 ou autre) à l'Arduino. Elle dispose: - du DAC deux voies. - de 2 connecteurs BNC et de 2 sorties au pas de 2.54mm pour les sorties du DAC. - de 2 potentiomètres rotatifs pour régler les tensions analogiques en entrée des entrées analogiques (ADC) de l'Arduino. Ces 2 potentiomètres peuvent être déconnectés des ADC en retirant les cavaliers correspondant. - d'une led connectée à la sortie 8 de l'Arduino et active sur l'état haut. - d'un bouton connecté à l'entrée 9 de l'Arduino, générant un état bas lorsqu'il est pressé. ==== Exercice 1: Utilisation d'une Librairie pour le TLV5637==== Vous allez dans un premier temps utiliser une librairie objet pour piloter le DAC. Récupérer le fichier: https://bvdp.inetdoc.net/files/iut/tp_dacspi/Tlv5637.zip et l'installer de la manière suivante: Copiez-collez dans une console après l'avoir ouverte avec ALT+F2 lxterm : mkdir -p ~/Arduino cd ~/Arduino mkdir -p libraries cd libraries wget https://bvdp.inetdoc.net/files/iut/tp_dacspi/Tlv5637.zip unzip -o Tlv5637.zip rm Tlv5637.zip arduino La librairie ainsi installée déclare la classe TLV5637: /* * Copyright (c) 2014 by Bertrand VANDEPORTAELE * TLV5637 library for arduino. * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 * or the GNU Lesser General Public License version 2.1, both as * published by the Free Software Foundation. */ // For details on the sensor, see: // www.ti.com/cn/lit/gpn/tlv5637 #ifndef _TLV5637_H_INCLUDED #define _TLV5637_H_INCLUDED #include #include #include // the sensor communicates using SPI, so include the library: #include #define REF_EXTERNAL_TLV5637 0 #define REF_1024MV_TLV5637 1 #define REF_2048MV_TLV5637 2 class TLV5637 { public: TLV5637(uint8_t PIN_CS_init,uint8_t REF_init); void powerOn(); //this method should be called before any other in order to initialize the SPI bus void powerOff(); void speedFast(); void speedSlow(); void setRef(uint8_t REF_init); void writeDACA(uint16_t Value); //also update DACB with value in the buffer void writeDACB(uint16_t Value); //also update buffer value void writeDACAB(uint16_t ValueA,uint16_t ValueB); private: void writetlv5637(uint8_t R, uint16_t Value); uint8_t SPD; uint8_t PWR; uint8_t REF; uint8_t PIN_CS; }; #endif {{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}} Compléter le sketch Arduino suivant dans lequel la librairie Tlv5637 est incluse. Implémentez la fonction setup pour activer le composant DAC (faire PowerOn) et le faire fonctionner en mode rapide. Dans la fonction loop, faire en sorte de générer des échantillons de la fonction sinus sur la voie A et cosinus sur la voie B en générant 100 échantillons pour les 2 $pi$ radians. Visualiser à l'oscilloscope les signaux générés. #include #include //Numéro de la broche Arduino connectée au Chip select du TLV5637 #define DAC_CS 3 TLV5637 dac(DAC_CS,REF_2048MV_TLV5637); // the setup routine runs once when you press reset: void setup() { } // the loop routine runs over and over again forever: void loop() { } Solutions: #include #include //Numéro de la broche Arduino connectée au Chip select du TLV5637 #define DAC_CS 3 TLV5637 dac(DAC_CS,REF_2048MV_TLV5637); // the setup routine runs once when you press reset: void setup() { // start the tlv5637 library: dac.powerOn(); dac.speedFast(); } // the loop routine runs over and over again forever: void loop() { static int i=0; dac.writeDACAB(512+511*cos(i/100.0),512+511*sin(i/100.0)); i++; } {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}} ==== Exercice 2: Commande à bas niveau du DAC en utilisant l'USART de l'arduino et les fonctions de la librairie SPI==== Vous allez maintenant devoir coder vous même les fonctions (sans approche objet) permettant de piloter le DAC. Vous utiliserez les fonctions présentées sur la documentation locale d'Arduino: [[https://www.arduino.cc/en/reference/SPI]] (copier le lien dans le navigateur) **Il est demandé d'utiliser le mode SPI 2 même si l'analyse de la documentation du composant nous dit que les modes 1 et 2 conviennent, sinon la commande simultanée des 2 voies du DAC ne fonctionne pas!** La documentation de la dernière version des librairies est consultable sur: http://arduino.cc/en/Reference/SPI {{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}} Implémentez les fonctions suivantes: **void initSPIforTLV5637();** Fonction qui initialise l'interface SPI pour pouvoir communiquer avec le TLV5637 **void send16bitsTLV5637(unsigned short int value);** Fonction qui envoie la valeur value au TLV5637. La fonction gère la sélection et la desélection du composant sur le bus SPI. Pour les questions suivantes, le TLV5637 sera toujours en mode fast et power-on. Les fonctions suivantes devront appeler la fonction **send16bitsTLV5637**. **void setIntRefTLV5637(unsigned char val);** Fonction de sélection et configuration de la référence interne du TLV5637 val : 0 pour 1.024v, 1 pour 2.048v **void setExtRefTLV5637(void);** Fonction de sélection de la référence externe du TLV5637 **void writeTLV5637DACA(unsigned int value);** Fonction d'écriture d'une valeur sur le canal A du TLV5637 value : valeur à écrire sur 10 bits **void writeTLV5637DACB(unsigned int value);** Fonction d'écriture d'une valeur sur le canal B du TLV5637 value : valeur à écrire sur 10 bits **void writeTLV5637DACA_B(unsigned int a_value, unsigned int b_value);** Fonction d'écriture synchrone sur le canal A et B du TLV5637 a_value : valeur à écrire sur le canal A b_value : valeur à écrire sur le canal B {{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}} Utilisez vos propres fonctions pour: - Configurer l'horloge SPI à 125Khz - Générer un signal carré de période 200ms et d'amplitude 1V Une fois ce signal validé, réutiliser le programme que vous aviez écrit lors le l'exercice précédent (sinus et cosinus sur les 2 voies) en appelant vos propres fonctions. En cas de problème, pour debugger, vous pourrez utiliser l'oscilloscope pour visualiser les signaux des transactions SPI. Afin de rendre les signaux 'observables', vous pourrez ralentir la fréquence d'horloge SPI. Solutions pour configuration avec les fonctions de la librairie 1.8.3: SPISettings mySettings(16000, MSBFIRST, SPI_MODE2); void initSPIforTLV5637(){ SPI.begin(); pinMode(DAC_CS, OUTPUT); digitalWrite(DAC_CS, HIGH); SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE2); SPI.setClockDivider(SPI_CLOCK_DIV2); setIntRefTLV5637(0); } void send16bitsTLV5637(unsigned short int value){ digitalWrite(DAC_CS, LOW); SPI.beginTransaction(mySettings); SPI.transfer(value>>8); //Send register location SPI.transfer(value & 0xff); //Send value to record into register digitalWrite(DAC_CS, HIGH); } Solutions: #include //mettre la bonne broche: #define SSDAC 3 void initSPIforTLV5637(void) { SPI.begin(); pinMode(SSDAC,OUTPUT); digitalWrite(SSDAC, HIGH); SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE2); SPI.setClockDivider(SPI_CLOCK_DIV2); } void send16bits(unsigned short int value) { digitalWrite(SSDAC,LOW); SPI.transfer(value >> 8); SPI.transfer(value & 0x00FF); digitalWrite(SSDAC, HIGH); } void setIntRefTLV5637(unsigned char val) { if(val == 0) { send16bits(0xD001); } else { send16bits(0xD002); } } void setExtRefTLV5637(void) { send16bits(0xD000); } void writeTLV5637DACA(unsigned int value) { send16bits(0xC000 | ((value & 0x3FF) << 2)); } void writeTLV5637DACB(unsigned int value) { send16bits(0x4000 | ((value & 0x3FF) << 2)); } void writeTLV5637DACA_B(unsigned int a_value, unsigned int b_value) { send16bits(0x5000 | ((b_value & 0x3FF) << 2)); send16bits(0xC000 | ((a_value & 0x3FF) << 2)); } void setup() { initSPIforTLV5637(); setIntRefTLV5637(0); } void loop() { } Rigolo pour faire de la modulation d'amplitude: #include #define DAC_CS 3 //Chip select du TLV5637 #define ECHANTILLONNAGE 100 unsigned char t=0; unsigned char t2=0; // the setup routine runs once when you press reset: void initSPIforTLV5637() { /* Fonction qui initialise l'interface SPI pour pouvoir communiquer avec le TLV5637 */ SPI.begin(); SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE2); SPI.setClockDivider(SPI_CLOCK_DIV128); // clk to 125Khz pinMode(DAC_CS, OUTPUT); digitalWrite(DAC_CS, HIGH); } void send16bitsTLV5637(unsigned short int value) { /* Fonction qui envoie la valeur value au TLV5637 */ digitalWrite(DAC_CS, LOW); SPI.transfer((value& 0xFF00)>>8); SPI.transfer(value& 0x00FF); digitalWrite(DAC_CS, HIGH); } void setIntRefTLV5637(unsigned char val) { /* Fonction de sélection et configuration de la référence interne du TLV5637 * val : 0 pour 1.024v, 1 pour 2.048v */ if (val == 0) { send16bitsTLV5637(0x4000|0x9001); } else { send16bitsTLV5637(0x4000|0x9002); } } void setExtRefTLV5637(void){ /*Fonction de sélection de la référence externe du TLV5637*/ send16bitsTLV5637(0x4000|0x9000); } void writeTLV5637DACA(unsigned int value) { /* Fonction d'écriture d'une valeur sur le canal A du TLV5637 * value : valeur à écrire sur 10 bits */ send16bitsTLV5637(0x4000|0x8000|((value&0x03FF)<<2)); } void writeTLV5637DACB(unsigned int value) { /* Fonction d'écriture d'une valeur sur le canal B du TLV5637 * value : valeur à écrire sur 10 bits */ send16bitsTLV5637(0x4000|0x0000|((value&0x03FF)<<2)); } void writeTLV5637DACA_B(unsigned int a_value, unsigned int b_value) { /* Fonction d'écriture synchrone sur le canal A et B du TLV5637 * a_value : valeur à écrire sur le canal A * b_value : valeur à écrire sur le canal B */ send16bitsTLV5637(0x4000|0x0001|((b_value&0x03FF)<<2)); // buffer send16bitsTLV5637(0x4000|0x8000|((a_value&0x03FF)<<2)); // DAC A + update DAC B with buffer } void setup() { initSPIforTLV5637(); setIntRefTLV5637(1); } // the loop routine runs over and over again forever: void loop() { /*unsigned int val1 = 512 + 511*(sin(2*M_PI*t/ECHANTILLONNAGE)); unsigned int val2 = 512 + 511*(cos(2*M_PI*t/ECHANTILLONNAGE)); */ unsigned int val1 = 512 + 511*cos(t2*2*M_PI/100.)*(sin(2*M_PI*t/ECHANTILLONNAGE)); unsigned int val2 = 512 + 511*sin(t2*2*M_PI/100.)*(cos(2*M_PI*t/ECHANTILLONNAGE)); t++; if (t==ECHANTILLONNAGE) { t = 0; t2++; if (t2==100) t2=0; } writeTLV5637DACA_B((unsigned int) val1,(unsigned int) val2); } {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}} ==== Exercice 3: Emulation de l'interface SPI avec des GPIOs==== Vous allez maintenant devoir coder vous même les fonctions (sans approche objet) permettant de piloter le DAC sans utiliser l'interface matérielle USART. Vous devrez donc vous passer de toutes les fonctions de la librairie SPI. Les broches MOSI, SCK et CSTLV/ seront désormais configurées en sorties et pilotés comme des GPIOs par logiciel. **Pour rappel: Il est demandé d'utiliser le mode SPI 2 même si l'analyse de la documentation du composant nous dit que les modes 1 et 2 conviennent, sinon la commande simultanée des 2 voies du DAC ne fonctionne pas! En déduire les valeurs de repos pour le signal d'horloge.** {{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}} Implémentez les fonctions suivantes: **void initSPISoftforTLV5637();** Fonction qui initialise l'interface SPI Emulée pour pouvoir communiquer avec le TLV5637 (configuration de la direction des broches) **void send16bitsSoftTLV5637(unsigned short int value);** Fonction qui envoie la valeur value au TLV5637 par l'interface SPI Emulée. Vous prendrez les précautions nécessaires pour que les signaux générés respectent les timings imposés par la documentation du TLV5637. Vous pourrez tester ces fonctions en substituant les appels des fonctions SPI dans le programme de test de l'exercice précédent. void send16bitsSPI(unsigned char mosiPin,unsigned char ssPin,unsigned char sck,unsigned short int value){ digitalWrite(sck,HIGH); digitalWrite(ssPin,LOW); for(unsigned char i = 0;i < 16;i++){ digitalWrite(mosiPin,((value<>15); digitalWrite(sck,LOW); //delay(1); digitalWrite(sck,HIGH); } digitalWrite(ssPin,HIGH); } void send16bit(unsigned short int value){ send16bitsSPI(11,3,13,value); } void setIntRefTLV5637(unsigned char val){ unsigned short int trans = 0xd000; trans+=val+1; send16bit(trans); } void setExtRefTLV5637(void){ setIntRefTLV5637(2); } void writeTLV5637DACA(unsigned int value){ send16bit(0xc000+(value<<2)); } void writeTLV5637DACB(unsigned int value){ send16bit(0x4000+(value<<2)); } void writeTLV5637DACA_B(unsigned int a_value, unsigned int b_value){ send16bit(0x5000+(b_value<<2)); send16bit(0xc000+(a_value<<2)); } unsigned int i; void setup() { // put your setup code here, to run once: initSPIforTLV5637(); setIntRefTLV5637(0); } void initSPIforTLV5637(){ pinMode(3,OUTPUT); pinMode(11,OUTPUT); pinMode(13,OUTPUT); digitalWrite(3,HIGH); } void loop() { // put your main code here, to run repeatedly: //writeTLV5637DACA_B(512+sin(i*M_PI/100)*511 , 512+cos(i*M_PI/100)*511); i++; writeTLV5637DACA_B((i%2)*1023,((i+1)%2)*1023); } {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}} ===== Exercice 4: EEPROM SPI ===== Vous allez maintenant utiliser la carte présentée en [[tdcom2]] pour piloter une mémoire EEPROM via un bus SPI. La documentation du composant est disponible sur: [[http://ww1.microchip.com/downloads/en/DeviceDoc/21204E.pdf]] ==== Etude du composant 25C040 ==== - Proposer un schéma pour connecter deux eeprom 25C040 à la plateforme Arduino - Déterminer la fréquence maximale de l'horloge spi utilisable pour ce composant - Indiquer le rôle de la broche /WP - Indiquer le rôle de la broche /HOLD - Indiquer le nombre de bits d'adresse utilisés pour sélectionner une case de la mémoire - Indiquer la suite d'opérations nécessaires pour effectuer une lecture - Indiquer la suite d'opérations nécessaires pour effectuer une écriture - que faut il faire pour s'assurer que l'eeprom est prête à recevoir un ordre d'écriture? - quel est le nombre maximum de données que l'on peut écrire en une fois? ==== Codage des accès à la mémoire ==== Dans les exercices suivants, vous utiliserez l'USART matériel via la librairie SPI. {{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}} Décrire et implémenter les fonctions suivantes: **void readEEPROM(unsigned int addr, unsigned char * buffer, unsigned char nb_bytes):** addr : l'adresse de la première case à écrire sur l'EEPROM buffer : le pointeur sur une zone mémoire pour le résultat de la lecture nb_bytes : la taille de la zone à lire **void writeEEPROM(unsigned int addr, unsigned char * buffer, unsigned char nb_bytes)** addr : l'adresse de la première case à lire sur l'EEPROM buffer : le pointeur sur une zone mémoire contenant les valeurs à écrire nb_bytes : la taille de la zone à écrire {{https://bvdp.inetdoc.net/files/iut/tp_tns/TODO.jpg}} Ecrire un sketch arduino permettant de tester vos fonctions. TODO: Solution à compléter #include #define CS 7 void enableWR() { digitalWrite(CS,LOW); SPI.transfer(0x6); digitalWrite(CS,HIGH); } char EEPROMReady() { digitalWrite(CS,LOW); SPI.transfer(5); unsigned char val = SPI.transfer(0); digitalWrite(CS,HIGH); return (val&1); } void readEEPROM(unsigned int addr, unsigned char * donnee, unsigned char nb) // 17 > nb > 0 { digitalWrite(CS,LOW); SPI.transfer(0x03|(((addr>>8)&0x01)<<3)); SPI.transfer(addr&0xFF); for(char i = 0;i>8)&0x01)<<3)); SPI.transfer(addr&0xFF); for(char i = 0;i {{https://bvdp.inetdoc.net/files/iut/tp_pic/validation.png}} --------------------------------------------------------------------------------------------------------- Vielles infos pour version précédente d'arduino: La version 1.6 stocke les librairies dans ~/Arduino/libraries alors que la 1.0.5 stocke les librairies dans ~/sketchbook/libraries Configurer l'IDE Arduino pour travailler dans le dossier sketchbook, Fichier->Préférence: Emplacement du carnet de croquis: {{https://bvdp.inetdoc.net/files/iut/tp_dacspi/arduinopreferences.png}} Vérifier que vous ayez une valeur comme celle-ci (en remplaçant bertrand.vandeportae par votre login) /home/IUT/bertrand.vandeportae/sketchbook