P19 Relai Ethernet Lora
Sommaire
Présentation générale du projet
Contexte du projet
L'internet des objets est un domaine en pleine croissance qui permet entre autres d'établir des interactions entre des utilisateurs et des objets connectables.
Les domaines d'applications sont diverses et variées: du contrôle des chauffages dans nos maisons en passant par les smart cities,ou encore le tracking des marchandises,..on y retrouve des dispositifs intelligents tels que des capteurs, des interfaces de communication avec d'autres dispositifs,.. Aujourd'hui plusieurs équipements embarqués voient le jour, cependant les protocoles de communication n'évoluent pas autant, entraînant donc une forte consommation d'énergie, un besoin énorme en termes de mémoire, réseau,..
Semtech,une entreprise grenobloise, crée en 19 un modem radio LoRa adapté aux besoins des objets connectés et offre une technologie de communication à faible consommation d'énergie, une longue portée(pouvant aller jusqu'à 15 km),un débit faible,..
L'actuelle main mise du privé sur les réseaux IP n'est pas forcément une bonne chose pour Internet.
Objectif du projet
L'objectif du projet est de réaliser un module autonome connectable sur une box Internet permettant de relier deux sites avec une connexion longue distance.
Cahier de charges
Le projet se déroulera en deux phases. Nous utiliserons 2 technologies: L'ethernet et la communication par radio fréquences.
Nous réaliserons d'abord un premier prototype construit autour d'un AtMega328P, d'une carte Ethernet (avec un micro-contrôleur Microchip ENC28J60), et d'un modem radio LoRa. Un connecteur USB est prévu pour l'alimentation.
Ensuite, nous réaliserons un deuxième prototype sur la base d'un module MBED équipé d'un microcontroleur 32 bits à processeur ARM Cortex M3 , du même modem LoRa.
Nous avons choisi ce processeur pour :
le fait qu'un module Ethernet PHY soit intégré; qui opère au niveau de la couche physique du modèle OSI et met en œuvre la partie de la couche physique Ethernet du 1000BASE-T, 100BASE-TX, et les normes 10BASE-T.
la vitesse du processeur très élevée,
Présence de plusieurs périphériques série
En ce qui concerne l'environnement de développement,le compilateur MBED permet d'écrire des programmes en C++ qui peuvent être compilés en ligne.
Nous comptons également utiliser le protocole PoE (Power over Ethernet) pour l'alimentation par le port Ethernet, prévoir un protocole de communication pour la transmission des paquets Ethernet par LoRa.
Suivi du projet
Semaine 1 (19/09) | Réunions avec l'encadrant de projet / Définition des objectifs / Recherche bibliographique |
---|---|
Semaine 2 (26/09) | |
Semaine 3 (03/10) | |
Semaine 4 (11/10) | Etablissement de la liste du matériel |
Semaine 5(18/10) | Etablissement de la liste du matériel |
Semaine 6(25/10) | Recherche de la librairie C pour le SX1276 |
Semaine 7(31/10) | Réalisation des schematics pour la carte1 et création des bibliothèques des composants |
Planning prévisionnel
La recherche et la documentation
Microcontrôleur Atmega328p
Atmega328p est un mono-puce microcontrôleur.
Carte Réseau
Qu'est-ce qu'une carte réseau?
La carte réseau (appelée Network Interface Card en anglais et notée NIC) constitue l'interface entre l'ordinateur et le câble du réseau. La fonction d'une carte réseau est de préparer, d'envoyer et de contrôler les données sur le réseau.
Pour préparer les données à envoyer, la carte réseau utilise un transceiver qui transforme les données parallèles en données séries. Chaque carte dispose d'une adresse unique, appelée adresse MAC, affectée par le constructeur de la carte, ce qui lui permet d'être identifiée de façon unique dans le monde parmi toutes les autres cartes réseau.
Quel est le rôle d'une carte réseau?
Une carte réseau sert d'interface physique entre l'ordinateur et le câble. Elle prépare pour le câble réseau les données émises par l'ordinateur, les transfère vers un autre ordinateur et contrôle le flux de données entre l'ordinateur et le câble. Elle traduit aussi les données venant du câble et les traduit en octets afin que l'Unité Centrale de l'ordinateur les comprenne. Ainsi une carte réseau est une carte d'extension s'insérant dans un connecteur d'extensions (slot).
Qu'est-ce qu'une carte réseau Ethernet?
La plupart des cartes réseau destinées au grand public sont des cartes Ethernet. Elles utilisent comme support de communication des paires torsadées (8 fils en cuivre), disposant à chaque extrémité de prises RJ45.
Les trois standards Ethernet (norme 802.3) les plus courants correspondent aux trois débits les plus fréquemment rencontrés : 1.Le 10Base-T permet un débit maximal de 10 Mbit/s. Le câble RJ45 peut alors mesurer jusqu'à une centaine de mètres et seuls 4 des 8 fils sont utilisés. 2.Le 100Base-TX permet un débit maximal de 100 Mbit/s. Il est également appelé Fast Ethernet et est désormais supporté par la quasi-totalité des cartes réseau. Comme pour le 10Base-T, le câble RJ45 peut alors mesurer jusqu'à une centaine de mètres et seuls 4 des 8 fils sont utilisés. 3.Le 1000Base-T permet un débit maximal de 1 000 Mbit/s. Il est également appelé Gigabit Ethernet et se démocratise rapidement. Pour que le réseau fonctionne correctement, le câble RJ45 peut toujours mesurer jusqu'à 100 m, mais doit être de bonne qualité. Cette fois, les 8 fils sont utilisés.
Ethernet Module ENC28J60
Pour la suite de notre projet, il faut une bonne connaissance du module ENC28J60. Les comportements d'enc28j60.
Il y a trois types de registres pour enc28j60: controller registre, ethernet registre et mac registre. Pour voir comment fonctionne le registre, cela contient 2+2+2 étapes, c'est à dire que l'écriture de registre et la lecture de registre, l'écriture de buffer et la lecture de buffer, l'écriture de registre PHY et la lecture de registre PHY. Les fonctions dans la librairie d'enc28j60 qui permettent de réaliser toutes ces l'écriture et la lecture sont.
Avancement du projet
Souder la carte Ethernet
Liste du matériel
Matériel | Quantité requise | Quantité disponible | A commander | Commentaires |
---|---|---|---|---|
Premier prototype (à base d'un AtMega328P) | ||||
Partie Ethernet | ||||
Résistances 49.9Ω | 10 | 10 | 10 | Farnell [1] |
Résistances 270Ω | 10 | 10 | 10 | Farnell [2] |
Résistances 2.32kΩ | 10 | 10 | 10 | Farnell [3] |
Capacités polarisation 10µF | 10 | 10 | 10 | Mouser [4] |
Capacités 0.1µF | 10 | 10 | 10 | Farnell [5] |
Capacités 20pF | 10 | 10 | 10 | Farnell [6] |
Capacités 1µF | 10 | 10 | 10 | Farnell [7] |
Puce Électronique ENC28J60SP | 3 | 3 | 3 | Farnell [8] |
Régulateur MCP1702Z | 3 | 3 | 3 | Mouser [9] |
Régulateur de tension LD1117AV33 | 3 | 3 | 3 | Mouser [10] |
Connecteur SI-50196-F | 3 | 3 | 3 | Digi-Key [11] |
Filtre BL01RN1A | 3 | 3 | 3 | Farnell [12][13] |
Quartz ECSS250XM | 2 | 2 | 2 | Mouser [14] |
Partie Arduino | ||||
Micro-contrôleur de type ATMEGA328P | 3 | 3 | 3 | Farnell [15] |
Quartz FA238 16MHz | 3 | 3 | 3 | Farnell [16] |
Résistance 1MΩ +/- 5% | 5 | 5 | 5 | Farnell [17] |
Résistance 1KΩ | 5 | 5 | 5 | Farnell [18] |
Resistances 470Ω | 10 | 10 | 10 | Farnell [19] |
Capacité 100nF | 10 | 10 | 10 | Farnell [20] |
Capacité 4.7uF | 5 | 5 | 5 | Farnell [21] |
Capacité 10uF | 5 | 5 | Farnell [22] | |
Interrupteur | 2 | 2 | 2 | Mouser [23] |
Embase USB | 2 | 2 | 2 | Farnell [24] |
FTDI FT232 BASIC | 3 | 3 | 3 | Farnell [25] MOUSER [26] |
Diode | 5 | 5 | 5 | Farnell [27] |
Regulateur 78ADJ LDO Tension fixe | 3 | 3 | 3 | Farnell [28] |
LED yellow | 3 | 3 | 3 | Farnell [29] |
LED orange | 3 | 3 | 3 | Farnell |
LED green | 3 | 3 | 3 | Farnell [30] |
LED blue | 3 | 3 | 3 | Farnell [31] |
Partie LoRa | ||||
Module radio de type RF-LORA-868-SX1276 | 4 | 4 | 4 | Mouser [32] |
Capacités 10uF | 10 | 10 | 10 | Farnell [33] |
Capacités 100nF | 20 | 20 | 20 | Farnell [34] |
20 | 20 | 20 | Farnell [35] | |
Capacités 15pF | 10 | 10 | 10 | Farnell [36] |
Capacités 10nF | 10 | 10 | 10 | Farnell [37] |
Capacités 1.5pF | 10 | 10 | 10 | Farnell [38] |
Capacités 33pF | 10 | 10 | 10 | Farnell [39] |
Capacités 4.7pF | 10 | 10 | 10 | Farnell [40] |
Capacités 1.2pF | 10 | 10 | 10 | Farnell [41] |
Capacités 1.8pF | 10 | 10 | 10 | Farnell [42] |
10 | 10 | 10 | Farnell [43] | |
Capacités 1nF | 10 | 10 | 10 | Farnell [44] |
Inductance 33nH | 10 | 10 | 10 | Farnell [45] |
Inductance 6.2nH (0402) | 10 | 10 | 10 | Farnell [46] |
Inductance 10nH | 10 | 10 | 10 | Farnell [47] |
Resistances 1KΩ | 10 | 10 | 10 | Farnell [48] |
Quartz 32MHz(16pF) | 10 | 10 | 10 | Farnell [49] |
Regulateur PE4259 | 5 | 5 | 5 | Digi-Key [50] Farnell[51] |
Deuxième prototype (à base d'un ARM-3 Cortex) | ||||
Autres cartes | ||||
32u4 RFM95 LoRa Radio - 868 or 915 MHz | 2 | 2 | 2 | Adafruit [52] |
Prototype carte developpement MBED | 2 | 2 | 2 | [53] |
Kit Board developpement MBED | 2 | 2 | 2 | [54] |
Liste du matériel
Fichier:NEWListe du matériel-IMA5-PFE19.ods
Premier prototype
La carte est composée de 3 parties principales : partie Ethernet, partie uC AtMega328P , partie LoRa.
Le rôle du micro-contrôleur est de traiter les informations qui lui parviennent , interfacer et contrôler les communications entre les périphériques.
La partie LoRa est gérée par un émetteur-recepteur SX1276 doté d'un modem LoRa de chez Semtech offrant une communication longue portée. Cette communication repose sur le principe de la modulation à étalement de spectre.
Qu'est ce qu'une modulation à étalement de spectre LoRa?
Le modem LoRa utilise une technique exclusive de modulation du spectre étalé opérant dans la bande de fréquences ISM. Cette technique est plus résistante aux interférences et au bruit dans la bande.
La modulation LoRa repose sur le même principe que la modulation DSSS( Direct Sequence Spread Spectrum) qui consiste donc à générer de la redondance d’information à chaque envoi d’une séquence de bits. Ainsi les bits reçus qui n’utilisent pas le même codage seront rejetés (dont les signaux d’interférence ou le bruit). Le récepteur peut ainsi reconnaître l’émetteur. Dans la modulation LoRa, l'étalement de spectre est obtenu en générant un signal qui varie continuellement en fréquence et occupe toute la bande passante.
// schéma
Alimentation
Pour fonctionner la carte a besoin d'alimentation.La carte fonctionnant sous une tension de 5V ,il a été convenu qu'elle sera alimentée via un port USB.
Interfaçage
Les périphériques reliés au microcontrôleur communiqueront avec ce dernier via la liaison SPI. Le bus SPI est un bus série synchrone constitué de 4 signaux logiques. SCK,MOSI,SS générés par le maître et MISO généré par l'esclave. Le maître s'occupe de la communication. Plusieurs esclaves peuvent communiquer sur le même bus à condition qu'il y ait une ligne de sélection dédiée à chaque esclave.
NB : Le uC AtMEGA328P ne disposant que d'une seule ligne de sélection SS nous sommes confrontés au problème de liaison d' un périphérique supplémentaire. Solution: Nous allons donc configurer un I/O comme un SS afin d'avoir autant de SS que de périphériques esclaves.
Fonctionnement de l'interface SPI du SX1278 :
La communication est simultanée entre un maître et un esclave. Le maître génère l'horloge et sélectionne un esclave. A chaque coup d'horloge , le maître transmet un bit à l'esclave.
MOSI est généré par le maître sur le front descendant de SCK et est échantillonné par l'esclave sur le front montant de SCK tandis que MISO est généré par l'esclave sur le bord descendant de SCK.
Le transfert est déclenché lorsque NSS est à l'état bas . MISO est alors en haute impédance lorsque NSS est à l'état haut.
- Le premier octet envoyé est l'octet d'adresse. Il comprend:
* Un bit wnr, 1 pour l'accès en écriture et 0 pour l'accès en lecture. * suivi de 7 bits d'adresse(MSB en premier).
- Le deuxième octet est un octet de données, soit envoyé sur MOSI par le maître en cas d'accès en écriture ou reçu par le maître sur MISO en cas d'accès en lecture. L'octet de données est transmis MSB en premier.
Les octets de traitement peuvent être envoyés sur MOSI (pour accès en écriture) ou reçus sur MISO (pour accès en lecture) sans un front montant du NSS et renvoyer l'adresse.
La transmission de la trame se termine lorsque NSS passe à l'état haut.
Pendant l'accès en écriture, l'octet transféré de l'esclave au maître sur la ligne MISO est la valeur de l'écriture avant l'opération d'écriture.
Transmission d'une trame SPI LoRa en mode simple accès
Machine d'états
Réalisation des cartes PCB
La carte PCB
Depuis quelques séances, nous avons commencé à réaliser notre carte PCB qui contient la partie Ethernet , Microcontrôleur et LoRa à l'aide du logiciel Altium. Dans un premier temps nous avons d'abord réalisé les librairies Altium des composants dont nous ne disposons pas. La réalisation des librairies consiste en 2 étapes : schématique et empreinte. Il s'agit donc des composants tels que : le chip SX1276, régulateur PE4259 et le connecteur SI-50196-F.
Voici leurs schématiques et footprints :
Il conviendra de préciser que quelques librairies utilisées sont disponibles et téléchargeables sur le site d'Altium Designer et peuvent être installées sur le logiciel Altium de l'école. http://techdocs.altium.com/display/ADOH/Download+Libraries
Cependant nous avons eu un problème du connecteur, puisque normalement pour les autres composants les pistes sont reliés avec les composants qui sont autours sur le schématique et le routage. Mais après avoir vu la carte que nous avons, pour la partie du connecteur il faut créer une cadre pour fixer la place du connecteur sur la carte PCB.
Parallèlement nous avons réalisé la première étape de la conception d'une carte électronique : la réalisation de la schématique. Ci-dessous les schématiques des différentes parties de la carte
Très vite, nous avons entamé la deuxième étape de la conception : le routage. En raison des contraintes de temps, nous allons d'abord produire la partie RF_LoRa afin de pouvoir avancer sur la partie programmation.
Routage du PCB
Le routage consiste à déterminer la route des signaux d'alimentation qui vont relier les composants entre eux et à placer les composants sur la carte. La carte a été conçue en respectant quelques contraintes de conception dimensionnelles :
*la valeurs théoriques de conception sont *largeur des pistes = *, * l'angle entre les pistes ne doit pas être droit, *la carte est en double face,
Réalisation de l'antenne
La carte nécessite une antenne pour la communication RF. En concevant la carte , nous avons désigné la piste reliée à l'antenne de telle sorte qu'elle soit adaptée à 50 ohms (afin d'éviter toute perte de puissance liée à la désadaptation). Nous avons donc utilisé le logiciel AppCAD en prenant en compte certains paramètres tels que le substrat utilisé, la fréquence de fonctionnement,..
La programmation
La carte sera programmée en langage C, langage de programmation modulaire.
Le langage a été choisi pour son caractère universel, sa rapidité, proche du langage machine permettant une programmation simple des microcontrôleurs,..
- Partie LoRa
semaine 07/11/2016: Ecriture des fonctions d'écriture et de lecture de l'AtMega (digitalWrite() et digitalRead()) en C qui nous permettront d'écrire les fonctions d'écriture et de lecture SPI.
semaine 14/11/2016 : Ecriture des librairies LoRa et AtMega ainsi que des fichiers de compilation.
Le programme est subdivisé en 5 parties : partie configuration des entrées sorties, partie gestion de la liaison SPI , partie gestion de la modulation LoRa ainsi que les parties gérant les modules émetteurs et récepteurs de la communication RF (Client-Server). Le programme est compilable. Nous allons d'abord faire des tests basiques sur un Arduino et ensuite nous testerons sur les modules inAir9 de chez modtronix.
Après avoir retranscrit les bibliothèques en C, nous avons tenté de faire un test. On s'est vite rendu compte que les fonctions SPI étaient mal écrites, elles ont été réécrites en utilisant les registres SPI de l'AtMega328P. Nous avons également réalisé 3 ponts diviseurs permettant de fournir des tensions supportables par les broches du modem LoRa. Cependant,
- Partie Ethernet
Pour la partie Ethernet, dans un premier temps nous avons écrit deux petits programmes pour l'émetteur et le récepteur. Voici le code pour l'émetteur
#include <stdio.h> #include <string.h> #include <avr/io.h> #include <util/delay.h> #include "serial.h" #include "spi.h" #include "enc28j60.h" #define MAX_PACKET 128 #define MAC_SIZE 6 #define TYPE_SIZE 2 unsigned char mac_sender[]={0x00,0x10,0x10,0x10,0x10,0x01}; unsigned char mac_receiver[]={0x00,0x10,0x10,0x10,0x10,0x02}; unsigned char packet_type[]={0x11,0x11}; unsigned char packet[MAX_PACKET]; int main(void]) { init_printf(); spi_init(); enc28j60Init(mac_sender); unsigned char version=enc28j60getrev(); printf("revision: %d\n",version); memcpy(packet,mac_receiver,MAC_SIZE); memcpy(packet+MAC_SIZE,mac_sender,MAC_SIZE); memcpy(packet+2*MAC_SIZE,packet_type,2); packet[2*MAC_SIZE+2]=0xaa; packet[2*MAC_SIZE+3]=0xbb; int len=2*MAC_SIZE+TYPE_SIZE+3; unsigned char count=0; while(1){ packet[2*MAC_SIZE+4]=count++; enc28j60PacketSend(len,packet); printf("Packet send size=%d\n",len); _delay_ms(1000); } return 0; }
Et le code pour le récepteur
int main(void]) { init_printf(); spi_init(); enc28j60Init(mac_receiver); unsigned char version=enc28j60getrev(); printf("revision: %d\n",version); while(1){ int size=enc28J60PacketReceive(MAX_PACKET,packet); printf("Packet received size=%d\n",size); int i,col=0; for(i=2*MAC_SIZE+TYPE_SIZE;i<size;i++){ printf("%02x",packet[i]); col++; if(col==16){ printf("\n"); col=0);} } if(col>0) printf"\n"); _delay_ms(1000); } return 0; }
Ces deux codes permettent l'émetteur et le récepteur de communiquer entre eux.
Avec le minicom, nous avons bien observé les données qui sont envoyées par l'émetteur et les données qui sont reçues par le récepteur.
Ensuite nous avons développé notre idée. Voici une image pour mieux expliqué comment cela fonctionne.
La carte ethernet1 doit arriver à recevoir des paquets ethernet du PC1 par la liaison série. Ensuite elle doit envoyer ces paquets à Arduino1 via SPI. Après l'Arduino1 va envoyer ces paquets par TX et RX. Une fois qu'Arduino2 reçoit ces paquet, il doit être capable d'envoyer des paquets à la carte ethernet2. Au final la carte ethernet2 doit envoyer toutes des données reçues à PC2. La transmission doit être bidirectionnel. Pour réussir ce but, nous avons divisé le travail en deux partie. Dans un premier temps, nous avons programmé une carte comme serveur et l'autre carte comme client. Et nous devions réaliser des taches marquées ci-dessous:
- si un paquet est reçu par le ENC28j60 alors le recopier dans le tableau Ethernet
- si un paquet est présent dans le tableau Ethernet, envoyer l'octet courant sur le port série
- si un octet arrive sur le port série le stocker dans le tableau Serie
- si le paquet dans le tableau Serie est complet, l'envoyer sur Ethernet
Lorsque nous envoyons des paquets via TX/RX donc ceux sont des paquets SLIP. Pour analyser des paquets, il faut chercher le début et la fin de la trame. Le protocole SLIP modifie le paquet IP de la manière suivante
- ajout d'un octet END afin de séparer les différents paquets
- si l'octet END est présent dans le paquet, il est remplacé par une séquence de deux octets ESC et ESC_END
- si l'octet ESC est présent dans le paquet, il est remplacé par une séquence de deux octets ESC et ESC_ESC
- une variante du protocole peut commencer et finir les paquets par l'octet END
Basé sur ce protocole, nous avons donc écrit le code ci-dessous
int main(void) { init_printf(); spi_init(); enc28j60Init(mac_receiver); //enc28j60Init(mac_sender) pour l'émetteur unsigned char version=enc28j60getrev(); printf("revision: %d\n",version); while(1){ if(nb_ethernet==0{ nb_ethernet=enc28j60PacketReceiver(MAX_BYTES,packet_ethernet); if(nb_ethernet!=0) index_ethernet=0; } if(nb_ethernet>0){ if(index_ethernet<nb_ethernet){ unsigned char c=packet_ethernet[index_ethernet++]; if(c==SLIP_END){ send_serial(SLIP_ESC); send_serial(SLIP_CODE_END); } else if(c==SLIP_ESC){ send_serial(SLIP_ESC); send_serial(SLIP_CODE_ESC); } else send_serial(c); } else{ send_serial(SLIP_END); nb_ethernet=0; } } if(serial_available()){ unsigned char c=get_serial(); if(c==SLIP_ESC){ unsigned char code=get_serial(); if(code==SLIP_CODE_END) packet_serial[nb_serial++]=SLIP_END; else if(code==SLIP_CODE_ESC) packet_serial[nb_serial++]=SLIP_ESC; } else if(c==SLIP_END){ enc28j60PacketSend(nb_serial,packet_serial); nb_serial=0; } else packet_serial[nb_serial++]=c; } } }
Ensuite pour visualiser les transmissions des données, nous avons utilisé une commande
tcpdump -vvvv -n -Xe -ieth0
Cette commande permet de savoir le type et les contenues d'un packet. Quelques options importantes pour tcpdump
- -n: tcpdump ne convertira pas les adresses et les numéros de ports en leurs noms.
- -i nom_interface : permet de choisir l'interface d'écoute.
- -v : permet d'afficher encore plus d'informations sur les paquets, il y a trois niveaux de verbosité.
- -X : affiche les paquets en hexadécimal et en ASCII.
Donc sur le terminal nous avons eu
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 11:16:32.102805 20:3d:20:30:78:30 > 4d:41:41:44:52:35, ethertype Unknown (0x0d0d), length 167: 0x0000: 0a4d 4141 4452 3420 3d20 3078 3130 0d0d .MAADR4.=.0x10.. 0x0010: 0a4d 4141 4452 3320 3d20 3078 3130 0d0d .MAADR3.=.0x10.. 0x0020: 0a4d 4141 4452 3220 3d20 3078 3130 0d0d .MAADR2.=.0x10.. 0x0030: 0a4d 4141 4452 3120 3d20 3078 3130 0d0d .MAADR1.=.0x10.. 0x0040: 0a4d 4141 4452 3020 3d20 3078 320d 0d0a .MAADR0.=.0x2... 0x0050: 7265 7669 7369 6f6e 3a20 360d 0aff ffff revision:.6..... 0x0060: ffff ff5c b901 01ed ce08 0600 0108 0006 ...\............ 0x0070: 0400 015c b901 01ed ceac 1a4f 2100 0000 ...\.......O!... 0x0080: 0000 00ac 1a4f fe00 0000 0000 0000 0000 .....O.......... 0x0090: 0000 0000 0000 0000 00 ......... 11:16:35.105084 5c:b9:01:01:ed:ce > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 60: Ethernet (len 6), IPv4 (len 4), Request who-has 172.26.79.254 tell 172.26.79.33, length 46 0x0000: 0001 0800 0604 0001 5cb9 0101 edce ac1a ........\....... 0x0010: 4f21 0000 0000 0000 ac1a 4ffe 0000 0000 O!........O..... 0x0020: 0000 0000 0000 0000 0000 0000 0000 .............. 11:16:36.102140 5c:b9:01:01:ed:ce > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 60: Ethernet (len 6), IPv4 (len 4), Request who-has 172.26.79.254 tell 172.26.79.33, length 46 0x0000: 0001 0800 0604 0001 5cb9 0101 edce ac1a ........\....... 0x0010: 4f21 0000 0000 0000 ac1a 4ffe 0000 0000 O!........O..... 0x0020: 0000 0000 0000 0000 0000 0000 0000 .............. 11:16:37.102128 5c:b9:01:01:ed:ce > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 60: Ethernet (len 6), IPv4 (len 4), Request who-has 172.26.79.254 tell 172.26.79.33, length 46 0x0000: 0001 0800 0604 0001 5cb9 0101 edce ac1a ........\....... 0x0010: 4f21 0000 0000 0000 ac1a 4ffe 0000 0000 O!........O..... 0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
Même si nous avons eu des message sur le port d'écoute mais nous avions un problème du passage d'un paquet ICMP. L'émetteur a essayé d'envoyer certaines types de paquet par exemple paquet ARP, paquet ICMP ... mais du coté de récepteur il n'a pas réussi à capter toutes les types de paquets.
Après avoir étudié le datasheet d'enc28j60, nous avons bien résolu ce problème par ajouter le registre ERXFCON dans la librairie d'enc28j60. Selon son datasheet, ce registre permets de filtrer des paquets que nous recevons. Dans la fonction qui initialise enc28j60, nous avons donc écrit
enc28j60Write(ERXFCON,0x60)
0x60 veut dire que nous mettons le 6ème et 5ème bit de ce registre en 1 et cela permet de laisser passer toutes les types de paquets. Nous avons ainsi réessayé ces deux cartes avec la nouvelle librairie et des nouveaux codes. Enfin nous avons réussit à envoyer et à recevoir des paquets ICMP et les autres genres de paquets ARP, IPV4...Nous avons refait la manipulation et nous avions des informations comme-suit
Voici le code pour cette partie
int main(void) { init_serial(115200); enc28j60Init(mac); output_init(); while(1){ if(nb_ethernet==0){ nb_ethernet=enc28j60PacketReceive(MAX_BYTES,packet_ethernet); if(nb_ethernet!=0){ index_ethernet=0; output_set(7,1); } } if((nb_ethernet>0)&&(serial_tx_available())){ if(index_ethernet<nb_ethernet){ output_set(6,1); unsigned char c=packet_ethernet[index_ethernet++]; if(c==SLIP_END){ send_serial(SLIP_ESC); send_serial(SLIP_CODE_END); } else if(c==SLIP_ESC){ send_serial(SLIP_ESC); send_serial(SLIP_CODE_ESC); } else send_serial(c); output_set(6,0); } else{ send_serial(SLIP_END); nb_ethernet=0; output_set(7,0); } } if(serial_rx_available()){ output_set(5,1); unsigned char c=get_serial(); output_set(5,0); if(c==SLIP_ESC){ output_set(5,1); unsigned char code=get_serial(); output_set(5,0); if(code==SLIP_CODE_END) packet_serial[nb_serial++]=SLIP_END; else if(code==SLIP_CODE_ESC) packet_serial[nb_serial++]=SLIP_ESC; } else if(c==SLIP_END){ enc28j60PacketSend(nb_serial,packet_serial); nb_serial=0; } else packet_serial[nb_serial++]=c; } } }
Ensuite nous avons passé en deuxième partie, au lieu d'enregistrer des paquets dans la mémoire d'Arduino nous voulions directement utiliser enc28j60 pour envoyer et recevoir des données. Pour cela nous avons changé un peu la fonction dans la librairie. A la place d'appeler la fonction enc28j60PacketSend(unsigned int len,unsigned char* packet) nous écrivions trois autres fonctions qui permettent initialiser le buffer, écrire un octet sur buffer et finalise envoyer cet octet.Voici ces 3 fonctions
//Function that initializes the Send Buffer int sendlen; void enc28j60InitializeSend(void) { // Set the write pointer to start of the transmit buffer area enc28j60Write(EWRPTL, TXSTART_INIT); enc28j60Write(EWRPTH, TXSTART_INIT>>8); sendlen = 0; enc28j60WriteByteSend(0x00); }
//Function that writes un octet in the buffer void enc28j60WriteByteSend(unsigned char byte) { enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, byte); sendlen++; }
//Function that finalizes the sending of the byte void enc28j60FinalizeSend(void) { // Set the TXND pointer to correspond to the packet size given enc28j60Write(ETXNDL, (TXSTART_INIT+sendlen)); enc28j60Write(ETXNDH, (TXSTART_INIT+sendlen)>>8); // send the contents of the transmit buffer onto the network enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); }
Donc dans le code main, nous avons écrit
int main(void) { init_serial(115200); enc28j60Init(mac); enc28j60InitializeSend(); output_init(); while(1) { if(nb_ethernet==0) { nb_ethernet=enc28j60PacketReceive(MAX_BYTES,packet_ethernet); if(nb_ethernet!=0) { index_ethernet=0; output_set(7,1); } } if((nb_ethernet>0)&&(serial_tx_available())) { if(index_ethernet<nb_ethernet) { output_set(6,1); unsigned char c=packet_ethernet[index_ethernet++]; if(c==SLIP_END){send_serial(SLIP_ESC); send_serial(SLIP_CODE_END);} else if(c==SLIP_ESC){send_serial(SLIP_ESC); send_serial(SLIP_CODE_ESC);} else send_serial(c); output_set(6,0); } else{send_serial(SLIP_END); nb_ethernet=0; output_set(7,0);} } if(serial_rx_available()) { output_set(5,1); unsigned char c=get_serial(); output_set(5,0); if(nb_serial==0) enc28j60InitializeSend(); if(c==SLIP_ESC) { output_set(5,1); unsigned char code=get_serial(); output_set(5,0); if(code==SLIP_CODE_END) { enc28j60WriteByteSend(SLIP_END); nb_serial++; } else if(code==SLIP_CODE_ESC) { enc28j60WriteByteSend(SLIP_ESC); nb_serial++; } } else if(c==SLIP_END) { enc28j60FinalizeSend(); nb_serial=0; } else { enc28j60WriteByteSend(c); nb_serial++; } } } }
Et cela marche aussi.
Nous avons aussi remplacé la fonction enc28j60PacketReceive(unsigned int maxlen, unsigned char* packet) par 3 fonctions. La première fonction permet d'initialiser le buffer de recevoir et voir s'il y a un paquet est reçu.
//Function that initializes the receive buffer unsigned int enc28j60PacketReceive(void) { uint16_t rcvlen; uint16_t rxstat; // check if a packet has been received and buffered if(enc28j60Read(EPKTCNT)==0) { return(0); } // set the read pointer to the start of the received packet enc28j60Write(ERDPTL, (NextPacketPtr)); enc28j60Write(ERDPTH, (NextPacketPtr)>>8); // read the next packet pointer NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM,0); NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM,0)<<8; // read the packet length rcvlen = enc28j60ReadOp(ENC28J60_READ_BUF_MEM,0); rcvlen |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM,0)<<8; // read the receive status rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM,0); rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM,0)<<8; return(rcvlen); }
La seconde fonction permets de lire un seul octet dans un paquet
unsigned char enc28j60ByteRead(void) { return enc28j60ReadOp(ENC28J60_READ_BUF_MEM,0); }
La troisième fonction permets de libérer le buffer
void enc28j60FreeMemory(void) { // move the RX read pointer to the start of the next received packet // this frees the memory we just read out enc28j60Write(ERXRDPTL, (NextPacketPtr)); enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8); enc28j60WriteOp(ENC28J60_BIT_FIELD_SET,ECON2,ECON2_PKTDEC); }
Donc le code principal est
int main(void) { init_serial(115200); enc28j60Init(mac); enc28j60InitializeSend(); output_init(); while(1) { if(nb_ethernet==0) { //nb_ethernet=enc28j60PacketReceive(MAX_BYTES,packet_ethernet); nb_ethernet=enc28j60PacketReceive(); if(nb_ethernet!=0) { index_ethernet=0; output_set(7,1); } } if((nb_ethernet>0)&&(serial_tx_available())) { if(index_ethernet<nb_ethernet) { output_set(6,1); unsigned char c=enc28j60ByteRead(); index_ethernet++; if(c==SLIP_END){send_serial(SLIP_ESC); send_serial(SLIP_CODE_END);} else if(c==SLIP_ESC){send_serial(SLIP_ESC); send_serial(SLIP_CODE_ESC);} else send_serial(c); output_set(6,0); } else { send_serial(SLIP_END); nb_ethernet=0; output_set(7,0); enc28j60FreeMemory(); } } if(serial_rx_available()) { output_set(5,1); unsigned char c=get_serial(); output_set(5,0); if(nb_serial==0) enc28j60InitializeSend(); if(c==SLIP_ESC) { output_set(5,1); unsigned char code=get_serial(); output_set(5,0); if(code==SLIP_CODE_END) { enc28j60WriteByteSend(SLIP_END); nb_serial++; } else if(code==SLIP_CODE_ESC) { enc28j60WriteByteSend(SLIP_ESC); nb_serial++; } } else if(c==SLIP_END) { enc28j60FinalizeSend(); nb_serial=0; } else { enc28j60WriteByteSend(c); nb_serial++; } } } }
Avec toutes ces modifications, ces deux cartes Ethernet peuvent communiquer entre eux.
- Partie Ethernet+LoRa
Pour cette partie, nous essayons de mettre toutes les cartes ensemble: enc28j60+arduino+LoRa. Les paquets que la carte ethernet reçoit doivent être envoyés à LoRa ensuite le LoRa va les envoyer à l'autre LoRa. Une fois que l'autre LoRa reçoit ces données, elles vont être envoyée à la carte ethernet. Le PC pourra traiter des données par la liaison série. Pour réussir cette idée, nous avons rencontré deux problèmes principaux
- Le choix de CS d'Arduino
- La correspondance de la taille du paquet
1). Pour le premier problème, lorsque les fonctions de SPI sont déjà définies dans les fonctions dans la librairie de l'enc28j60 au lieu d'utiliser des fonctions définies nous avons appelé directement la fonction spi_init() dans le répertoire SPI du LoRa. Ensuite nous avons changé le pin de CS de l'enc28j60 pour que les deux cartes puissent travailler une après l'autre.
2). Lorsque la longueur d'un paquet Ethernet peut atteindre 1500 octets mais la longueur maximal d'un paquet pour LoRa ne fait que 64 octets, donc nous avions le problème de correspondance de la taille du paquet. Pour résoudre ce problème nous avons fait la fragmentation. Nous avons créé un tableau de 64 octets, ensuite nous avons remplit ce tableau octet par octet du paquet. La dernière case est réservée pour dire le numéro du fragement et vérifier si c'est la fin du paquet. Au niveau de la réception, si le récepteur doit recevoir des fragments en ordre. Une fois qu'il loupe un, le récepteur va s'arrêter de capter des paquets.
Références
Datasheets
Fichier:Datasheet cartereseau.pdf
Micro-controleur Atmega328p: http://www.atmel.com/Images/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_datasheet.pdf
Documentation (Liens utiles)
https://learn.adafruit.com/adafruit-feather-32u4-radio-with-lora-radio-module/downloads
Schematic du module radio : http://modtronix.com/prod/imod/inair9/inair9_r1_sch.pdf
Schematic du mbed : https://developer.mbed.org/media/uploads/chris/lpc1768-refdesign-schematic.pdf
Carte MBED à base de microprocesseur ARM Cortex-3 : http://www.rennes.supelec.fr/ren/perso/jweiss/microp/mbed/mbed.php/
Carte MBED : http://elmicro.com/en/mbed-nxp-lpc1768.html
https://github.com/2xs/smews/tree/develop/targets/Arduino_ethernet/drivers