IMA4 2019/2020 P10 : Différence entre versions
(→Programmation d'un code pour le test du DAC) |
(→Documents Rendus) |
||
(18 révisions intermédiaires par le même utilisateur non affichées) | |||
Ligne 641 : | Ligne 641 : | ||
Les résultats que j'ai obtenus ne sont pas encore satisfaisant. J'ai d'abord réussi à créer le pattern de reset du DAC, comme on peut le voir sur les trois images d'oscilloscope : | Les résultats que j'ai obtenus ne sont pas encore satisfaisant. J'ai d'abord réussi à créer le pattern de reset du DAC, comme on peut le voir sur les trois images d'oscilloscope : | ||
− | + | [[Fichier:reset_2.jpg|400px]] | |
− | + | [[Fichier:reset_3.jpg|400px]] | |
− | + | [[Fichier:reset_1.jpg|400px]] | |
− | + | ||
Cependant, cela fonctionne lorsque j'observe le pin SCLK si la carte potentiostat, dès l'instant où la carte est connectée au microcontrôleur, le signal passe à 0, et dans ce cas, je ne peux échanger de données avec le DAC, car le signal SCLK est nécessaire pour la transmission des données. En revanche, il me semble avoir une idée sur ce problème. En reprenant la documentation, je me suis rendu compte que la fréquence SCLK que j'ai mise dans le code, autour de 2,5kHz, alors que dans la documentation, il est indiqué que la fréquence du signal d'horloge doit supérieure à 100kHz. | Cependant, cela fonctionne lorsque j'observe le pin SCLK si la carte potentiostat, dès l'instant où la carte est connectée au microcontrôleur, le signal passe à 0, et dans ce cas, je ne peux échanger de données avec le DAC, car le signal SCLK est nécessaire pour la transmission des données. En revanche, il me semble avoir une idée sur ce problème. En reprenant la documentation, je me suis rendu compte que la fréquence SCLK que j'ai mise dans le code, autour de 2,5kHz, alors que dans la documentation, il est indiqué que la fréquence du signal d'horloge doit supérieure à 100kHz. | ||
+ | |||
+ | ==Semaine 12== | ||
+ | Cette semaine, j'ai continué plusieurs travaux en même temps, j'ai d'abord avancé sur le code du DAC, et par ailleurs terminé la soudure de mes composants de ma carte, en validant à chaque étape la carte. | ||
+ | |||
+ | ===AOP=== | ||
+ | Comme j'étais certain que le DAC fonctionnais, je n'arrivais seulement pas à communiquer avec celui-ci, j'ai continué la soudure des composants, en mettant de côté ce soucis. Dans la suite logique de la carte, j'ai donc soudé les différents AOP qui composent mon potentiostat. Après la soudure de U7, qui est un OPA4192, qui comporte 4 AOP différents utiles pour l'amplification de la tension en sortie du DAC, ainsi que pour le retour du potentiostat, j'ai vérifié la non présence de court-circuit et la présence des bonnes tensions lors de l'alimentation de la carte en entrées des pins V+ et V− (donc de +/-9V). Tout fonctionnait, je suis passé donc à l'autre composant qui comporte des AOP, l'OPA2192, qui lui également fonctionnait correctement à la mise sous tension. | ||
+ | |||
+ | [[Fichier:AOP_1.jpg|400px|]] | ||
+ | [[Fichier:AOP_2.jpg|400px|]] | ||
+ | |||
+ | ===MCP3550=== | ||
+ | Ensuite, j'ai soudé les deux convertisseurs ADC qui permettent de convertir le feedback analogique en valeur numérique. J'ai effectué les tests habituels ensuite, et à la mise sous tension, rien à signaler. | ||
+ | |||
+ | ===DG449=== | ||
+ | Ce composant m'a donné beaucoup de difficultés. C'est un composant assez petit et son empreinte sur la carte est mal passée à l'impression de la carte, j'ai du utiliser le cutter pour correctement délimiter les pistes arrivant au composant. Malheureusement, j'ai mal fait cette opération, et du cuivre s'est arraché de la carte. La soudure s'est révélée être une tâche difficile au final, je n'ai pas réussi à le faire. Cependant, comme le DG449 permet de sélectionner le mode de la carte entre Galvanostat∕Potentiostat, j'ai directement connecté le feedback de la boucle potentiostat à la sortie du switch. Pour résumé, j'ai shunté la partie galvanostat de la carte. | ||
+ | |||
+ | ===Puissance=== | ||
+ | Au final, après la soudure totale des composants, rien à signaler, à la mise sous tension de la carte sous 5V, la carte consomme 0.049A soit 0.24W, ce qui est intéressant dans un contexte de système embarqué. | ||
+ | Par ailleurs, j'ai emprunté la caméra thermique de M.Flamen, afin de vois si certains composants chauffaient lors de la mise sous tension, rien à signaler, si ce n'est que les AOP sont à une trentaine de degrés. | ||
+ | [[Fichier:Temperature_1.jpg|center|400px|]] | ||
+ | |||
+ | ===DAC=== | ||
+ | Je reviens sur la partie du DAC1220. La semaine dernière, je n'arrivais pas à communiquer avec lui, car dès lors que je branchais la pin SCLK à la carte, j'avais plus de signal. Après un petit test de continuité, je me suis rendu compte que c'était dû à un court-circuit. Après la résolution de ce problème en enlevant la petite pointe d'étain qui était la cause de ce souci, j'ai pu interagir avec le DAC. Comme expliqué plus haut, mon code est composé en plusieurs parties. Je commence par réinitialiser le DAC avec le pattern expliqué plus haut. Ensuite, je l'autocalibre, en écrivant sur le bon registre et en mettant les bits MD à 01. Enfin, je passe le DAC en mode normal, mais surtout en modifiant sa résolution et en passant de 20 à 16 bits. Je le fait car, lors de mes tests, j'avais des soucis lors de l'écriture sur les registres DIR, et la tension de sortie sur la pin Vout n'était pas conforme à ce que la documentation donnait. | ||
+ | Enfin, j'envoie une rampe de tension, avec la fonction suivante : | ||
+ | |||
+ | void rampe(void) | ||
+ | { | ||
+ | uint16_t i; | ||
+ | uint16_t i_msb, i_lsb; | ||
+ | for(i=0x0000; i<=0xFFFF; i=i+16) | ||
+ | { | ||
+ | i_msb = i & 0xFF00; | ||
+ | i_lsb = i & 0x00FF; | ||
+ | DAC1220_Ecrire2octet(0, i_msb>>8, i_lsb); | ||
+ | serial.printf("%x %x\n\r", i_msb>>8, i_lsb); | ||
+ | wait_ms(100); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | Par ailleurs, en m'inspirant du code déjà réalisé par les universitaires, j'ai crée les fonctions DAC1220_Ecrire2octet() & DAC1220_Ecrire3octet() qui permet d'envoyer deux ou trois octets en fonction du besoin. Le premier paramètre est l'adresse et ensuite les valeurs de octets à envoyer. | ||
+ | |||
+ | void DAC1220_Ecrire3octet(const uint8_t address, const uint8_t byte1, const uint8_t byte2, const uint8_t byte3) | ||
+ | { | ||
+ | CS1 = LOW; | ||
+ | SPIDelay(); | ||
+ | EcrireOctetSPI_DAC(64+address); | ||
+ | EcrireOctetSPI_DAC(byte1); | ||
+ | EcrireOctetSPI_DAC(byte2); | ||
+ | EcrireOctetSPI_DAC(byte3); | ||
+ | CS1= HIGH; | ||
+ | SPIDelay(); | ||
+ | } | ||
+ | |||
+ | void DAC1220_Ecrire2octet(const uint8_t address, const uint8_t byte1, const uint8_t byte2) | ||
+ | { | ||
+ | CS1 = LOW; | ||
+ | SPIDelay(); | ||
+ | EcrireOctetSPI_DAC(32+address); | ||
+ | EcrireOctetSPI_DAC(byte1); | ||
+ | EcrireOctetSPI_DAC(byte2); | ||
+ | CS1= HIGH; | ||
+ | SPIDelay(); | ||
+ | } | ||
+ | |||
+ | Au final, le DAC fonctionne parfaitement, l'étage d'amplification après le DAC, régit par U7A fonctionne également, la tension monte jusqu'a 9V en entrée de l'électrode de travail. | ||
+ | |||
+ | [[Fichier:DAC_1.jpg|left|vignette|300px|Tension en sortie du DAC, pour la conversion des octets suivants : 0xFFFF]] | ||
+ | [[Fichier:DAC_2.jpg|center|vignette|300px|Tension en sortie de l'étage d'amplification, juste après le DAC]] | ||
+ | |||
+ | ===Dummy Cell=== | ||
+ | Après m'être assuré que chaque étage fonctionnait sans court-circuit, la prochaine étape étape était de tenter de récupérer les données en sortie des convertisseurs MCP3550. Pour cela, j'ai étudié la documentation du circuit. Il fonctionne assez simplement, dès qu'une conversion est réalisée, la pin SDO, connectée au MISO du STM32 passe à un niveau logique 1 et ensuite, envoie la trame de données, le deux premiers bits du SDO étant pour informer l'arrivée des données converties. | ||
+ | |||
+ | Pour tester donc ces deux composants (les deux ADC), j'ai d'abord réalisé un petit montage d'une dummy cell, afin de voir la charge et décharge aux bornes de ce composant. Je me suis inspiré du montage trouvé dans le pdf des universitaire, document où se trouvait le montage du potentiostat également (pdf présent au début du wiki). | ||
+ | [[Fichier:Dummy_cell5.png|center|400px|]] | ||
+ | |||
+ | J'ai donc pris une capa de 1000µF, et une résistance de 1kOmh et j'ai connecté les différentes pins de sorties de ma carte, comme indiqué sur le schéma. Le montage final donnait ceci : | ||
+ | |||
+ | [[Fichier:Dummy_cell2.jpg|center|400px|]] | ||
+ | |||
+ | Lorsque j'envoyais ma trame de données au DAC, amplifié par le montage d'AOP en sortie du DAC, je voyais aux bornes de la capacité la tension à ses bornes monter avec une constante de temps proportionnelle à la valeur de la capa, comme les lois de l'électronique peuvent l'expliquer. J'ai également rajouté une résistance de 100k aux bornes de cette capacité pour voir sa décharge lorsque ma rampe de tension revenais à 0V. Et la décharge se voyait également ! | ||
+ | Le montage de la carte fonctionne ! c'est une petite victoire. | ||
+ | |||
+ | Ensuite, j'ai donc tenté de récupérer les données en sortie du MCP, en m'inspirant du code réalisé par les universitaires, qui se trouve dans le pdf. | ||
+ | |||
+ | |||
+ | uint8_t ReadByteSPI() | ||
+ | { | ||
+ | uint8_t data_byte = 0; | ||
+ | uint8_t bit_counter = 8; | ||
+ | do | ||
+ | { | ||
+ | ClockPulse(); // generate a clock pulse | ||
+ | data_byte <<= 1; // shift composed byte by 1 | ||
+ | data_byte &= 0xFE; // clear bit 0 | ||
+ | if(MISO) // is data line high | ||
+ | data_byte |= 0x01; // set bit 0 to logic 1 | ||
+ | } while (--bit_counter); // repeat until 8 bits have been acquired | ||
+ | return data_byte; | ||
+ | } | ||
+ | |||
+ | uint8_t MCP3550_Read(uint8_t *adc_data) | ||
+ | { | ||
+ | uint8_t data_ready = 0; | ||
+ | // Poll conversion status | ||
+ | CS2 = LOW; | ||
+ | SPIDelay(); | ||
+ | if(!MISO) // conversions are ready | ||
+ | { | ||
+ | *adc_data=ReadByteSPI(); | ||
+ | data_ready = 1; | ||
+ | CS2 = HIGH; | ||
+ | SPIDelay(); | ||
+ | CS2 = LOW; | ||
+ | SPIDelay(); | ||
+ | } | ||
+ | CS2 = HIGH; | ||
+ | SPIDelay(); | ||
+ | return data_ready; | ||
+ | } | ||
+ | |||
+ | void command_read_adc() | ||
+ | { | ||
+ | uint8_t data; | ||
+ | transmit_data = &data; | ||
+ | uint8_t adc_data[6]; | ||
+ | if(MCP3550_Read(adc_data)) | ||
+ | { | ||
+ | uint8_t transmit_data_length=6; | ||
+ | memcpy(transmit_data, adc_data, transmit_data_length); | ||
+ | serial.printf("%6x\n\r", *transmit_data); | ||
+ | } | ||
+ | else | ||
+ | serial.printf("Pas de valeurs converties\n\r"); | ||
+ | } | ||
+ | |||
+ | On vient lire la valeur en entrée de la pin MISO, et décaler le bit de la variable data_byte en fonction si SDO et au niveau 1 ou 0. Et ensuite, on envoie la valeur de cette variable que l'on copie via un memcpy dans une autre variable pour l'afficher sur le port série. Malheureusement, le code n'est pas très fonctionnel, j'arrive à récupérer des données, mais elles ne sont pas compatibles avec celle de la documentation. | ||
=Documents Rendus= | =Documents Rendus= | ||
+ | [[Fichier:Rapport_PierreGuigo.pdf]] |
Version actuelle datée du 8 janvier 2020 à 20:04
Sommaire
- 1 Présentation générale
- 2 Analyse du projet
- 3 Préparation du projet
- 4 Réalisation du Projet
- 5 Documents Rendus
Présentation générale
Dans les sujets proposés, j'ai décidé de prendre le projet "Capteur de niveau d'eau et de pollution" dirigé par Antoine Branquart lors de la période 2018/2019.
Le but est de reprendre le projet, d'expliquer les soucis de sa non finalisation et d'enfin mener le projet à son terme. Ce projet vise la réalisation d'un système de détection de pollution dans l'eau. En effet, la pollution provoque une mauvaise qualité de l'eau, et cela engendre près de 2 millions de morts par an dû à la maladie.
La pollution est présente sous différente formes, est difficilement détectable et parfois avec une constante de temps assez longue (Certains toxiques produisent leur effet néfaste qu'après certaines années).
Il est difficile de prévoir les épisodes de pollution (qui intervient lorsque un ou plusieurs polluant dépassent la concentration limite fixés par des seuils) car les tests sont ponctuels et nécessitent des outils coûteux dans des laboratoires, ce qui prend du temps.
Le projet vise donc la réalisation d'un capteur autonome qui permet d’éviter les épisodes de pollution et d'envoyer ses résultat à un module via un couple émetteur-récepteur radio.
Description
Lors de son projet, Antoine a commencé par la réalisation d'une carte électronique avec un potentiostat. Commençons par expliquer ce qu'est un potentiostat.
Potentiostat
Un potentiostat est un outil capable de réaliser des expériences de voltamétrie cyclique simple. C'est une méthode d’électro-analyse basée sur la mesure du flux de courant résultant de la réduction ou de l'oxydation des composés tests présents en solution (ici, dans de l’eau) sous l'effet d'une variation contrôlée de la différence de potentiel entre deux électrodes spécifiques.
Le potentiostat est composé de 3 électrodes :
- Une électrode de travail "ET" (en platine)
- Une électrode de référence "ECS" (au calomel saturé)
- Une contre électrode "CE" (en platine)
Le principe est d'imposer une différence de potentiel entre l'ET et L'ER et de mesurer le courant traversant l'ET.
Schéma de principe
Sur le schéma, on peut voir que l'AOP permet de maintenir la différence de potentiel entre la référence et l'électrode de travail, aussi proche possible du potentiel d'entrée de la source.
Objectifs
J'ai discuté avec Antoine à propos de son projet qu'il a continué au Vietnam. Là-bas il a designé une nouvelle carte différente de celle qu'il avait faite en France. Malheureusement, la carte n'était pas fonctionnelle. Il m'a conseillé de m'inspirer du montage qu'il avait vu (et routée) et que j'ai retrouvé dans un document. (lien vers le pdf : Fichier:Pot.pdf)
Le synoptique du système reste le même :
La communication entre le microcontrôleur et le potentiostat se fera de la manière suivante. Le microcontrôleur envoie les données numériques pour générer un potentiel. Ces valeurs numériques passent à travers un DAC pour générer des valeurs analogues correspondantes. Ensuite, l'amplificateur opérationnel compare cette valeur au potentiel mesuré entre le courant dans la contre électrode jusqu'à ce que la valeur mesurée soit égale à la valeur de consigne générée par le microcontrôleur via le DAC. Ensuite, le potentiel mesuré est introduit dans un ADC, pour transmettre le tout au microcontrôleur. La transmission se fait via un bus SPI et le microcontrôleur envoie les données au module radio via également un bus SPI. Les deux modules radio communiquent via le protocole LoRa.
Antoine avait fait son potentiostat sur une carte à part, je pense qu'il est possible de faire une carte de type "shield" et de brancher ça directement sur la carte du microcontrôleur.
Pour la communication entre les deux systèmes (les deux microcontrôleurs), il est judicieux d'utiliser le protocole LoRa avec les modules radios achetés pour le projet. Enfin, pour les microcontrôleurs, les cartes Nucléo qu'Antoine utilisait au début de son projet. Cependant, ces cartes souffrent d'un manque de librairies au niveau des protocoles LoRa, et une carte arduino de basse consommation sera également envisageable.
Donc, il y aura une partie de réalisation de carte, en s'inspirant du schéma trouvé sur internet. Ensuite, la réalisation du code pour la communication radio entre les deux microcontrôleurs.
Analyse du projet
Analyse de l'ancien projet
Antoine à réalisé une carte potentiostat et à également réussi une communication entre les deux modules radio qu'il a acheté au vietnam.
Cependant, les tests réalisés avec le potentiostat qu'il a réalisé au Vietnam n'étaient pas bons. Cela vient peut-être qu'il n'a pas pu tester son capteur avec un "dummy cell", petit module qui permet de tester efficacement un potentiostat. Par ailleurs, il n'a pas réussi à assembler complètement son système.
Réunion avec M.Boé
Le 19 Septembre, j'ai eu une réunion avec M.Boé. Nous avons discuté des différends points du projet.
Tout d'abord, M.Boé m'a conforté dans mon choix de réaliser le schéma suivant :
Nous avons d'abord discuté du choix du microcontrôleur. Il m'a conseillé d'enlever le PIC16F1259 du schéma et d'intégrer dans le projet une carte avec un STM32F4XXX (de STMicroElectronics) qui se programme à l'aide de Mbed OS. C'est un RTOS (Real-time Operating system) qui permet de programmer des périphériques se basant sur un processeur ARM comme avec le STM32. De plus, pour la sélection de la carte STM32, je dois choisir une carte en adéquation avec un module radio LoRa compatible, et qui se branche directement sur la carte.
Par ailleurs, nous avons également discuté du DAC et des deux ADC présents sur le schéma. Ils utilisent le protocole SPI pour échanger des données. Les auteurs du pdf dans lequel se trouve le schéma on utiliser des librairies permettant l'utilisation du SPI. Le but est donc de réécrire en partie du code afin de l'adapter à mon projet.
En outre, M.Boé m'a conseillé d'ajouter des jumpers ainsi que des "tests points", afin de pouvoir déboguer la carte la plus rapidement et simplement possible.
De surcroît, la carte potentiostat sera réalisée en type "shield" afin de la brancher plus facilement sur la carte STM et d'avoir un système le plus compact possible. Il est envisageable par la suite de réfléchir sur un autre type de microcontrôleur moins gourmand en énergie.
Liste de Matériel
En adéquation avec le schéma, je reprends les composants qui sont disposés sur le schématique :
Circuits intégrés
- LM2662 (Régulateur de tension 5V - 9V)(ref : LM2662MX/NOPB) (Lien Digikey : [1] Lien Farnell : [2]) (Quantité = 1)
- DAC1220 (Convertisseur Numérique Analogique)(ref : DAC1220E) (Lien Digikey : [3] Lien Farnell : [4]) (Quantité = 1)
- ADR421 (2.5V Reférence) (ref : ADR421ARZ) (Lien Digikey : [5] Lien Farnell : [6]) (Quantité = 1)
- MCP3550 (Convertisseur Analogique Numérique) (ref : MCP3550-50E/SN) (Lien Digikey : [7] Lien Farnell : [8] ) (Quantité = 2)
- OPA4192 (AOP) (ref : OPA4192IDR) (Lien Digikey : [9] Lien Farnell : [10] (TSSOP)] (Quantité = 1)
- OPA2192 (AOP) (ref : OPA2192IDR) (Lien Digikey : [11] Lien Farnell : [12]) (Quantité = 1)
- DG449 (Analog Switch) (ref : DG449DS-T1-E3) (Lien Digikey : [13] Lien Farnell : [14]) (Quantité = 1)
Résistances
- Résistances 1k ±1% de type 0805 (ref : RC0805FR-071KL) (Lien Digikey : [15] Lien Farnell : [16]) (Quantité = 5)
- Résistances 10k ±1% de type 0805 (ref : RC0805FR-0710KL) (Lien Digikey : [17] Lien Farnell :[18])(Quantité = 2)
- Résistance 27 ohms ±1% de type 0805 (ref : RC0805FR-0727RL) (Lien Digikey : [19] Lien Farnell : [20]) (Quantité = 1)
- Résistances 240k ±0.05% de type 0805 (ref : RG2012N-244-W-T1) (Lien Digikey : [21] Lien Farnell : [22]) (Quantité = 2)
- Résistances 75k ±0.05% de type 0805 (ref : ERA-6ARW753V) (Lien Digikey : [23] Lien Farnell : [24])(Quantité = 6)
- Résistance 10 ohms ±0.1% de type 0805 (ref : CPF0805B10RE) (Lien Digikey : [25] Lien Farnell : [26]) (Quantité = 1)
- Résistance 1k ±0.1% de type 0805 (ref : ERA-6AEB102V) (Lien Digikey : [27] Lien Farnell : [28]) (Quantité = 1)
- Résistance 100k ±0.1% de type 0805 (ref : ERA-6AEB104V) (Lien Digikey : [29] Lien Farnell : [30]) (Quantité = 1)
- Résistance 18k ±0.1% de type 0805 (ref : ERA-6AEB183V) (Lien Digikey : [31] Lien Farnell : [32]) (Quantité = 1)
- Résistance 2k ±0.1% de type 0805 (ref : ERA-6AEB202V) (Lien Digikey : [33] Lien Farnell : [34]) (Quantité = 1)
- Résistance 10M ±5% de type 0805 (ref : CRGS0805J10M) (Lien Digikey : [35] Lien Farnell : [36]) (Quantité = 2)
Capacités
- Capacité, 10µF 25V X7R 1210 (ref : GRM32DR71E106KA12L) (Lien Digikey : [37] Lien Farnell : [38] )(Quantité = 9)
- Capacité, 0.1µF 25V X7R 0805 (ref : C0805C104K3RACTU) (Lien Digikey : [39] Lien Farnell : [40]) (Quantité = 13)
- Capacité 12pF 50V NP0 0805 (ref : CL21C120JBANNNC) (Lien Digikey : [41] Lien Farnell : [42]) (Quantité = 4)
- Capacité 3300pF 50V NP0 0805 (ref : C0805C332J5GACTU) (Lien Digikey : [43] Lien Farnell : [44]) (Quantité = 1)
- Capacité 10nF 50V NP0 0805 (ref : C0805C103J5GACTU) (Lien Digikey : [45] Lien Farnell : [46]) (Quantité = 1)
- Capacité 4700pF 50V NP0 0805 (ref : C0805C472K5RACTU) (Lien Digikey : [47] Lien Farnell : [48]) (Quantité = 1)
Autres composants
- Diode Schottky Dual BAT721S SOT-23 (ref : BAT721S,215) (Lien Digikey : [49] Lien Farnell : [50]) (quantité = 2)
- LED 3mm Rouge (ref : WP710A10LSRD) (Lien Digikey : [51] Lien Farnell : [52]) (quantité = 2)
- Quartz 2.5Mhz (ref : ECS-25-S-1X) (Lien Digikey : [53] Lien Farnell (Equivalent): [54]) (quantité = 1)
- Bornier Connection Electrodes (ref : 1751277) (Lien Digikey : [55] Lien Farnell : [56]) (quantité = 1)
- Cavaliers (ref : 142270-1) (Lien Farnell : [57]) (quantité = 10)
- Connecteurs 26pins 2.54mm (ref : SSQ-126-23-F-S) (Lien Farnell : [58]) (quantité = 2)
- Pointes de test (ref : S1621-46) (Lien Farnell : [59]) (quantité :)
- Carte STM32 B-L072Z-LRWAN1 (ref : B-L072Z-LRWAN1) (Lien Farnell : [60]) (quantité = 2)
Positionnement par rapport à l'existant
Analyse du premier concurrent
Analyse du second concurrent
Scénario d'usage du produit ou du concept envisagé
Réponse à la question difficile
Préparation du projet
Cahier des charges
Donc, après cette réunion, je peux commencer mon cahier des charges et ensuite réaliser un petit planning.
- Réalisation d'un potentiostat fonctionnel
- Communication entre le potentiostat et le STM32F4XXX fonctionnelle
- Communication entre l'emetteur et le recepteur LoRa fonctionnelle
- Assemblage fonctionnelle
Pour le planning :
- Réalisation du schématique & Routage de la carte du potentiostat
- Recherches autour du module radio & du STM32F4XXX
- Validation de la carte & Modifications
Choix techniques : matériel et logiciel
Liste des tâches à effectuer
Calendrier prévisionnel
Réalisation du Projet
Feuille d'heures
Tâche | Prélude | Heures S1 | Heures S2 | Heures S3 | Heures S4 | Heures S5 | Heures S6 | Heures S7 | Heures S8 | Heures S9 | Heures S10 | Total |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Analyse du projet | 0 |
Prologue
Semaine 1
Pour la séance du 26 septembre, j'ai commencé par réaliser des recherches à propos du protocole LoRa.
Protocole LoRa
Le protocole LoRa ou LoRaWAN(Long Range Wide-area network) permet la communication à bas débit d'objet à faible consommation d'énergie facilitant l'internet des objets. C'est un protocole crée par la startup grenobloise Cycléo et rachetée par Semtech en 2012. Ce protocole utilise une technique de modulation par étalement de spectre de type Chirp spread spectrum propriétaire appelée LoRa.
Un réseau LoRaWAN est composé d'équipements sans-fils basse consommation qui interagissent avec des serveurs applicatifs au travers de passerelles. La modulation utilisée entre les équipements et les passerelles est LoRa. La communication entre les passerelles et les serveurs est établie via le protocole IP au moyen d'un réseau de collecte Ethernet ou 3G. La topologie d'un réseau LoRaWAN est en étoile car un serveur applicatif est connecté à une multitude de passerelles elles-mêmes connectées à une multitude d'équipements.
C'est pour cela que ce protocole est parfaitement adapté aux utilisations de basse consommation d'énergie. Dans le cas de ce projet, nous pouvons imaginer le potentiostat proche d'un courant d'eau qui détermine la pollution de cette source. Ensuite, elle transmet les données collectées par le potentiostat au µC. Ce µC connecté à un module LoRa transmet à la station la plus proche, en charge de la gestion des eaux, ces données via le protocole LoRa. Ensuite, ces données sont stockées sur un serveur en attente de traitement par un opérateur.
Il est également possible d'utiliser un protocole P2P entre deux modules radio LoRa en utilisant seulement la modulation qu'offre ce protocole. Dans notre cas, nous allons nous attacher à faire communiquer deux modules radio LoRa eux-mêmes connectés à des µC STM32.
Recherche STM32
Ensuite, après avoir réalisé mes recherches à propos de ce protocole, je me suis attaché à trouver un µC de STM compatible avec des modules radio. Il existe de nombreuses combinaisons possibles. Je peux partir sur une carte de développement qui intègre directement une chip LoRa ainsi qu'un µC STM32L0 de faible consommation d'énergie. Ces cartes ont l'avantage de permettre la communication P2P entre elles, car des exemples existent directement sur Mbed.
Je peux également prendre une carte STM32F4 discovery et trouver une carte qui intègre une chip LoRa et tenter de les faire communiquer. Cependant, cette solution semble risquée.
J'ai donc trouvé une carte de développement : la carte B-L072Z-LRWAN1 (https://www.st.com/content/ccc/resource/technical/document/user_manual/group0/ac/62/15/c7/60/ac/4e/9c/DM00329995/files/DM00329995.pdf/jcr:content/translations/en.DM00329995.pdf). Cette carte est intéressante car elle intègre un module LoRa avec un µC sur la même carte. Elle est compatible Mbed, possède plusieurs bus SPI (pour permettre la communication entre le DAC et les ADC du potentiostat). Enfin, il existe des exemple de code de communication P2P entre deux cartes identiques de cette référence (https://os.mbed.com/teams/ST/code/DISCO-L072CZ-LRWAN1_LoRa_PingPong/)
Semaine 2
Etude du schéma du potentiostat
Avant de commencer la réalisation du potentiostat, il est intéressant d'étudier le schéma et les modification que je vais y apporter. (Pour repère, le schéma dont je vais parler est situé plus haut dans le wiki)
Alimentation
Pour l'alimentation, le potentiostat utilise un LM2662 qui va transformer le 5V transmis par la carte du MicroContrôleur, en 9V, afin d'alimenter les circuits intégrés commes les AOP, ou le switch DG449.
De plus, Il y a un autre circuit (ADR421) qui va permettre de fixer le Vref (2.5V) qui va être utile pour le DAC et les deux ADC.
Circuit Analogique
Le circuit analogique est rendu possible grâce aux AOP, OPA2192 & OPA4192. U7a, sur le schéma, permet de comparer la tension imposée par le microcontrôleur via le DAC à la tension de retour du potentiostat ou galvanostat selon le mode, et conduit l'électrode de travail jusqu'a ce que les deux valeurs soient égales. La résistance R5 et la capacité C24 permettent de fixer la bande passante de U7a. Les valeurs donnent une fréquence d'environ 3Khz, ce qui reste largement supérieur à la constante de temps d'une mesure, et donc ne risque pas d'avoir un impact sur la mesure.
Sur le schéma, on remarque la présence d'un relais K1. Ce relais permet d'activer l’électrode de travail lorsque le microcontrôleur envoie le signal "CELL_ON", et une Led permet de signaler la mise en route de la mesure. Comme je me base sur un microcontrôleur différent, je pense remplacer le signal de commande par un interrupteur. L'interrupteur connectera le reste du circuit à du 5V. Lorsque ça sera activé, le courant passera dans la bobine ainsi que dans la led, ce qui sera équivalent au circuit antérieur, et ainsi activer la mesure via l'électrode de travail.
Le retour du potentiostat/galvanostat est récupéré par les AOP U7b, U7d et U7c. U7d et U7b permettent d'isoler les électrodes et le reste du montage grâce à leurs grandes impédances d'entrée, et donc d'avoir aucun courant entre l'électrode SE et l'électrode RE. Les tensions récupérées sont ensuite transmises à U7c qui fonctionne en amplificateur différentiel.
Avec Vref = 2.5V et R7 = 75kOmh & R6 = 240kOmh, la différence de potentiel entre l'électrode SE et l'électrode RE qui en entrée (avant U7c) varie de -8V et +8V, et en sortie de 0-5V, ce qui permet de matcher correctement avec les entrées des deux ADC qui vont permettre de transmettre les données au microcontrôleur.
Le retour galvanique est acquis grâce aux résistances de shunt qui permettent de transformer le courant de retour en une tension équivalente. Les relais sont là pour choisir la précision du galvanostat. Dans la plus grande range, le courant est compris entre -25mA et 25mA (avec R10). U9a convertit ce courant avec l'aide de la résistance associée en une tension comprise entre 0 et 5V, idéal pour les ADC ensuite. Chaque résistance divise par 10 le courant capté et permet une meilleur précision.
Comme le galvanostat n'est pas l'objectif premier de la carte, je vais enlever les relais (qui on un certain coût) et conserver seulement la résistance R10 directement connectée à la masse.
Enfin, les signaux retournés par les électrodes et traités par les AOP U7 et U9 sont envoyés vers DG449, qui est un switch analogique. Il permet de sélectionner dans quel mode se trouve la carte. Lorsque l'entrée IN est à 0, le switch met la carte en mode potentiostat. Au contraire, si IN est à 1, on est en mode galvanostat.
Comme l'entrée IN est contrôlée par le microcontrôleur, j'ai choisi de modifier cette partie. A la place, je vais mettre deux résistance de 10MOhm et 10Mohm avec un interrupteur. Lorsque l'interrupteur sera ouvert, l'entrée IN connectée à la résistance de 10M sera forcée à 0 (la masse), et lorsque l'interrupteur sera fermé, le niveau logique 1 (5V) sera sur l'entrée IN, avec un courant limité à 0.5µA, ce qui est inférieur à l'ampérage maximum que l'entrée peut recevoir (selon la documentation). On pourra alors choisir entre le mode galvanostat ou potentiostat avec cet interrupteur.
Conversion Analogique/Numérique
Les retours Vmes et Imes sont ensuite introduits dans les deux ADC U4 et U5 qui sont des MCP3550 qui sont d'une grande précision et permettent de filtrer le bruit d'entrée. En entrée de chaque ADC, un filtre est ajouté afin de réduire le bruit et d'améliorer la conversion.
Conversion Numérique/Analogique
Le DAC reçoit du Microcontrôleur les données numériques via le bus SPI. Lors de mes recherches, j'ai trouvé des bibliothèques sur Mbed dédiées à la carte de developpement B-L072Z-LRWAN1, ce qui facilera la communication. Ensuite, le DAC envoie la tension de contrôle à U7a qui ensuite va comparer au valeur retournées par les electrodes.
Semaine 3 & 4
Réalisation Schématique
Ces semaines on été dédiées à la réalisation du schématique, basé sur la carte STM32 que j'ai sélectionnée plus haut. Il y a 3 pages sur le schématique, je vais les décrire plus en détail, mais elles sont basées sur le schématique étudié plus haut.
Page 1
Sur cette page, il y a d'abord le convertisseur 5V/+-9V qui va permettre de convertir la tension 5V transmise via le STM32 en +-9V et nécessaire pour l'alimentation des AOP. Il y a également la conversion du 5V en 2.5V pour fixer la tension Vref, nécessaire pour différents composants. Nous avons également le DAC qui connecté au microcontrôleur via le bus SPI, permet de convertir les données digitales en donnée analogique pour les transmettre au électrodes. Les deux ADC sont présents, et font le travail inverse, c'est à dire, transformer la valeur analogique retournée par la contre-électrode en valeur numérique, pour être traitée ensuite par le microcontrôleur. La modification que j'ai faite par rapport au schématique original, est l'absence des relais, que j'ai enlevé, car je les ai jugés inutiles, il y a juste une diode qui témoigne de la mise sous tension de la carte (D4).
Page 2
La seconde page apporte des nouveautées, j'ai enlevé les 3 relais qui permettaient de sélectionner le calibre sur le potentiel de retour de la contre-électrode. M.Boé m'a conseillé de mettre des cavaliers à la place, ce qui est le cas. J'ai rajouté à la fin de chaque mesure (mesure de courant ou de tension, suivant le cas où la carte est en potentiostat ou galvanostat), un "jumper" qui permettra d'observer le signal à l’oscilloscope, comme M.Boé me l'avait demandé. J'ai également rajouté un "jumper" identique jsute avant l'électrode de travail. Par ailleurs, sur le schématique originel, la sélection du mode galvanostat/potentiostat se faisait via le microcontrôleur, j'ai préférer enlever cela, et le remplacer par un interrupteur, où en position ouvert, le switch analogique sera directement relié à la masse via la résistance de pull-down et enclenchera le mode potentiostat. En revanche, lorsque l'interrupteur sera fermé, le mode galvanostat sera activé.
Page 3
Cette page concerne seulement les deux connecteurs, qui sont des connecteurs femelles 26pins qui sont standards (mais assez difficiles à trouver sur les sites de composants). Je me suis référencé à la documentation de la carte B-L072Z-LRWAN1 pour l'affectation des pins, notamment pour les pins associées au bus SPI et les 3 pins que je vais utiliser pour le chip select. In fine, j'ai décidé de l'attribution des pins suivantes :
- PB12 -> CS1 (pour le DAC)
- PB9 -> CS2 (Pour l'ADC 1)
- PB8 -> CS3 (Pour l'ADC 2)
Semaine 5& 6
Ensuite, après une réunion avec M.Boé, afin d’éclaircir quelques points, notamment sur le bus SPI et pour également valider le choix de la carte STM32, j'ai commencé à router ma carte. J'ai incorporé les demandes de M.Boé, avec les cavaliers et les "jumpers" pour pouvoir débugger la carte plus facilement. Le routage m'a pris du temps, notamment parce que je ne suis pas expert dans ce domaine, mais également parce que j'essayais de me passer de via, chose que je n'ai pas réussi à faire. Finalement, j'ai fini un premier routage, mais j'attends le retour de M.Boé, car il est évident que certaines choses sont à revoir.
Semaine 7
Cette semaine à été consacrée aux modifications sur le pcb demandées par M.Boé.
Voici la listes des modifications apportées
- Tailles des pistes supérieures à 0.3mm, elles ont étés fixées à 0.35 par la suite
- Taille de la piste d'alimentation de 5V à augmenter (1mm si possible), je l'ai fixée à 0.9 par la suite, car je n'avais pas la place nécéssaire.
- Vias percés en 0.6mm
- Quelques pistes à décaler pour les aligner
- Le quartz n'existait pas en version CMS, je l'ai donc placé sur le bottom et sera soudé à l'opposé.
- Réduction de la taille des pistes qui arrivent sur les CI, juste localement pour qu'elles soit inférieures à la taille du footprint
Par ailleurs, U8 possède un packaging assez petit, malheureusement, il n'existe pas dans un autre type de packaging, je le souderais avec la plus grande précaution possible. Ensuite, j'ai écarté la masse des piste, via les règles de clearance. Cela à engendré que toutes les masse n'étaient pas reliées entre elles. J'ai donc dû rajouter des vias pour régler ce souci. Enfin, pour indication, sur la face bottom, on aura un plan de masse et je souderais des fils pour faire les pistes. Cela ne sera d'une qualité professionnelle, mais simplifiera la création de carte pour Thierry Flamen.
Enfin, j'ai volontairement enlevé l'interrupteur qui permettait de switcher entre les deux modes du potentiostat/galvanostat. Notamment parce qu'il était cher et aussi parce que c'était assez gadget. A la place, j'ai mis un cavalier. Lorsque le cavalier est présent, la broche 6 du switch est au potentiel 1, et donc la carte est en mode galvanostat. Lorsque qu'il n'y a pas de cavalier, la broche est lié à la masse via la résistance de pull-down, et la carte est en mode potentiostat.
Semaine 8
Après la soutenance de mi-projet, j'ai pu me procurer une Carte B-L072Z-LRWAN1, la carte sur laquelle je me suis basé pour la réalisation de mon shield potentiostat. En plus de cette carte, il m'a confié également un shield I-NUCLEO-LRWAN1, shield qui lorsque connecté à une nucléo permet d'envoyer des packets LoRa. Cependant, le shield NUCLEO intègre un module LoRa SX1272, alors que la carte B-L072Z-LRWAN1 intègre un module LoRa SX1276. Un tableau résume les différences entre ces deux technologies LoRa.
Sur Mbed, il existe des librairies pour les deux types de technologies. J'ai commencé par réaliser un programme pour la carte B-L072Z-LRWAN1, car c'est elle qui possède le plus d'exemples. Dans le code, il y a plusieurs parties. La première est la déclaration des différentes variables pour le module LoRa :
#define RF_FREQUENCY 868000000 // Hz #define TX_OUTPUT_POWER 14 // 14 dBm #define LORA_BANDWIDTH 125000 // LoRa default, details in SX1276::BandwidthMap #define LORA_SPREADING_FACTOR LORA_SF7 #define LORA_CODINGRATE LORA_ERROR_CODING_RATE_4_5 #define LORA_PREAMBLE_LENGTH 6 // Same for Tx and Rx #define LORA_SYMBOL_TIMEOUT 10 // Symbols #define LORA_FIX_LENGTH_PAYLOAD_ON false #define LORA_FHSS_ENABLED false #define LORA_NB_SYMB_HOP 4 #define LORA_IQ_INVERSION_ON false #define LORA_CRC_ENABLED true #define RX_TIMEOUT_VALUE 3500 // in ms #define BUFFER_SIZE 32 // Define the payload size here
Ces variables vont nous permettre de déterminer la fréquence des paquets LoRa, la bande passante, etc...
Ensuite, nous avons les différentes initialisations :
typedef enum { SLEEP = 0, RX_INIT, RX_INIT_WAIT, RX_ENUM, RX_ENUM_WAIT, TX_PING, RX_TIMEOUT, RX_ERROR, TX_INIT, TX_INIT_WAIT, TX_ENUM, TX_ENUM_WAIT, CAD, CAD_DONE } AppStates_t;//Objet nécessaire pour l'initialisation du module LoRa ensuite DigitalOut myled1(LED1); static RadioEvents_t RadioEvents;// Initialisation d'un objet de classe RadioEvents Serial serial(SERIAL_TX, SERIAL_RX);// Initialisation d'un objet serial de classe Serial SX1276Generic *Radio;// Initialisation d'un pointeur sur un objet de classe SX1276 const uint8_t PongMsg[] = { 0xFF, 0xFF, 0xFF, 0xFF};// Message à envoyer;
Puis, dans une fonction void init() on initialise nos différends objets
//On initialise notre Objet radio Radio = new SX1276Generic(NULL, MURATA_SX1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5, LORA_ANT_RX, LORA_ANT_TX, LORA_ANT_BOOST, LORA_TCXO); //Initialisation du driver Radio RadioEvents.TxDone = OnTxDone; RadioEvents.RxDone = OnRxDone; RadioEvents.RxError = OnRxError; RadioEvents.TxTimeout = OnTxTimeout; RadioEvents.RxTimeout = OnRxTimeout; if (Radio->Init( &RadioEvents ) == false) { while(1) { serial.printf("Radio could not be detected!"); wait( 1 ); } } Radio->SetChannel(RF_FREQUENCY ); Radio->SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, LORA_CODINGRATE, LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP, LORA_IQ_INVERSION_ON, 2000 ); Radio->SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, 0, LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP, LORA_IQ_INVERSION_ON, true );
Les fonctions de RadioEvents sont importantes, car c'est ce qui permet de savoir si un paquet est correctement reçu ou envoyé.
void OnTxDone(void *radio, void *a, void *b) { Radio->Sleep( ); serial.printf( "> OnTxDone\n\r" ); } void OnRxDone(void *radio, void *a, void *b, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) { Radio->Sleep( ); serial.printf( "> OnRxDone\n\r" ); } void OnTxTimeout( void *radio, void *a, void *b) { Radio->Sleep( ); serial.printf( "> OnTxTimeout\n\r" ); } void OnRxTimeout( void *radio, void *a, void *b) { Radio->Sleep( ); serial.printf( "> OnRxTimeout\n\r" ); } void OnRxError( void *radio, void *a, void *b ) { Radio->Sleep( ); serial.printf( "> OnRxError\n\r" ); }
Par exemple, la fonction void OnTxDone(void *radio, void *a, void *b) envoie sur le port série le message "> OnTxDone". Enfin, dans la boucle principale,
while(1) { Radio->Send( (void*) PingMsg, BufferSize); serial.printf("Pong\n\r"); myled1 != myled1; // inverser état led1 }
On envoie le message Ping et si l'envoi est effectué correctement, la fonction void OnTxDone(void *radio, void *a, void *b) est appelée. Pour ajouter quelque chose de plus visuel, on fait clignoter une led à chaque envoi de paquet.
Sur le port série, on observe les messages suivants :
Ensuite, après le code d'envoi via le B-L072Z-LRWAN1, j'ai essayé de faire un code pour récupérer le paquet transmis, avec le shield Nucleo. Malheureusement, je n'y suis pas encore parvenu, et cela malgré l'envoi et la réception sur la même fréquence/Bande passante. La solution est que j'ai réussi à me procurer une autre carte B-L072Z-LRWAN1, et le code de réception sera plus simple, car utilisant la même librairie.
Semaine 9
J'ai réussi à obtenir une autre carte B-L072Z-LRWAN1, et donc la communication entre deux cartes identiques est plus simple ! Je me suis inspiré du code Ping/Pong présent sur Mbed afin de réaliser un code simple. L'envoi d'une chaîne de caractère via une carte, récupérée par l'autre, et l'afficher au port série. Le synoptique suivant résume l'ensemble du projet, afin d'améliorer la compréhension du lecteur.
En ce qui concerne le travail réalisé cette semaine, j'ai tenté la communication entre les deux cartes B-L072Z-LRWAN1. Pour le code d'envoi, j'ai gardé celui réalisé la semaine précédente, mais avec quelques ajustements qui sont les suivants :
while(1) { memcpy(Buffer, chaine, sizeof(chaine)); //On copie la chaîne de caractère chaine dans buffer wait_ms( 10 ); Radio->Send( Buffer, BufferSize );//On envoie le buffer serial.printf("%s\n\r", Buffer);//Afficher la chaîne de caractère à envoyer invert(); // inverser état led1 }
Auparavant, on initialise la variable buffer dans la fonction d'initialisation. Le code de réception est légèrement différent. L'initialisation se fait de façon similaire, cependant on utilise la fonction OnRxDone pour afficher la chaîne de caractère reçue.
void OnRxDone(void *radio, void *a, void *b, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) { serial.printf("0x%x, %d bytes\n\r", payload, size);// Affiche la valeur en hexa de la variable reçue serial.printf("> OnRxDone "); Radio->Sleep( ); BufferSize = size; memcpy(Buffer, payload, BufferSize );// On copie la variable reçue dans la variable Buffer serial.printf("RssiValue=%d dBm, SnrValue=%d, size=%d\n\r", rssi, snr, size); serial.printf("Buffer : %s\n\r", Buffer);// On affiche la chaîne de caractère if(size != BUFFER_SIZE) { Radio->Sleep( ); serial.printf("> Payload error"); return;} }
La boucle principale comporte seulement le code suivant :
while(1) { Radio->Rx(23000);//Passer la carte en mode réception pendant un temps déterminé invert();//Inverser Led }Via le port série de mon pc, j'obtiens l'image suivante :
A droite, c'est la carte qui envoie le paquet. J'envoie la chaîne de caractère "Pong", et à gauche, en plus des informations sur le signal reçu, j'affiche le message.
Semaine 10 & 11
Ces deux semaines ont étés consacrées au tirage de la carte potentiostat. J'ai envoyé les fichiers gerber validés par M.Boé à M.Flamen qui a sorti la carte. Ensuite, j'ai récupéré les composants de ma carte. En faisant le point sur les composants commandés, j'ai remarqué que j'avais oublié une capacité de découpage pour l'alimentation 5V du DAC1220E, directement sur le schematique, ce qui signifie qu'il n'y a pas l'empreinte sur la carte. Tant pis, je souderais directement entre la piste de 5V et le plan de masse, à proximité du DAC. M.Boé m'a donné des consignes pour cette partie. Il est nécessaire de souder partie par partie (Alimentation, Convertisseurs, AOP) et tester chaque partie une à une pour avancer. Cela permettra d'éviter d'endommager et de prévenir quelques problèmes.
LM2662
J'ai commencé par souder le circuit d'alimentation, car il permet de fournir le +/-9V. Pour cette partie, j'ai eu quelques problèmes, car j'ai eu un court-circuit sur la piste de 5V avec le plan de masse, ce qui était du à de la soudure qui faisait la liaison. J'ai également eu un court-circuit entre le 9V et la masse. J'ai mis une bonne heure à trouver le soucis. La piste de 9V permet d'alimenter un certain nombre de composant sur la carte, notamment le switch analogique. Celui ci possède une empreinte assez petite (SOT23-8). L'impression de la carte n'a pas été extrêmement précise, et au lieu d'avoir 8 pattes pour chaque connecteur du CI, elle étaient toutes reliées, ce qui causait ce court-circuit. Après un coup de cutter, ce problème était réglé !
Une fois les composants soudés, j'ai testé en alimentant la carte. J'ai soudés des connecteurs de fortune et relié tous mes plans de masses (les fils noirs présents sur la photo, afin d'avoir une masse uniforme). Sans charge au bout (les pistes de +/-9V n'étaient connectées à rien), ce circuit sors du -10V et du 10,5V. Sur les conseils de M.Flamen, j'ai tiré une cinquantaine de mA, histoire de voir si j'avais une grosse chute de tension. J'ai connecté une résistance de 150 Ohm sur la piste de -9V. La tension à chuté à -8,7V et à 9.5V. Le CI principal ne chauffait pas et j'ai testé sur une dizaine de minutes, histoire de voir si un défaut pouvait arriver ! J'en ai conclus que c'était correct et je suis passé à la suite.
ADR421
Ce composant permet de fixer la tension de référence nécessaire pour le bon fonctionnement des AOP. Pour cette partie j'ai soudé le composant ainsi que les quelques composants passifs. Après un traditionnel test de continuité, et vérifié qu'aucun court-circuit n'était présent, j'ai alimenté la carte, et en sortie du composant j'obtiens bien 2,5V. Cette partie fonctionne, je passe donc à la suite !
DAC1220E
Le DAC est un composant assez sensible, car il coute assez cher. Je l'ai d'abord soudé, de façon très magnanime, et ensuite les composants passifs autours, notamment le quartz de 2.5MhZ. Un petit test de continuité et ensuite une mise sous tension. Lors de la mise sous tension, je n'ai aucun court-circuit, ce qui est déjà une première victoire. Le DAC est correctement alimenté, et la prochaine étape sera de connecter la carte potentiostat au microcontrôleur, et d'envoyer des données numériques au DAC via le SPI. Cela me permettra de voir également si la carte microcontrôleur peut alimenter le potentiostat, et d'avoir un système autonome .
Programmation d'un code pour le test du DAC
On rentre dans une partie intéressante. J'ai passé la séance du vendredi 06 décembre sur l'étude de la documentation du DAC. Revenons sur ce que j'ai compris de ce composant.
Le DAC1220 est un composant avec lequel interagit via des registres. Le plus important est le registre de commande, qui est le registre qui va déterminer sur quel registre ensuite on va écrire sur les prochains octets envoyés. Le tableau ci dessous explique en détail ce registre :
On signifie dans quel registre on va écrire/lire, et surtout quel nombre d'octet on va écrire ensuite. A noter, qu'à chaque réception d'un octet (après réception sur le registre de commande), le DAC incrémente l'adresse sur laquelle on va écrire.
Par ailleurs, le DAC ne possède pas de broche pour le reset, il faut lui envoyer un pattern spécial sur la broche SCLK.
Enfin, le DAC possède un système d'autocalibration, qui s'active lorsqu'on met les bits MD du registre CMR à 01 (MD1 à 0 et MD0 à 1).
Dans la documentation, on nous explique un exemple de mise en route du DAC. Il faut d'abord réinitialiser le DAC via le pattern expliqué plus haut. Ensuite, il faut calibrer le DAC avec son principe d'autocalibration. Il est indiqué qu'il dure environ 500 millisecondes. Ensuite, on passe le DAC en mode normal, en mettant les bits MD du registre CMR à 00 (MD1 à 0 et MD0 à 0).
J'ai d'abord réalisé un code qui fait le pattern pour l'initialisation du DAC.
On initialise d'abord les pins utilisées pour la suite du code.
DigitalOut CS1(PB_12); DigitalOut MISO(PB_14); DigitalOut MOSI(PB_15); DigitalOut SCLK(PB_13);
Ensuite, on crée une horloge pour la broche SCLK, soit une horloge de 2,5kHz.
void SPIDelay() { wait_us(200); }
void ClockPulse()//Horloge de 2.5kHz { SCLK = HIGH; SPIDelay(); SCLK = LOW; SPIDelay(); }
Enfin, on crée le code qui respecte le pattern du reset.
void DAC_reset(void) { CS1=0; SPIDelay(); SCLK=HIGH; wait_us(600);//t16 SCLK = LOW; wait_us(10);//t17 SCLK = HIGH; SPIDelay(); wait_us(1100);//t18 SCLK = LOW; wait_us(10);//t17 SCLK = HIGH; wait_us(2100);//t19 SCLK = LOW; SPIDelay(); SCLK = HIGH; SPIDelay(); }
Ensuite, j'ai réalisé un code qui permet l'envoi d'un octet permettant la calibration
void DAC_Calibration(void) { CS1=LOW;//On active le DAC en mettant son chip select à 0 SPIDelay(); EcrireOctetSPI_DAC(0x24);// On envoie un octet indiquant l'écriture sur le registre CMR (le CMR High), et les deux octets suivant sont à prendre en compte EcrireOctetSPI_DAC(0x60);// Içi, je me suis inspiré du code récupéré dans le document des universitaire (pdf au début du wiki), où pour certaines version du DAC, il est nécéssaire d'activer un bit à 1. EcrireOctetSPI_DAC(0xA1);// On active l'autocalibration du DAC CS1=HIGH; SPIDelay(); }
De surcroît, pour ensuite, réaliser la conversion de valeurs numérique, en tension équivalente, on écrit dans le registre DIR, dont le tableau est le suivant :
On vient écrire un certain nombre d'octet, pour indiquer quelle tension à mettre en sortie. Le registre DIR est un resgitre à 3 octets, il faut donc indiquer en préambule qu'on souhaite envoyer trois octets. Voici le code que j'ai fais, afin de réaliser des tests :
void DAC_DIR(void) { CS1=LOW; SPIDelay(); EcrireOctetSPI_DAC(0x00);// On demande l'écriture de 3 octets sur le registre DIR, en commençant par le MSB. EcrireOctetSPI_DAC(0x00);// On fixe Vout à 0 EcrireOctetSPI_DAC(0x00);// EcrireOctetSPI_DAC(0x00);// CS1=HIGH; SPIDelay(); }
Les résultats que j'ai obtenus ne sont pas encore satisfaisant. J'ai d'abord réussi à créer le pattern de reset du DAC, comme on peut le voir sur les trois images d'oscilloscope :
Cependant, cela fonctionne lorsque j'observe le pin SCLK si la carte potentiostat, dès l'instant où la carte est connectée au microcontrôleur, le signal passe à 0, et dans ce cas, je ne peux échanger de données avec le DAC, car le signal SCLK est nécessaire pour la transmission des données. En revanche, il me semble avoir une idée sur ce problème. En reprenant la documentation, je me suis rendu compte que la fréquence SCLK que j'ai mise dans le code, autour de 2,5kHz, alors que dans la documentation, il est indiqué que la fréquence du signal d'horloge doit supérieure à 100kHz.
Semaine 12
Cette semaine, j'ai continué plusieurs travaux en même temps, j'ai d'abord avancé sur le code du DAC, et par ailleurs terminé la soudure de mes composants de ma carte, en validant à chaque étape la carte.
AOP
Comme j'étais certain que le DAC fonctionnais, je n'arrivais seulement pas à communiquer avec celui-ci, j'ai continué la soudure des composants, en mettant de côté ce soucis. Dans la suite logique de la carte, j'ai donc soudé les différents AOP qui composent mon potentiostat. Après la soudure de U7, qui est un OPA4192, qui comporte 4 AOP différents utiles pour l'amplification de la tension en sortie du DAC, ainsi que pour le retour du potentiostat, j'ai vérifié la non présence de court-circuit et la présence des bonnes tensions lors de l'alimentation de la carte en entrées des pins V+ et V− (donc de +/-9V). Tout fonctionnait, je suis passé donc à l'autre composant qui comporte des AOP, l'OPA2192, qui lui également fonctionnait correctement à la mise sous tension.
MCP3550
Ensuite, j'ai soudé les deux convertisseurs ADC qui permettent de convertir le feedback analogique en valeur numérique. J'ai effectué les tests habituels ensuite, et à la mise sous tension, rien à signaler.
DG449
Ce composant m'a donné beaucoup de difficultés. C'est un composant assez petit et son empreinte sur la carte est mal passée à l'impression de la carte, j'ai du utiliser le cutter pour correctement délimiter les pistes arrivant au composant. Malheureusement, j'ai mal fait cette opération, et du cuivre s'est arraché de la carte. La soudure s'est révélée être une tâche difficile au final, je n'ai pas réussi à le faire. Cependant, comme le DG449 permet de sélectionner le mode de la carte entre Galvanostat∕Potentiostat, j'ai directement connecté le feedback de la boucle potentiostat à la sortie du switch. Pour résumé, j'ai shunté la partie galvanostat de la carte.
Puissance
Au final, après la soudure totale des composants, rien à signaler, à la mise sous tension de la carte sous 5V, la carte consomme 0.049A soit 0.24W, ce qui est intéressant dans un contexte de système embarqué. Par ailleurs, j'ai emprunté la caméra thermique de M.Flamen, afin de vois si certains composants chauffaient lors de la mise sous tension, rien à signaler, si ce n'est que les AOP sont à une trentaine de degrés.
DAC
Je reviens sur la partie du DAC1220. La semaine dernière, je n'arrivais pas à communiquer avec lui, car dès lors que je branchais la pin SCLK à la carte, j'avais plus de signal. Après un petit test de continuité, je me suis rendu compte que c'était dû à un court-circuit. Après la résolution de ce problème en enlevant la petite pointe d'étain qui était la cause de ce souci, j'ai pu interagir avec le DAC. Comme expliqué plus haut, mon code est composé en plusieurs parties. Je commence par réinitialiser le DAC avec le pattern expliqué plus haut. Ensuite, je l'autocalibre, en écrivant sur le bon registre et en mettant les bits MD à 01. Enfin, je passe le DAC en mode normal, mais surtout en modifiant sa résolution et en passant de 20 à 16 bits. Je le fait car, lors de mes tests, j'avais des soucis lors de l'écriture sur les registres DIR, et la tension de sortie sur la pin Vout n'était pas conforme à ce que la documentation donnait. Enfin, j'envoie une rampe de tension, avec la fonction suivante :
void rampe(void) { uint16_t i; uint16_t i_msb, i_lsb; for(i=0x0000; i<=0xFFFF; i=i+16) { i_msb = i & 0xFF00; i_lsb = i & 0x00FF; DAC1220_Ecrire2octet(0, i_msb>>8, i_lsb); serial.printf("%x %x\n\r", i_msb>>8, i_lsb); wait_ms(100); } }
Par ailleurs, en m'inspirant du code déjà réalisé par les universitaires, j'ai crée les fonctions DAC1220_Ecrire2octet() & DAC1220_Ecrire3octet() qui permet d'envoyer deux ou trois octets en fonction du besoin. Le premier paramètre est l'adresse et ensuite les valeurs de octets à envoyer.
void DAC1220_Ecrire3octet(const uint8_t address, const uint8_t byte1, const uint8_t byte2, const uint8_t byte3) { CS1 = LOW; SPIDelay(); EcrireOctetSPI_DAC(64+address); EcrireOctetSPI_DAC(byte1); EcrireOctetSPI_DAC(byte2); EcrireOctetSPI_DAC(byte3); CS1= HIGH; SPIDelay(); }
void DAC1220_Ecrire2octet(const uint8_t address, const uint8_t byte1, const uint8_t byte2) { CS1 = LOW; SPIDelay(); EcrireOctetSPI_DAC(32+address); EcrireOctetSPI_DAC(byte1); EcrireOctetSPI_DAC(byte2); CS1= HIGH; SPIDelay(); }
Au final, le DAC fonctionne parfaitement, l'étage d'amplification après le DAC, régit par U7A fonctionne également, la tension monte jusqu'a 9V en entrée de l'électrode de travail.
Dummy Cell
Après m'être assuré que chaque étage fonctionnait sans court-circuit, la prochaine étape étape était de tenter de récupérer les données en sortie des convertisseurs MCP3550. Pour cela, j'ai étudié la documentation du circuit. Il fonctionne assez simplement, dès qu'une conversion est réalisée, la pin SDO, connectée au MISO du STM32 passe à un niveau logique 1 et ensuite, envoie la trame de données, le deux premiers bits du SDO étant pour informer l'arrivée des données converties.
Pour tester donc ces deux composants (les deux ADC), j'ai d'abord réalisé un petit montage d'une dummy cell, afin de voir la charge et décharge aux bornes de ce composant. Je me suis inspiré du montage trouvé dans le pdf des universitaire, document où se trouvait le montage du potentiostat également (pdf présent au début du wiki).
J'ai donc pris une capa de 1000µF, et une résistance de 1kOmh et j'ai connecté les différentes pins de sorties de ma carte, comme indiqué sur le schéma. Le montage final donnait ceci :
Lorsque j'envoyais ma trame de données au DAC, amplifié par le montage d'AOP en sortie du DAC, je voyais aux bornes de la capacité la tension à ses bornes monter avec une constante de temps proportionnelle à la valeur de la capa, comme les lois de l'électronique peuvent l'expliquer. J'ai également rajouté une résistance de 100k aux bornes de cette capacité pour voir sa décharge lorsque ma rampe de tension revenais à 0V. Et la décharge se voyait également ! Le montage de la carte fonctionne ! c'est une petite victoire.
Ensuite, j'ai donc tenté de récupérer les données en sortie du MCP, en m'inspirant du code réalisé par les universitaires, qui se trouve dans le pdf.
uint8_t ReadByteSPI() { uint8_t data_byte = 0; uint8_t bit_counter = 8; do { ClockPulse(); // generate a clock pulse data_byte <<= 1; // shift composed byte by 1 data_byte &= 0xFE; // clear bit 0 if(MISO) // is data line high data_byte |= 0x01; // set bit 0 to logic 1 } while (--bit_counter); // repeat until 8 bits have been acquired return data_byte; }
uint8_t MCP3550_Read(uint8_t *adc_data) { uint8_t data_ready = 0; // Poll conversion status CS2 = LOW; SPIDelay(); if(!MISO) // conversions are ready { *adc_data=ReadByteSPI(); data_ready = 1; CS2 = HIGH; SPIDelay(); CS2 = LOW; SPIDelay(); } CS2 = HIGH; SPIDelay(); return data_ready; }
void command_read_adc() { uint8_t data; transmit_data = &data; uint8_t adc_data[6]; if(MCP3550_Read(adc_data)) { uint8_t transmit_data_length=6; memcpy(transmit_data, adc_data, transmit_data_length); serial.printf("%6x\n\r", *transmit_data); } else serial.printf("Pas de valeurs converties\n\r"); }
On vient lire la valeur en entrée de la pin MISO, et décaler le bit de la variable data_byte en fonction si SDO et au niveau 1 ou 0. Et ensuite, on envoie la valeur de cette variable que l'on copie via un memcpy dans une autre variable pour l'afficher sur le port série. Malheureusement, le code n'est pas très fonctionnel, j'arrive à récupérer des données, mais elles ne sont pas compatibles avec celle de la documentation.