SE4Binome2023-8
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âbles 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
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 :
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 microcontrôleur. 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 utilisé un sémaphore pour chaque tâche, permettant ainsi de limiter l'accès temporairement à la ressource 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é ce sémaphore, il fallait que nous comprenions comment utiliser l'UART du microcontrôleur. 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 :
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à effectuée et le 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 :
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édigé 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 :
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 7 segments convertit (si c'est possible) la lettre en segments à allumer comme nous pouvons le voir sur la vidéo suivante :
Carte FPGA/VHDL :
Contrôleur de bus série SPI
Pour ce programme VHDL, nous avons voulu faire une communication SPI Maitre/Esclave. Pour cela, nous nous sommes documentés sur comment fonctionnait cette communication. Il faut alors réaliser les 4 signaux MOSI, MISO, SS et SCK afin de pouvoir communiquer. On vérifie alors chacun de bits envoyé afin de gérer les signaux de contrôle et de l'entrée MISO. Ensuite, on génère les données de sortie pour la réponse. Enfin, on peut assigner les sorties avec les informations que l'on a. Voici alors les processus utilisés :
-- Processus 1 : Gestion des signaux de contrôle et de l'entrée MISO
process (reset, start_transfer, MISO)
begin
if reset = '1' then
-- En cas de réinitialisation, retour à l'état IDLE
state <= IDLE;
bit_counter <= 0;
SS <= '1';
elsif start_transfer = '1' then
-- Au début d'une nouvelle transmission, passage à l'état TRANSFER
state <= TRANSFER;
bit_counter <= 0;
SS <= '0'; -- Sélection du périphérique esclave au début de la transmission
elsif state = TRANSFER then
-- Déplacement du bit reçu dans le tampon
received_data <= MISO & received_data(7 downto 1);
bit_counter <= bit_counter + 1;
if bit_counter = 7 then
-- Si tous les bits ont été déplacés, passage à l'état DONE
state <= DONE;
end if;
elsif state = DONE then
-- Fin de la transmission, désélection du périphérique esclave
SS <= '1';
state <= IDLE;
end if;
end process;
-- Processus 2 : Génération des données de sortie (data_out)
process (reset, start_transfer, bit_counter)
begin
if reset = '1' then
-- En cas de réinitialisation, les données de sortie sont mises à zéro
data_out <= (others => '0');
elsif start_transfer = '1' then
-- Au début d'une nouvelle transmission, envoi du premier bit
data_out <= data_out(6 downto 0) & '0';
elsif state = TRANSFER then
-- Déplacement du bit à envoyer dans le registre de sortie
data_out <= '0' & data_out(7 downto 1);
end if;
end process;
-- Assignements des sorties
transfer_done <= '1' when state = DONE else '0';
clk <= not clk after 5 ns; -- Simulation de l'horloge (pour la démo)
MOSI <= data_out(7);
data_in <= received_data;
Contrôleur VGA
Pour ce contrôleur, il faut utiliser le port VGA présent sur la carte Basys-3. Sur ce connecteur VGA, il y a plusieurs sorties à gérer. En effet, il y a les signaux de synchronisation HS et VS qui fonctionnent s'ils ont une certaine forme d'ondes. Ces signaux doivent être à 0 pendant un certain temps. De plus, nous avons les ports permettant de gérer les couleur, vert, bleu et rouge, chacun sur 4 bits. L'horloge du FPGA fonctionnant à 100MHz, nous devons la moduler à 60Hz, car l'écran fonctionne à cette fréquence. Pour cela, nous avons utilisé les IP catalogs. Ce sont des composants existants dans des librairies qui peuvent être utilisés. Dans notre cas, nous avons utilisé un composant qui permet de modifier la fréquence d’un signal.
Nous avons ensuite reconstitué le signal de HS et VS. En effet, ces signaux ont besoin d’une période très spécifique permettant de bien configurer la taille de notre écran. Nous avons donc configuré un compteur incrémenté à chaque front montant de l’horloge, ce qui permet de mettre à l’état bas nos signaux.
Le signal HS possède un front descendant à chaque changement de pixel, et lorsque que l’on a fait toute la ligne, un front descendant est envoyé sur VS pour descendre d’une ligne. Voici les programmes fait pour créer ces signaux :
Balayage : process(clk_pixel)
begin
if clk_pixel'event and clk_pixel = '1' then
-- Compteur horizontal
if compteur_horizontal < 1343 then
compteur_horizontal <= compteur_horizontal + 1;
else
compteur_horizontal <= 0;
-- Compteur vertical
if compteur_vertical < 805 then
compteur_vertical <= compteur_vertical + 1;
else
compteur_vertical <= 0;
end if;
end if;
end if;
-- Création signal HS
if compteur_horizontal > 1047 and compteur_horizontal < 1184 then
HS_out <= '0';
HS_sig <= '0';
else
HS_out <= '1';
HS_sig <= '1';
end if;
-- Création signal VS
if compteur_vertical > 770 and compteur_vertical < 777 then
VS_out <= '0';
VS_sig <= '0';
else
VS_out <= '1';
VS_sig <= '1';
end if;
Après avoir fait ces programmes, nous avons fait la simulation pour voir si les signaux étaient bien réalisés. Voici les simulations de ces signaux :
Après avoir fait cela, il fallait s’occuper des sorties des couleurs. Pour cela, nous devons mettre les valeurs des canaux de couleurs au maximum lorsque les boutons correspondants sont appuyés et quand les signaux HS et VS sont eux aussi à 1. Une condition supplémentaire permet de contrôler la taille du carré à afficher. Les programmes de gestion des couleurs étant quasiment les mêmes aux exceptions des boutons à appuyer, nous ne montrerons que celui de la couleur rouge sur l’image ci-dessous :
-- Gestion couleur rouge --
if B1_in = '1' and clk_pixel'event and clk_pixel = '1' then
if VS_sig = '1' and HS_sig = '1' then
if compteur_horizontal > 400 and compteur_horizontal < 600 then
if compteur_vertical > 200 and compteur_vertical < 400 then
red_out <= "1111";
else
red_out <= "0000";
end if;
else
red_out <= "0000";
end if;
else
red_out <= "0000";
end if;
end if;
Au final, après la génération du fichier .bit, de la modification du fichier de contrainte et de l'envoi du programme sur la carte FPGA Basys-3, nous avons bien un carré pouvant changer de couleur lorsque l'on appuie sur un bouton :
Il nous manque alors la gestion de la couleur en mémoire, mais nous n'avons pas eu le temps de réaliser cette fonction. Cependant la gestion du contrôleur VGA et de la création des signaux HS et VS nous ont beaucoup appris sur le fonctionnement du VGA.
Carte fille réseau RNDIS :
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 à 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à utilisé 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ôleur. 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émenté 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 ne se fasse pas correctement. Voici alors le schéma électrique 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 être disposées. Le plus difficile dans ce routage a été de mettre les 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 vias 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 43mm par 33mm. Voici alors le routage de notre carte RNDIS.
Voici donc une 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.
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 :
Au final, la carte est bien reconnue grâce à la commande "lsusb" :
Après cela, nous avons entamé la programmation pour avoir une communication RNDIS.
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é. 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.
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".
Par la 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 :
Il faut maintenant recevoir les paquets envoyés et vérifiés leur bonne réception sur le terminal. Nous avons alors utilisé l'outil "ether" afin d'observer les paquets reçus sur l'interface "usb0" créée. Pour rendre compte des paquets envoyés/reçus, nous allumons une LED à chaque ping :
À ce moment précis, la carte allume bien les LEDs lors de la récéption des mêmes paquets que ceux implémentés dans la pile TCP/IP. Puisque l'on veut utiliser nos propres paquets avec notre protocole, nous devons ajouter dans cette pile le traitement de notre protocole. Tout d'abord, dans le fichier "EthernerProtocols.h", nous avons créé notre propre protocole et sera le suivant : "0x0903"
#define ETHERTYPE_PICO 0x0903
Ensuite, il faut créer une structure représentant notre trame dans un fichier permettant son traitement. Ici, le fichier s'appelle "PICO.h". Nous avons alors choisi d'utiliser cette structure de trame :
/** Type define for a PICO header. */
typedef struct
{
MAC_Address_t Destination_MAC; /**< MAC address of the packet recipient */
MAC_Address_t Source_MAC; /**< MAC address of the packet source */
IP_Address_t Destination_IP; /**< IP address of the packet recipient */
IP_Address_t Source_IP; /**< IP address of the packet source */
uint16_t PICOType; /**< PICO packet sub-protocol type*/
}PICO_Header_t;
Dans le fichier c, il faut alors réaliser le traitement de cette trame pour créer la réponse :
int16_t PICO_ProcessPICOPacket(void* InDataStart,
void* OutDataStart)
{
PICO_Header_t* PICOHeaderIN = (PICO_Header_t*)InDataStart;
PICO_Header_t* PICOHeaderOUT = (PICO_Header_t*)OutDataStart;
/* Ensure that the PICO request is a PICO request packet */
if (SwapEndian_16(PICOHeaderIN->PICOType) == ETHERTYPE_PICO)
{
if (IP_COMPARE(&PICOHeaderIN->Destination_IP, &ServerIPAddress)||
MAC_COMPARE(&PICOHeaderIN->Destination_MAC, &ServerMACAddress))
{
/* Fill out the PICO response header */
PICOHeaderOUT->Destination_MAC = PICOHeaderIN->Source_MAC;
PICOHeaderOUT->Source_MAC = ServerMACAddress;
PICOHeaderOUT->Destination_IP = PICOHeaderIN->Source_IP;
PICOHeaderOUT->Source_IP = ServerIPAddress;
PICOHeaderOUT->PICOType = PICOHeaderIN->PICOType;
/* Blink the LED */
PORTC ^= 0x30;
/* Return the size of the response so far */
return sizeof(PICO_Header_t);
}
}
return NO_RESPONSE;
}
De cette façon, lorsqu'une trame respectant notre forme et utilisant notre protocole est envoyée sur l'interface, la LED de la carte devrait clignoter. Enfin, il faut aussi adapter le fichier "ProtocolsDecoders" afin que la LUFA arrive à décoder notre trame :
void DecodePICOFrameHeader(void* InDataStart)
{
PICO_Header_t* PICOHeader = (PICO_Header_t*)InDataStart;
printf_P(PSTR(" \\\r\n PICO\r\n"));
if (!(IP_COMPARE(&PICOHeader->Destination_IP, &ServerIPAddress)) &&
!(IP_COMPARE(&PICOHeader->Destination_IP, &BroadcastIPAddress)))
{
printf_P(PSTR(" + NOT ADDRESSED TO DEVICE\r\n"));
return;
}
printf_P(PSTR(" + MAC Dest: %u:%u:%u:%u:%u:%u\r\n"), PICOHeader->Destination_MAC.Octets[0],
PICOHeader->Destination_MAC.Octets[1],
PICOHeader->Destination_MAC.Octets[2],
PICOHeader->Destination_MAC.Octets[3],
PICOHeader->Destination_MAC.Octets[4],
PICOHeader->Destination_MAC.Octets[5]);
printf_P(PSTR(" + MAC Source : %u:%u:%u:%u:%u:%u\r\n"), PICOHeader->Source_MAC.Octets[0],
PICOHeader->Source_MAC.Octets[1],
PICOHeader->Source_MAC.Octets[2],
PICOHeader->Source_MAC.Octets[3],
PICOHeader->Source_MAC.Octets[4],
PICOHeader->Source_MAC.Octets[5]);
printf_P(PSTR(" + IP Dest : %u:%u:%u:%u\r\n"), PICOHeader->Destination_IP.Octets[0],
PICOHeader->Destination_IP.Octets[1],
PICOHeader->Destination_IP.Octets[2],
PICOHeader->Destination_IP.Octets[3]);
printf_P(PSTR(" + IP Source : %u:%u:%u:%u\r\n"), PICOHeader->Source_IP.Octets[0],
PICOHeader->Source_IP.Octets[1],
PICOHeader->Source_IP.Octets[2],
PICOHeader->Source_IP.Octets[3]);
printf_P(PSTR(" + Protocol : %x\r\n"), SwapEndian_16(PICOHeader->PICOType));
}
Après cela, nous pouvons envoyer une trame sur l'interface "usb0" utilisant notre protocole. Pour cela, nous avons modifié l'outil "ether" pour observer directement l'interface "usb0" et aussi pour que le filtre accepte notre protocole. En envoyant alors la trame, la LED s'allume bien correctement :
Cependant, on remarque que la LED s'allume, c'est-à-dire que la réponse est bien créée, mais elle n'est pas envoyée. En remontant chaque fonction pouvant être la cause du non-envoi de la réponse, nous avons "RNDIS_Task" que nous n'arrivons pas à comprendre. Cependant, nous n'avons pas modifié cette fonction, cela doit provenir de la trame envoyée, mais pourtant, le programme rentre bien complétement dans la fonction. À ce stade, nous n'arrivons toujours pas à trouver la cause du problème.
Conclusion :
Durant ce projet, nous avons essayé de travailler sur toutes les parties. En effet, nous avons consacré beaucoup de temps sur la partie Ordonnanceur pendant que la carte électronique était expédiée, c'est d'ailleurs comme ça que nous avons réussi à terminer toutes les tâches. Nous avons rencontré beaucoup de difficultés pendant la programmation de l'ordonnanceur, certaines tâches étaient plus compliquées pour nous que d'autres, mais nous avons réussi à nous organiser et à réaliser ces tâches. Ensuite, nous nous sommes séparés en deux, un qui travaillait sur le VHDL et l'autre sur la carte RNDIS. Du côté de la partie VHDL, la gestion du SPI était compliquée à réalisée et nous n'avons pas eu le temps de tester notre programme sur une carte FPGA. Cependant, nous avons pu tester et beaucoup mieux avancer sur le VGA. Enfin, la carte RNDIS a été compliquée à comprendre et nous avons perdu beaucoup de temps sur la réduction de la pile TCP/IP. Nous avons quand même réussi à avancer jusqu'à ce blocage sur la réponse que l'on devait recevoir.
Globalement, nous sommes contents du résultat de notre travail. Nous avons travaillé sur chaque partie comme nous le voulions afin de renforcer ou d'acquérir de nouvelles compétences. L'organisation entre nous nous a permis de gagner du temps sur notre travail. De plus, nous avons travaillé chez nous, ce qui nous permit aussi de mieux nous organiser et de mieux prévoir les séances de travail qui venaient.
Rendus :
Lien de notre GIT : https://archives.plil.fr/ncazin/Projet_Pico_SE4.git