« SE4Binome2023-8 » : différence entre les versions

De projets-se.plil.fr
Aller à la navigation Aller à la recherche
m (correction orthographique)
Ligne 56 : Ligne 56 :


=== 2) Ecriture de caractères sur le port série ===
=== 2) Ecriture de caractères sur le port série ===
Tout d'abord, avant de commencer la tâche, nous savions que nous devions utiliser l'UART du microcontrolleur. De plus, la tâche d'après devait utiliser aussi l'UART. Puisque 2 tâches utilisent la même ressource, il faut implémenter un système pour savoir quelle tâche utilise la ressource. Nous avons alors utiliser une sémaphore pour chaque tâche, permettant ainsi de limiter l'accès temporairement à la ressources aux autres tâches : <syntaxhighlight lang="c">
Tout d'abord, avant de commencer la tâche, nous savions que nous devions utiliser l'UART du microcontrolleur. De plus, la tâche suivante devait utiliser aussi l'UART. Puisque 2 tâches utilisent la même ressource, il faut implémenter un système pour savoir quelle tâche utilise la ressource. Nous avons alors utiliser une sémaphore pour chaque tâche, permettant ainsi de limiter l'accès temporairement à la ressources aux autres tâches : <syntaxhighlight lang="c">
void semaphore_write(int action){
void semaphore_write(int action){
     if(action == TAKE_RESOURCE){
     if(action == TAKE_RESOURCE){
Ligne 86 : Ligne 86 :
     }
     }
}
}
</syntaxhighlight>Après avoir implémenté cette sémaphore, il nous fallait comprendre comment utiliser l'UART du microcontrôlleur. Pour cela, il faut initialiser coorectement l'UART pour pouvoir écrire et lire en série. La fonction suivante permet d'initialiser correctement l'UART : <syntaxhighlight lang="c">
</syntaxhighlight>Après avoir implémenté cette sémaphore, il fallait que nous comprenions comment utiliser l'UART du microcontrôlleur. Pour cela, il faut initialiser correctement l'UART pour pouvoir écrire et lire en série. La fonction suivante permet d'initialiser correctement l'UART : <syntaxhighlight lang="c">
void init_usart(long int speed){
void init_usart(long int speed){
     UBRR0 = FREQUENCE/((unsigned long int)speed << 4) -1;
     UBRR0 = FREQUENCE/((unsigned long int)speed << 4) -1;
Ligne 93 : Ligne 93 :
     UCSR0A &= ~(1 << U2X0);
     UCSR0A &= ~(1 << U2X0);
}
}
</syntaxhighlight>Enfin, après l'initialisation, nous pouvons réaliser la tâche utilisant les fonctions permettant d'écrire plusieurs caractères (ici "abc") sur le port série, que l'on peut observer grâce à la commande shell ''"minicom -D /dev/ttyUSB0 -b 9600".'' On utilise alors les fonctions suivantes pour écrire sur le port série :<syntaxhighlight lang="c">
</syntaxhighlight>Enfin, une fois l'initialisation réalisée, nous pouvons réaliser la tâche utilisant les fonctions permettant d'écrire plusieurs caractères (ici "abc") sur le port série, que l'on peut observer grâce à la commande shell ''"minicom -D /dev/ttyUSB0 -b 9600".'' On utilise alors les fonctions suivantes pour écrire sur le port série :<syntaxhighlight lang="c">
void serial_send(unsigned char c){
void serial_send(unsigned char c){
     loop_until_bit_is_set(UCSR0A, UDRE0);
     loop_until_bit_is_set(UCSR0A, UDRE0);
Ligne 107 : Ligne 107 :
     semaphore_write(DROP_RESOURCE);   
     semaphore_write(DROP_RESOURCE);   
}
}
</syntaxhighlight>On peut observer que la tâche fonctionne comme sur la vidéo suivante :[[Fichier:Tâche d'écriture sur le port série.mp4|vignette|On Tâche d'écriture sur le port série|centré]]
</syntaxhighlight>On peut observer que la tâche fonctionne comme sur la vidéo suivante :[[Fichier:Tâche d'écriture sur le port série.mp4|vignette|Tâche d'écriture sur le port série|centré]]


=== 3) Lecture sur le port série ===
=== 3) Lecture sur le port série ===
De la même façon que la tâche précédente, pour cette tâche nous devons lire les pressions de touches du clavier et les afficher sur le minicom. L'initialisation est déjà efféctuée et la sémaphore et la même que dans la partie précédente, nous ne la traiterons donc pas. On utilise alors les fonctions suivantes pour lire les pressions des touches du clavier, et la tâche les fait afficher ensuite : <syntaxhighlight lang="c">
De la même façon que la tâche précédente, pour cette tâche nous devons lire les pressions de touches du clavier et les afficher sur le minicom. L'initialisation est déjà efféctuée et la sémaphore et la même que dans la partie précédente, nous ne la traiterons donc pas. On utilise alors les fonctions suivantes pour lire les pressions des touches sur le clavier, et la tâche les fait afficher ensuite : <syntaxhighlight lang="c">
unsigned char serial_read(void){
unsigned char serial_read(void){
     loop_until_bit_is_set(UCSR0A, RXC0);
     loop_until_bit_is_set(UCSR0A, RXC0);
Ligne 124 : Ligne 124 :
     semaphore_read(DROP_RESOURCE);   
     semaphore_read(DROP_RESOURCE);   
}
}
</syntaxhighlight>On peut alors observer les résultat grâce à la vidéo suivante :  
</syntaxhighlight>On peut alors observer les résultats grâce à la vidéo suivante :  
[[Fichier:Tâche de lecture sur le port série.mp4|centré|vignette|Tâche de lecture sur le port série]]
[[Fichier:Tâche de lecture sur le port série.mp4|centré|vignette|Tâche de lecture sur le port série]]


Ligne 148 : Ligne 148 :
     PORTC |= (1 << CS);
     PORTC |= (1 << CS);
}
}
</syntaxhighlight>Après vérification du bon fonctionnement de notre programme, nous avons ajouté la fonction principale dans notre fichier de gestion des tâches. Nous pouvons alors voir le changment des LEDs allumées lorsque l'on appuie sur un autre caractère grâce à la vidéo suivante :
</syntaxhighlight>Après vérification du bon fonctionnement de notre programme, nous avons ajouté la fonction principale dans notre fichier de gestion des tâches. Nous pouvons alors voir le changement des LEDs allumées lorsque l'on appuie sur un autre caractère grâce à la vidéo suivante :
[[Fichier:Matrice2.mov|centré|vignette|Affichage de caractères sur la matrice]]
[[Fichier:Matrice2.mov|centré|vignette|Affichage des caractères sur la matrice]]


=== 5) Afficheur 7 segments ===
=== 5) Afficheur 7 segments ===
Ligne 167 : Ligne 167 :


=== 1) Création de la carte électronique RNDIS ===
=== 1) Création de la carte électronique RNDIS ===
Nous avons choisi de réaliser la carte réseau RNDIS car nous pensons que ce projet était aussi en lien avec nos cours de réseau et de système d'exploitation, cette carte été pour nous un moyen d'en apprendre plus sur ces aspects.
Nous avons choisi de réaliser la carte réseau RNDIS car nous pensons que ce projet était aussi en lien avec nos cours de réseau et de système d'exploitation, cette carte était pour nous un moyen d'en apprendre plus sur ces aspects.


La première chose à faire était de réaliser la carte électronique. Pour cela, des informations nous sont fournies. On sait alors que le microcontrôleur a utiliser doit avoir des capacités USB et que l'on peut utiliser soit un ATMega16u2, un ATMega32u4 ou un AT90USB suivant la mémoire que l'on veut disposer. Nous avons choisi d'utiliser un ATMega16u2 car nous en avions déjà utiliser un lors de notre projet en SE3 et nous étions plus à l'aise avec.
La première chose à faire était de réaliser la carte électronique. Pour cela, des informations nous sont fournies. On sait alors que le microcontrôleur a utiliser doit avoir des capacités USB et que l'on peut utiliser soit un ATMega16u2, un ATMega32u4 ou un AT90USB suivant la mémoire que l'on veut disposer. Nous avons choisi d'utiliser un ATMega16u2 car nous en avions déjà utiliser un lors de notre projet en SE3 et nous étions plus à l'aise avec.
Ligne 178 : Ligne 178 :
* CS ==> PB4
* CS ==> PB4


De cette façon, nous pouvons récupérer et envoyer simplement des informations depuis la carte mère. Nous avons aussi connecter des LEDs sur les ports PC4 à PC7. Les autres ports sont connectés à des testpoints. La communication RNDIS se faisant via le port USB, nous avons aussi implémenter un port USB communicant via D+ et D-. Par sécurité, nous avons aussi mis un AVR-ISP dans le cas où la programmation du microcontrôleur se fasse pas correctement. Voici alors le schéma électrique de notre carte RNDIS :
De cette façon, nous pouvons récupérer et envoyer simplement des informations depuis la carte mère. Nous avons aussi connecté des LEDs sur les ports PC4 à PC7. Les autres ports sont connectés à des testpoints. La communication RNDIS se faisant via le port USB, nous avons aussi implémenter un port USB communicant via D+ et D-. Par sécurité, nous avons aussi mis un AVR-ISP dans le cas où la programmation du microcontrôleur se fasse pas correctement. Voici alors le schéma électrique de notre carte RNDIS :
[[Fichier:Schéma électrique de la carte RNDIS.jpg|alt=Schéma électrique de la carte RNDIS|centré|vignette|234x234px|Schéma électrique de la carte RNDIS]]
[[Fichier:Schéma électrique de la carte RNDIS.jpg|alt=Schéma électrique de la carte RNDIS|centré|vignette|234x234px|Schéma électrique de la carte RNDIS]]
Après avoir fais le schéma électrique, nous avons fait le routage de la carte. Le routage était simple, nous avons commencé par router les parties USB et microcontôleur car nous savons comment elles doivent êtres disposées. Le plus difficile dans ce routage a été de mettre le capacités les plus proches du quartz et du microcontôleur car nous avons essayé de faire une carte compacte, et les testpoints prennent beaucoup de place sur la carte. Il fallait donc être précis sur la disposition des composants. Il fallait aussi faire attention à ce que les pistes D+ et D- soient les plus courtes et avec le moins de via possibles pour ne pas endommager les signaux qu' l'on va envoyer. Nous avons fait le plan de masse de la carte et au final nous avons réussi à compacter la carte pour qu'elle fasse une taille de 33mm x 43mm. Voici alors le routage de notre carte RNDIS.
Après avoir réalisé le schéma électrique, nous avons fait le routage de la carte. Le routage était simple, nous avons commencé par router les parties USB et microcontôleur car nous savons comment elles doivent êtres disposées. Le plus difficile dans ce routage a été de mettre le capacités les plus proches du quartz et du microcontôleur car nous avons essayé de faire une carte compacte, et les testpoints prennent beaucoup de place sur la carte. Il fallait donc être précis sur la disposition des composants. Il fallait aussi faire attention à ce que les pistes D+ et D- soient les plus courtes et avec le moins de via possibles pour ne pas endommager les signaux que l'on souhaite envoyer. Nous avons fait le plan de masse de la carte et au final nous avons réussi à compacter la carte pour qu'elle fasse une taille de 33mm x 43mm. Voici alors le routage de notre carte RNDIS.
[[Fichier:Routage de la carte RNDIS.jpg|alt=Routage de la carte RNDIS|centré|vignette|245x245px|Routage de la carte RNDIS]]
[[Fichier:Routage de la carte RNDIS.jpg|alt=Routage de la carte RNDIS|centré|vignette|245x245px|Routage de la carte RNDIS]]
Voici donc une réprésentation 3D de notre carte RNDIS :
Voici donc une réprésentation 3D de notre carte RNDIS :
[[Fichier:Représentation 3D de notre carte RNDIS.jpg|alt=Représentation 3D de notre carte RNDIS|centré|vignette|Représentation 3D de notre carte RNDIS]]
[[Fichier:Représentation 3D de notre carte RNDIS.jpg|alt=Représentation 3D de notre carte RNDIS|centré|vignette|Représentation 3D de notre carte RNDIS]]
Nous avons alors router notre carte, il fallait donc faire un fichier ZIP à partir de ces fichiers afin que la carte puisse être envoyée en production pour que l'on puisse souder les composants par la suite. Nous avons donc suivi les étapes de ce tutoriel : ''https://jlcpcb.com/help/article/16-How-to-generate-Gerber-and-Drill-files-in-KiCad-6''.  
Nous avons alors routé notre carte, il fallait donc faire un fichier ZIP à partir de ces fichiers afin que la carte puisse être envoyée en production pour que l'on puisse souder les composants par la suite. Nous avons donc suivi les étapes de ce tutoriel : ''https://jlcpcb.com/help/article/16-How-to-generate-Gerber-and-Drill-files-in-KiCad-6''.  


=== 2) Soudure de la carte électronique RNDIS ===
=== 2) Soudure de la carte électronique RNDIS ===
Ligne 199 : Ligne 199 :
Au final, la carte est bien reconnue grâce à la commande ''"lsusb" :''  
Au final, la carte est bien reconnue grâce à la commande ''"lsusb" :''  
[[Fichier:Carte reconnue par le "lsusb".png|alt=Carte reconnue par le "lsusb"|centré|vignette|Carte reconnue par le "lsusb"]]
[[Fichier:Carte reconnue par le "lsusb".png|alt=Carte reconnue par le "lsusb"|centré|vignette|Carte reconnue par le "lsusb"]]
Après cela, nous allons commencer à programmer le programme pour avoir une communication RNDIS.
Après cela, nous allons entamé la programmation pour avoir une communication RNDIS.


=== '''3) Programmation de la carte électronique RNDIS''' ===
=== '''3) Programmation de la carte électronique RNDIS''' ===
Pour la programmation de la carte électronique RNDIS, nous avons utiliser une démonstration LUFA déjà existante qui implémente une pile TCP/IP. En faisant directement un "make", nous avons remarqué que l'espace mémoire était dépassée. En effet, notre microcontrôleur ATMega16u2 n'a que 2k de mémoire.
Pour la programmation de la carte électronique RNDIS, nous avons utilisé une démonstration LUFA déjà existante qui implémente une pile TCP/IP. En faisant directement un "make", nous avons remarqué que l'espace mémoire était dépassée. En effet, notre microcontrôleur ATMega16u2 n'a que 2k de mémoire.


Pour réduire la taille du programme, nous avons déjà réduit la taille de la trame Ethernet qui est de 1500 octets à 100 octets. Ensuite nous avons réduit la pile TCP/IP en supprimant les fichiers UDP, TCP et Webserveur qui ne nous étaient pas utiles dans le fonctionnement de notre carte. Après la commande "make", un fichier hex est bien créer mais nous avons dû changer ce fichier Makefile en conséquence pour l'adapter à notre microcontrôleur. Enfn nous avond dû changer les VendorID et les productID dans certains fichiers :
Pour réduire la taille du programme, nous avons déjà réduit la taille de la trame Ethernet qui est de 1500 octets à 100 octets. Ensuite nous avons réduit la pile TCP/IP en supprimant les fichiers UDP, TCP et Webserveur qui ne nous étaient pas utiles dans le fonctionnement de notre carte. Après la commande "make", un fichier hex est bien créé mais nous avons dû changer ce fichier Makefile en conséquence pour l'adapter à notre microcontrôleur. Enfn nous avons dû changer les VendorID et les productID dans certains fichiers :


* VendorID = 0x03EB
* VendorID = 0x03EB
Ligne 211 : Ligne 211 :
Après un upload du programme sur notre carte, nous avons réussi à obtenir une nouvelle interface réseau nommée "usb0" que l'on a pu visualiser grâce à la commande "ip a".
Après un upload du programme sur notre carte, nous avons réussi à obtenir une nouvelle interface réseau nommée "usb0" que l'on a pu visualiser grâce à la commande "ip a".
[[Fichier:Interface usb0 créée.png|alt=Interface usb0 créée|centré|vignette|397x397px|Interface usb0 créée]]
[[Fichier:Interface usb0 créée.png|alt=Interface usb0 créée|centré|vignette|397x397px|Interface usb0 créée]]
Par le suite, nous avons configuré cette nouvelle interface avec la commande "ip address add 10.0.0.100/24 dev usb0" qui lui ajoute l'adresse 10.0.0.100 et un masque de classe C qui convient à nos besoins. A présent, nous pouvons faire un ping l'addresse 10.0.0.2 pour voir si elle répond bien :   
Par le suite, nous avons configuré cette nouvelle interface avec la commande "ip address add 10.0.0.100/24 dev usb0" qui lui ajoute l'adresse 10.0.0.100 et un masque de classe C qui convient à nos besoins. A présent, nous pouvons faire un ping de l'adresse 10.0.0.2 pour voir si elle répond bien :   
[[Fichier:Ping usb0 2.png|alt=Ping vers la carte RNDIS|centré|vignette|Ping vers la carte RNDIS]]
[[Fichier:Ping usb0 2.png|alt=Ping vers la carte RNDIS|centré|vignette|Ping vers la carte RNDIS]]
Il faut maintenant recevoir les paquets envoyés et leur bonne réception sur le terminal. Pour rendre compte des paquets envoyés/reçus, nous allumons une LED à chaque ping :   
Il faut maintenant recevoir les paquets envoyés et vérifiés leur bonne réception sur le terminal. Pour rendre compte des paquets envoyés/reçus, nous allumons une LED à chaque ping :   
[[Fichier:Reception .mp4|centré|vignette]]  
[[Fichier:Reception .mp4|centré|vignette]]  


== Rendus : ==
== Rendus : ==
Lien de notre GIT : https://archives.plil.fr/ncazin/Projet_Pico_SE4.git
Lien de notre GIT : https://archives.plil.fr/ncazin/Projet_Pico_SE4.git

Version du 20 décembre 2023 à 17:31

Matériel :

Préparation de la carte Shield :

Pour la première séance de TP, nous avons dû souder des composants sur la carte Shield fournie. Nous nous sommes alors séparés, un qui faisait la soudure, et un autre préparant les câble reliant la carte Shield aux cartes filles.

Pour les câbles, nous avons comparé notre travail avec le câble de l'enseignant. Le plus dur était de savoir dans quel sens mettre les fiches HE10 femelle, un renfoncement permet heureusement de savoir le sens dans lequel insérer le câble. Après cela, le câble est un peu fragile si on tire dessus, nous avons donc replier le câble et mis un bloqueur pour augmenter sa résistance. Nous avons réalisé au total 3 câbles, donc un de plus que le nombre de base au cas où un des câbles ne fonctionne pas. Voici une photo des trois câbles :

Par la suite, nous avons dû souder une carte Shield pouvant être ajoutée à un Arduino Uno. Cette carte Shield était déjà partiellement soudée. De plus nous avons dû souder 2 connecteurs permettant la jonction avec les cartes . Voici une photo de la carte soudée :

Ordonnanceur

1) Clignotement de 2 LEDs

Nous avons commencé l'ordonnanceur avec l'objectif de faire clignoter dans un premier temps 2 LEDs, à l'aide de deux tâches statiques, avec des périodes différentes.

Pour cela, nous avons utilisé un ISR permettant de gérer plusieurs tâches en même temps. Avant cela, il y a des fonctions de gestion et de restitution des registres afin que l'ISR commence le programme avec tous les registres à 0. Nous avons utilisé le lien suivant pour nous aider : https://tvantroys.plil.fr/IMA4/system/Multitasking%20on%20an%20AVR.pdf. Ensuite, nous avons implémenté un "scheduler" avec tout d'abord une première version où nous utilisions des "_delay_ms_". Par la suite, une mise à jour de ce "scheduler" s'imposait afin de supprimer les _delay_ms_ pour que chaque tâche possède son propre délai.

void scheduler(void){
    for(int i = 0; i < MAX_TASKS; i++){
        if(tasks[i].state == SLEEPING && tasks[i].reason == DELAY){
            uint16_t time = 20;
            if(TCNT1 != 0){
                time = TCNT1 * 200 / OCR1A / 10;
                TCNT1 = 0;
            }
            tasks[i].duration = tasks[i].duration - time;
            if(tasks[i].duration <= 0) { tasks[i].state = WORKING; }
        }
    }
    
    do{
        actuel++;
        if(actuel == MAX_TASKS) { actuel = 0; }
    } while(tasks[actuel].state == SLEEPING);
}


ISR(TIMER1_COMPA_vect,ISR_NAKED){
    /* Sauvegarde du contexte de la tâche interrompue */
    portSAVE_CONTEXT();
    tasks[actuel].StackPointeur = SP;
    /* Appel à l'ordonnanceur */
    scheduler();
    /* Récupération du contexte de la tâche ré-activée */
    SP = tasks[actuel].StackPointeur;
    portRESTORE_CONTEXT();
    asm volatile ("reti");
}

Au final, nous arrivons à faire clignoter 2 LEDs avec deux périodes différentes :

2) Ecriture de caractères sur le port série

Tout d'abord, avant de commencer la tâche, nous savions que nous devions utiliser l'UART du microcontrolleur. De plus, la tâche suivante devait utiliser aussi l'UART. Puisque 2 tâches utilisent la même ressource, il faut implémenter un système pour savoir quelle tâche utilise la ressource. Nous avons alors utiliser une sémaphore pour chaque tâche, permettant ainsi de limiter l'accès temporairement à la ressources aux autres tâches :

void semaphore_write(int action){
    if(action == TAKE_RESOURCE){
        while(1){
            cli();
            
            /** Ressource Disponible */
            if(sem_writing > 0){
                sem_writing = 0;
                sei();
                break;
            }
            
            /** Ressource occupée */
            else{
                tasks[actuel].reason = WORKING;
                tasks[actuel].state = SLEEPING;
                TCNT1 = 0;
                TIMER1_COMPA_vect();
            }
        sei();
        while(sem_writing == 0);
        }
    }
    if(action == DROP_RESOURCE){
        cli();
        sem_writing = 1;
        sei();
    }
}

Après avoir implémenté cette sémaphore, il fallait que nous comprenions comment utiliser l'UART du microcontrôlleur. Pour cela, il faut initialiser correctement l'UART pour pouvoir écrire et lire en série. La fonction suivante permet d'initialiser correctement l'UART :

void init_usart(long int speed){
    UBRR0 = FREQUENCE/((unsigned long int)speed << 4) -1;
    UCSR0B = (1 << TXEN0 | 1 << RXEN0);
    UCSR0C = (1 << UCSZ01 | 1 << UCSZ00);
    UCSR0A &= ~(1 << U2X0);
}

Enfin, une fois l'initialisation réalisée, nous pouvons réaliser la tâche utilisant les fonctions permettant d'écrire plusieurs caractères (ici "abc") sur le port série, que l'on peut observer grâce à la commande shell "minicom -D /dev/ttyUSB0 -b 9600". On utilise alors les fonctions suivantes pour écrire sur le port série :

void serial_send(unsigned char c){
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
}


void serial_send_str(char chaine[]){
    semaphore_write(TAKE_RESOURCE);
    for(int i = 0; i < SIZE_CHAINE; i++){
        serial_send(chaine[i]);
    }
    semaphore_write(DROP_RESOURCE);   
}

On peut observer que la tâche fonctionne comme sur la vidéo suivante :

3) Lecture sur le port série

De la même façon que la tâche précédente, pour cette tâche nous devons lire les pressions de touches du clavier et les afficher sur le minicom. L'initialisation est déjà efféctuée et la sémaphore et la même que dans la partie précédente, nous ne la traiterons donc pas. On utilise alors les fonctions suivantes pour lire les pressions des touches sur le clavier, et la tâche les fait afficher ensuite :

unsigned char serial_read(void){
    loop_until_bit_is_set(UCSR0A, RXC0);
    return UDR0;
}


void serial_read_str(char chaine[]){
    semaphore_read(TAKE_RESOURCE);
    for(int i = 0; i < SIZE_CHAINE; i++){
        chaine[i] = serial_read();
    }
    semaphore_read(DROP_RESOURCE);   
}

On peut alors observer les résultats grâce à la vidéo suivante :

4) Matrice de LEDs

Dans cette partie, nous souhaitons gérer l'affichage d'une matrice de LEDs 8x8 grâce au SPI. Il faut alors réussir à initialiser le SPI correctement :

void SPI_MasterInit(void){
    DDRB |= (1 << MOSI) | (1 << SCK) | (1 << SS);
    DDRC |= (1 << CS);
    SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
}

Ensuite, nous avons rédiger un programme utilisé par notre tâche afin d'afficher différents caractères sur la matrice en allumant les LEDs voulues bit par bit :

void loop_matrix(char letter[8]){
    int temp;
    PORTC &= ~(1 << CS);
    for(short int i = 0; i < 8; i++){
            
        for(short int j = 0; j < 8; j++)
        {
            temp = letter[i] & (1 << j); 
            diplayLED(temp); //Envoir de chaque bit sur le SPI
        }
    }
    PORTC |= (1 << CS);
}

Après vérification du bon fonctionnement de notre programme, nous avons ajouté la fonction principale dans notre fichier de gestion des tâches. Nous pouvons alors voir le changement des LEDs allumées lorsque l'on appuie sur un autre caractère grâce à la vidéo suivante :

Affichage des caractères sur la matrice

5) Afficheur 7 segments

Pour le 7 segments, l'initialisation est différente. En effet, le 7 segments ne fonctionne qu'à une fréquence maximale de 250kHz, il faut alors modifier l'initialisation du SPI de la tâche pour le faire fonctionner en changeant le paramètre SPCR :

void SPI_MasterInit_segments(void){
    DDRB |= (1 << MOSI) | (1 << SCK) | (1 << SS);
    DDRC |= (1 << CS);
    PORTB |= (1 << SS);
    PORTC |= (1 << CS);
    SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0) | (1 << SPR1);    //SPR1 & SPR0 à 1 pour une fréquence en dessous de 250kHz (fréquence de l'afficheur 7 segments)
}

En envoyant alors la lettre appuyée sur le clavier, le 7segments convertit (si c'est posible) la lettre en segments à allumer comme nous pouvons le voir sur la vidéo suivante :

Affichage des caractères sur le 7 segments

Carte FPGA/VHDL :

Carte fille réseau RNDIS :

1) Création de la carte électronique RNDIS

Nous avons choisi de réaliser la carte réseau RNDIS car nous pensons que ce projet était aussi en lien avec nos cours de réseau et de système d'exploitation, cette carte était pour nous un moyen d'en apprendre plus sur ces aspects.

La première chose à faire était de réaliser la carte électronique. Pour cela, des informations nous sont fournies. On sait alors que le microcontrôleur a utiliser doit avoir des capacités USB et que l'on peut utiliser soit un ATMega16u2, un ATMega32u4 ou un AT90USB suivant la mémoire que l'on veut disposer. Nous avons choisi d'utiliser un ATMega16u2 car nous en avions déjà utiliser un lors de notre projet en SE3 et nous étions plus à l'aise avec.

Ensuite, nous avons commencé à faire le schéma électrique de la carte réseau. Nous avons commencé à mettre les composants pour faire fonctionner le microcontrôleur de la même façon que sur le projet de SE3. Après cela, nous avons commencé à faire les entrées et sorties. On sait que la carte va communiquer avec la carte mère via un connecteur HE10, des signaux MISO, MOSI, SCK et CS sont alors à connecter au microcontrôlleur. Nous avons choisi d'utiliser les ports suivants :

  • SCK ==> PB1
  • MOSI ==> PB2
  • MISO ==> PB3
  • CS ==> PB4

De cette façon, nous pouvons récupérer et envoyer simplement des informations depuis la carte mère. Nous avons aussi connecté des LEDs sur les ports PC4 à PC7. Les autres ports sont connectés à des testpoints. La communication RNDIS se faisant via le port USB, nous avons aussi implémenter un port USB communicant via D+ et D-. Par sécurité, nous avons aussi mis un AVR-ISP dans le cas où la programmation du microcontrôleur se fasse pas correctement. Voici alors le schéma électrique de notre carte RNDIS :

Schéma électrique de la carte RNDIS
Schéma électrique de la carte RNDIS

Après avoir réalisé le schéma électrique, nous avons fait le routage de la carte. Le routage était simple, nous avons commencé par router les parties USB et microcontôleur car nous savons comment elles doivent êtres disposées. Le plus difficile dans ce routage a été de mettre le capacités les plus proches du quartz et du microcontôleur car nous avons essayé de faire une carte compacte, et les testpoints prennent beaucoup de place sur la carte. Il fallait donc être précis sur la disposition des composants. Il fallait aussi faire attention à ce que les pistes D+ et D- soient les plus courtes et avec le moins de via possibles pour ne pas endommager les signaux que l'on souhaite envoyer. Nous avons fait le plan de masse de la carte et au final nous avons réussi à compacter la carte pour qu'elle fasse une taille de 33mm x 43mm. Voici alors le routage de notre carte RNDIS.

Routage de la carte RNDIS
Routage de la carte RNDIS

Voici donc une réprésentation 3D de notre carte RNDIS :

Représentation 3D de notre carte RNDIS
Représentation 3D de notre carte RNDIS

Nous avons alors routé notre carte, il fallait donc faire un fichier ZIP à partir de ces fichiers afin que la carte puisse être envoyée en production pour que l'on puisse souder les composants par la suite. Nous avons donc suivi les étapes de ce tutoriel : https://jlcpcb.com/help/article/16-How-to-generate-Gerber-and-Drill-files-in-KiCad-6.

2) Soudure de la carte électronique RNDIS

Durant deux séances, nous avons réalisé la soudure de la carte électronique sur laquelle nous avons été aidés pour souder le quartz ainsi que le port USB. A noter que sur la carte, deux diodes ont été enlevées au niveau de l'USB car il était impossible de la reconnaître par notre machine grâce à la commande "lsusb". Hormis les diodes à enlever, aucune difficulté n'a été relevée durant la soudure de la carte.

Au final, nous avons donc une carte électronique fonctionnelle et prête à être programmée.

Voici une photo de la carte soudée :

Carte soudée
Carte soudée

Au final, la carte est bien reconnue grâce à la commande "lsusb" :

Carte reconnue par le "lsusb"
Carte reconnue par le "lsusb"

Après cela, nous allons entamé la programmation pour avoir une communication RNDIS.

3) Programmation de la carte électronique RNDIS

Pour la programmation de la carte électronique RNDIS, nous avons utilisé une démonstration LUFA déjà existante qui implémente une pile TCP/IP. En faisant directement un "make", nous avons remarqué que l'espace mémoire était dépassée. En effet, notre microcontrôleur ATMega16u2 n'a que 2k de mémoire.

Pour réduire la taille du programme, nous avons déjà réduit la taille de la trame Ethernet qui est de 1500 octets à 100 octets. Ensuite nous avons réduit la pile TCP/IP en supprimant les fichiers UDP, TCP et Webserveur qui ne nous étaient pas utiles dans le fonctionnement de notre carte. Après la commande "make", un fichier hex est bien créé mais nous avons dû changer ce fichier Makefile en conséquence pour l'adapter à notre microcontrôleur. Enfn nous avons dû changer les VendorID et les productID dans certains fichiers :

  • VendorID = 0x03EB
  • ProductID = 0x2FEF

Après un upload du programme sur notre carte, nous avons réussi à obtenir une nouvelle interface réseau nommée "usb0" que l'on a pu visualiser grâce à la commande "ip a".

Interface usb0 créée
Interface usb0 créée

Par le suite, nous avons configuré cette nouvelle interface avec la commande "ip address add 10.0.0.100/24 dev usb0" qui lui ajoute l'adresse 10.0.0.100 et un masque de classe C qui convient à nos besoins. A présent, nous pouvons faire un ping de l'adresse 10.0.0.2 pour voir si elle répond bien :

Ping vers la carte RNDIS
Ping vers la carte RNDIS

Il faut maintenant recevoir les paquets envoyés et vérifiés leur bonne réception sur le terminal. Pour rendre compte des paquets envoyés/reçus, nous allumons une LED à chaque ping :

Rendus :

Lien de notre GIT : https://archives.plil.fr/ncazin/Projet_Pico_SE4.git