SE4Binome2024-6
GIT
Nos codes et nos conceptions kicad sont disponibles via notre GIT : https://gitea.plil.fr/yyahiani/pico_yahiani_zongo.git
Objectif
Nous avons pour objectif, avec les trois autres binômes de notre groupe, de construire un pico-ordinateur qui intégrera plusieurs éléments essentiels. Voici les composants que nous allons inclure :
- Un processeur de type microcontrôleur : Cela constituera le cœur de notre pico-ordinateur et permettra de gérer toutes les opérations.
- Un clavier : Il permettra l'entrée de données et d'interagir facilement avec notre dispositif.
- Un dispositif d'affichage : Cela nous permettra de visualiser les informations ainsi que les résultats des opérations effectuées par notre pico-ordinateur.
- Un système d'exploitation : Il sera stocké dans la mémoire flash du microcontrôleur, garantissant un fonctionnement fluide de l'appareil.
- Une mémoire de masse : Nous prévoyons d'ajouter une mémoire de masse pour stocker davantage de données.
- Un dispositif de communication externe : Cela permettra d'interagir avec d'autres dispositifs ou réseaux.
Enfin, pour assurer la communication entre ces éléments, nous mettrons en place un bus série. Cela facilitera les échanges de données et garantira une intégration harmonieuse des composants.
Notre binôme se concentrera sur la réalisation d'une carte écran, qui devra remplir les tâches précisées dans l'énoncé du projet.
En premier lieu, nous avons d'abord réalisé un shield qui nous servira, dans le cas où la carte mère ne serait pas fonctionnelle, à tester nos cartes filles à l'aide d'un Arduino Uno pour prototyper le cœur de la carte mère.
Shield
Realisation
Nous nous sommes aidés des indications données par nos encadrants lors de la première séance pour réaliser le schéma de notre shield. Nous y avons ajouté une puce mémoire AT45DB161D, et la datasheet nous a permis de comprendre comment l'intégrer correctement dans notre schéma. Vous pouvez voir ci-dessous la version finale du routage du PCB du bouclier ainsi que ce dernier après la soudure des différents composants.
Suite à une erreur d'orientation de nos broches, connecter l'Arduino et notre bouclier est devenue une tâche bien plus "compliquée" que prévu. Cependant, grâce à une idée ingénieuse proposée par nos encadrants (M. BOE et M. REDON), nous y sommes parvenus. Le bouclier se connecte donc à l'Arduino de la manière suivante :
Tests
LEDs
Après avoir connecté notre bouclier et l'Arduino nous avons effectué les tests et constaté l'allumage des différentes LEDs; attestant du bon fonctionnement de notre bouclier.
Voici le code C (GIT : pico_yahiani_zongo/Software/codes_Shield/clignotement) qui nous permet de faire clignoter les LEDs.
Code C | Vidéo fonctionnement |
---|---|
|
Puce mémoire
Après avoir testé les LEDs, nous cherchons à tester notre puce mémoire pour assurer son bon fonctionnement. Cependant, nous avons rencontré un petit problème.
Problème
En effet, lors du test de notre puce mémoire, nous avons introduit une carte SD pour vérifier, via le logiciel Arduino, si notre puce mémoire détecte la carte SD. Cependant, cela fut sans succès. Nous avons donc vérifié l'horloge de notre Arduino Uno à l'aide d'un oscilloscope en y injectant ce code (GIT : pico_yahiani_zongo/Software/codes_Shield/test_clk_arduino) :
Code arduino | Visualisation |
---|---|
|
Le signal d'horloge de notre Arduino est correct.
Le problème ne venant pas de l'Arduino, nous avons donc dessoudé puis ressoudé notre puce mémoire et le problème à été résolu, comme vous pouvez le voir ci-dessous.
Connecteurs HE10
À l'aide d'un afficheur 7 segments, nous vérifions le bon fonctionnement des connecteurs HE10 en affichant "GrP6" pour Groupe 6. Pour cela, nous configurons la communication SPI avec avr-gcc grâce au code présent dans notre fichier spi.c, grandement inspiré du code disponible sur le site de M. Redon (https://rex.plil.fr/Enseignement/Systeme/Systeme.PSE/systeme.html). Ci-dessous, vous trouverez un aperçu du code source utilisé pour gérer la communication SPI ainsi que celui utilisé pour gérer l'affichage du 7 segments.
Configuration communication SPI | |
---|---|
| |
Code de gestion du sept segments | Image de fonctionnement |
|
Ordonnanceur
Clignotement de deux LEDS
La principale tâche à accomplir en premier lieu est de faire clignoter deux LEDs à des fréquences différentes. Pour cela nous passerons par plusieurs étapes. La première tâche à réaliser est de programmer le minuteur 1 de l'ATMega328p de sorte à ce qu'il génère une interruption toutes les 20ms. Pour cela nous nous sommes inspirés du code donné par l'un de nos encadrants (M. REDON) et avons programmé le minuteur 1 comme vous pouvez le voir dans notre Git : pico_yahiani_zongo/Software/codes_Shield/ISR_nonNue_1tache/timer.c.
Le Timer 1 est configuré en mode CTC, c'est-à-dire qu'il se réinitialise automatiquement à chaque fois qu'il atteint la valeur OCR1A. Le prescaler est configuré à 256, ce qui divise la fréquence de l'horloge système (16000000 Hz) par 256. Nous avons donc une nouvelle fréquence d'horloge à 62500 Hz, ce qui implique que les coups d'horloge (ticks) s'effectuent toutes les 16 µs. Le timer compte jusqu'à 1250 ticks, ce qui génère une interruption toutes les 20 ms.
La seconde étape consistait à faire clignoter la LED sur la broche Arduino 13 (PB5) en utilisant une ISR non nue avec notre timer. Le code suivant nous a permis de réaliser cette tâche.
Code C | Vidéo de fonctionnement |
---|---|
|
Pour passer d'une ISR non nue à une ISR naked il faut écrire les macros de sauvegardes et de restaurations des registres, ces macros sont écrites dans des fichiers présents dans notre GIT :
- pico_yahiani_zongo/Software/codes_Shield/ordo_tourni_2taches/save_registers.h
- pico_yahiani_zongo/Software/codes_Shield/ordo_tourni_2taches/restore_registers.h
Dans la suite nous avons défini nos processus comme des structures que nous avons stockées dans un tableau.
typedef struct {
void (*tache)(void);
int pile;
int etat;//wake ou sleepy (processus actif ou en attente)
}tache;
tache taches[TACHE_MAX];
Notre prochain objectif est de lancer deux tâches en parallèle en incluant un ordonnanceur à torniquet dans l'ISR. Pour cela, nous utilisons, en plus du timer présenté plus haut, une fonction d'initialisation des tâches (init_taches()) et une ISR nue, cette fois, qui gère la succession des tâches. Nous utilisons cette fois une ISR NAKED pour avoir un contrôle total sur la gestion des registres et pour éviter la surcharge des sauvegardes et/ou restaurations automatiques générées par le compilateur.
Code C | Vidéo de fonctionnement |
---|---|
|
Gestion de l'état endormi
Notre ordonnanceur est désormais capable de lancer plusieurs tâches en parallèle, nous pouvons donc passer à la gestion de l'état endormi de nos processus. Jusqu'à présent, pour effectuer des pauses dans l'exécution de nos tâches, nous utilisions la fonction _delay_ms en incluant la bibliothèque <util/delay.h>. Pour améliorer notre ordonnanceur, nous effectuons maintenant les pauses avec une fonction que nous avons écrite (_delay).
Pour l'utilisation de notre fonction, nous avons redéfini la structure des tâches à laquelle nous avons ajouté un champ "temps" représentant le temps pendant lequel la tâche reste endormie. Nous avons également écrit une fonction ordonnanceur qui décrémente le champ "temps" d'une tâche puis la réveille une fois le temps écoulé. Ci-dessous, vous pouvez voir à quoi ressemblent ces fonctions.
Code fonction ordonnanceur | Code fonction _delay |
---|---|
|
|
La nouvelle structure de tâche se presente de la façon suivante :
|
Ci-dessous, une vidéo de fonctionnement de la gestion de l'état endormi des processus. Vous pouvez voir au début de la vidéo que seule la LED verte est active (état WAKE) pendant que la LED orange est endormie. Une fois le temps d'endormissement écoulé, vous pouvez voir la LED orange commencer à clignoter (elle est passée à l'état WAKE) à la même fréquence que la LED verte.
Pour une bonne gestion de l'état endormi, nous ajoutons à notre liste de tâches une tâche _wait qui ne fait rien en bouclant juste indéfiniment. Cette dernière est importante car lorsque toutes les autres tâches de l'ordonnanceur sont inactives ou en attente, une tâche "neutre" garantit qu'il y a toujours une activité en cours, même si elle est minimale. Cela évite que le processeur tombe dans un état imprévisible ou commence à exécuter du code non souhaité.
Liste des tâches | Vidéo de fonctionnement |
---|---|
|
Gestion communication Port serie et SPI
Avec afficheur sept-segments
Notre ordonnanceur est maintenant capable de gérer le clignotement de deux LEDs en parallèle ainsi que les processus endormis. Il s'agira maintenant pour nous de le complexifier en lui permettant de gérer les communications SPI et port série. Pour ce faire, nous utilisons des codes grandement inspirés de ceux présents sur le site de M. REDON (https://rex.plil.fr/Enseignement/Systeme/Systeme.PSE/systeme.html), qui se trouvent dans les fichiers SPI.c (pour la gestion de la communication SPI) et serial.c (pour le port série).
Gestion SPI | Gestion port série |
---|---|
|
|
Les fonctions serie_envoyer et serie_recevoir comportent chacune une phase d'attente de disponibilité avec les lignes loop_until_bit_is_set(UCSR0A, UDRE0); (qui attend que le bit UDRE0 dans le registre UCSR0A soit à 1 ; ce bit indique que le registre de transmission (UDR0) est prêt à recevoir un nouvel octet) et loop_until_bit_is_set(UCSR0A, RXC0); (qui attend que le bit RXC0 dans le registre UCSR0A soit à 1 ; ce bit indique qu'un octet a été reçu via le port série et est disponible dans le registre UDR0).
Il y a ensuite une phase de transmission pour serie_envoyer avec UDR0 = c; : l'octet est chargé dans le registre UDR0. Une fois chargé, l'octet est automatiquement envoyé via le port série. Pour serie_recevoir, la phase suivante est la lecture avec return UDR0; la fonction renvoie directement le contenu du registre UDR0, qui contient l'octet reçu.
Dans le fichier serial.c (image droite ci-dessus), nous avons ajouté la fonction set_valeur qui utilise simultanément les fonctions serie_envoyer et serie_recevoir pour gérer l'écriture et la lecture via le port série dans la même tâche. La valeur mise dans serie_recevoir est la même que celle utilisée dans la tâche de gestion de l'afficheur à sept segments. Nous ajoutons ensuite set_valeur dans notre liste de tâches. Vous pouvez voir le résultat que nous obtenons ci-dessous.
Liste des tâches | Vidéo de fonctionnement |
---|---|
|
Avec Matrice de LEDS
De la même manière qu'avec le sept-segments, nous utilisons notre ordonnanceur pour commander la matrice de LEDs par l'intermédiaire des modes de communication SPI et port série. À la différence du sept-segment, la matrice de LEDs nécessite une configuration des différents caractères qu'elle pourra afficher. Pour cela, nous initialisons une matrice définissant les LEDs qui doivent s'allumer pour afficher les caractères souhaités. Nous affichons l'ensemble des caractères hexadécimaux grâce à cette matrice (contenue dans le fichier matrice.h). Ci-dessous, vous pouvez voir les résultats que nous obtenons ainsi que les codes que nous avons utilisés.
Matrice de configuration des LEDs | |
---|---|
| |
Code de gestion de la matrice de LEDs | Vidéo de fonctionnement |
|
Carte fille écran LCD
Conception de la carte fille
La carte fille écran comporte un ATMega328p et un écran LCD à base de contrôleur HD44780. Nous utilisons, comme precisé dans le wiki, un potentiomètre pour régler la luminosité des cristaux liquides ainsi qu'un connecteur HE10 pour la connexion de cette carte fille à notre carte mère sur lequel nous avons bien prevu une ligne de sélection SPI. Aucune ligne d'interruption n'était initialement nécessaire, mais suite au rajout d'une RAM SPI (FM25W256-G) nous avons dû en rajouter une pour gérer les interruptions.La carte mère écrit dans la RAM et le microcontôleur de la carte fille rafraichit l'écran régulièrement; en outre pour éviter les conflits entre la carte mère qui écrit et la carte fille qui lit il est nécessaire d'effectuer une gestion de priorités entre les différents signaux de MOSI, d'horloge et de selection. Cette gestion se fait à l'aide de circuits intermédaires présents dans notre schématique inspirés des circuits "NMOS highside" que nous avons réalisé avec l'aide de nos Encadrants M. BOE et M. REDON.
Voici les étapes de conceptions de notre carte fille:
Première Version
réception de la carte PCB:
Carte fille avant soudure | Carte fille après soudure |
---|---|
Problèmes rencontrés avec la première version de la carte
Lors de la conception et du routage de la première version de la carte destinée à gérer l'écran LCD HD44780, plusieurs erreurs ont été identifiées. Ces erreurs ont gravement impacté le fonctionnement de la carte, rendant nécessaire la conception d'une nouvelle version. Voici un récapitulatif des problèmes rencontrés et de leur impact :
- Erreur sur l'empreinte du regulateur ISR
Une empreinte SMD a été utilisée pour le régulateur ISR, alors que nous ne disposions que du composant en version traversante. Nous avons dû improviser en soudant des fils pour relier les différentes broches (MOSI, MISO, RST, etc.). Cette approche temporaire a engendré des problèmes majeurs, tels que des connexions instables, des court-circuits et une exposition accrue au bruit électromagnétique. Ces problèmes ont compromis la fiabilité des communications SPI et l'alimentation du circuit, comme nous l'a fait remarquer l'un de nos encadrants, M. REDON. Nous avons donc dans la nouvelle version, remplacé cette empreinte par sa version traversante.
- Connexion incorrecte des broches E et RS
Les broches E (Enable) et RS (Register Select) de l'écran LCD ont été connectées directement au 5V, au lieu d’être reliées aux broches programmables de l’ATMega328p. Ces broches jouent un rôle essentiel dans la communication avec le contrôleur HD44780, en permettant de sélectionner le registre de commande ou de données et de déclencher des opérations d'écriture. En les connectant directement au 5V, il était impossible de les programmer ou de les utiliser correctement. Cela a totalement empêché la configuration et l’envoi de commandes à l’écran LCD. Dans la nouvelle version de la carte, nous avons donc relié les broches E et RS à des broches numériques de l’ATMega328p pour assurer leur contrôle logiciel.
- Erreur sur l'alimentation de l’écran LCD
L'alimentation de l’écran a été liée en série avec un condensateur, au lieu d'être connectée en parallèle. Cette configuration en série empêchait la bonne alimentation de l'écran après les modifications effectuées sur les broches RS et E, rendant ce dernier inopérant. Nous avons donc modifié le schéma pour connecter le condensateur en parallèle avec l’alimentation, ce qui est nécessaire pour stabiliser la tension d’alimentation, comme nous l'a fait remarquer l'un de nos encadrants, M. BOE.
Seconde Version
Une fois la seconde version de la carte reçue nous somme passés à la soudure des différents composants. Ci-dessous vous pouvez voir notre carte fille avant et après la phase de soudure.
Carte fille avant soudure | Carte fille après soudure |
---|---|
Programmation de la carte fille
Test de la carte fille
Avant d'entamer la gestion des différentes fonctionnalités de l'écran LCD, nous vérifions si les composants ont été bien soudés et si la carte est fonctionnelle et programmable, en faisant clignoter une de ses LEDs avec du code Arduino présent dans notre répertoire Git. Vous pouvez voir les résultats de ce test ci-dessous :
Code arduino | Vidéo fonctionnement |
---|---|
|
Test de l'écran LCD HD44780
Maintenant que notre carte fille est fonctionnelle, nous commençons la programmation de notre écran LCD. Encore une fois, nous passons par une étape de test où nous vérifions le bon fonctionnement de l'écran LCD. À l'aide de code Arduino, nous affichons le classique "Hello, World!" sur notre écran. Vous pouvez voir les résultats de ce test ci-dessous.
Code arduino | Image résultat |
---|---|
|
Gestion de l'affichage
Défilement
Notre écran affiche bien les caractères souhaités, nous pouvons donc passer à la réalisation des différentes fonctions de gestion de notre écran LCD HD44780. Pour ce faire, nous avons utilisé le code de gestion du HD44780 que nous a donné l'un de nos encadrants, M. REDON. En utilisant les fonctions présentes dans ce code nous arrivons à faire défiler des caractères sur notre écran.
Code arduino | Image résultat |
---|---|
|
Dans l'exemple ci-dessus nous utilisons les fonctions display_GD et defiler_GD que nous plaçons dans une boucle infinie ce qui nous permet de gérer un défilement continu. Vous pouvez voir le contenu de ces fonctions ci-dessous.
display_GD | defiler_GD |
---|---|
|
|
La fonction display_GD affiche le message sur une seule ligne de l'écran et le fait défiler si sa longueur dépasse 16 caractères, tandis que defiler_GD sauvegarde le premier caractère du message puis décale tous les caractères vers la gauche et enfin replace le premier caractère à la fin du message. Le message est donc modifié pour simuler un défilement.
Caractères spéciaux et quelques codes VT100
Pour gérer les caractères spéciaux nous avons écrit la fonction process_special_characters qui, avec ses différentes conditions, prend en compte les effets attendus pour le retour à la ligne (\n), le retour chariot (\r), et quelques codes VT100 qui déplacent le curseur. L'implémentation de cette fonction est visible ci-dessous.
fonction de gestion des caractères spéciaux |
---|
|
- Retour à la ligne
Le code présenté ci-dessus nous permet de gérer le retour à la ligne. Nous affichons la chaîne de caractères "retour...\n a la ligne". Vous pouvez voir le résultat du test ci-dessous.
section de gestion du retour à la ligne | Vidéo de fonctionnement |
---|---|
|
- Retour chariot
Nous pouvons également gérer le retour chariot. Nous affichons la chaîne de caractères "retour...\r charriot". Vous pouvez voir le résultat du test ci-dessous.
section de gestion du retour à la ligne + retour chariot | Vidéo de fonctionnement |
---|---|
|
- Codes VT100
Nous pouvons également gérer quelques codes VT100. Nous affichons la chaîne de caractères "PICO\033[3Cecran\033[1Bbin6\033[1B \rbye ;)". Vous pouvez voir le résultat du test ci-dessous.
section de gestion du retour à la ligne + retour chariot + VT100 | Vidéo de fonctionnement |
---|---|
|
Test sur la RAM (FM25W256-G)
Afin de vérifier le bon fonctionnement de notre RAM (FM25W256-G), nous tentons d'écrire dessus, puis d'afficher les caractères écrits sur notre écran (HD44780). Pour cela, nous utilisons le code de gestion de l'affichage sur l'écran, auquel nous ajoutons quelques fonctions de notre conception permettant l'écriture sur la RAM.
Pour la configuration de la RAM, nous utilisons le tableau de commandes ci-dessous présent dans la datasheet du FM25W256-G.
Table de commande FM25W256-G |
---|
Ces commandes sont définies dans notre code
// Instructions SPI pour la RAM FM25W256
#define WREN 0x06 // Write Enable
#define WRITE 0x02 // écriture dans la mémoire
#define READ 0x03 // lecture de la mémoire
#define FRAM_SIZE 32768 // Taille de la mémoire FM25W256 en octets (32 Ko)
|
Les principales fonctions que nous utilisons pour la configuration de la RAM SPI sont FRAM_read ,FRAM_write et FRAM_clear qui nous permettent respectivement de lire le contenu de la RAM, d'écrire dans la RAM et enfin d'effacer le contenu de la RAM. Vous pouvez voir ces fonctions ci-dessous.
Lecture de la RAM |
---|
void FRAM_read(uint16_t address, char *buffer, uint8_t length) {
CS_LOW();
SPI_transfer(READ); // Commande de lecture
SPI_transfer((address >> 8) & 0xFF); // Adresse haute
SPI_transfer(address & 0xFF); // Adresse basse
for (uint8_t i = 0; i < length; i++) {
buffer[i] = SPI_transfer(0x00); // Lire les données
}
CS_HIGH();
}
|
Écriture dans la RAM |
void FRAM_write(uint16_t address, char *data) {
FRAM_write_enable();
CS_LOW();
SPI_transfer(WRITE); // Commande d'écriture
SPI_transfer((address >> 8) & 0xFF); // Adresse haute
SPI_transfer(address & 0xFF); // Adresse basse
for (uint8_t i = 0; i < strlen(data); i++) {
SPI_transfer(data[i]); // Écrire chaque caractère
}
CS_HIGH();
}
|
Effaçage de la RAM |
void FRAM_clear() {
FRAM_write_enable(); // Activer l'écriture
CS_LOW();
SPI_transfer(WRITE); // Commande d'écriture
SPI_transfer(0x00); // Adresse haute (MSB)
SPI_transfer(0x00); // Adresse basse (LSB)
for (uint16_t i = 0; i < FRAM_SIZE; i++) {
SPI_transfer(0x00); // Écrire 0x00 à chaque adresse
}
CS_HIGH();
}
|
Grâce à ces fonctions nous écrivons la chaîne de caractères "PICO_Bin6" dans la RAM SPI puis nous affichons le contenu de la RAM avec notre écran HD44780. Vous pouvez voir le résultat ci-dessous.
Utilisation des fonctions dans le main | image résultat |
---|---|
int main(void) {
HD44780_Initialize();
HD44780_WriteCommand(LCD_ON|CURSOR_NONE);
HD44780_WriteCommand(LCD_CLEAR);
HD44780_WriteCommand(LCD_HOME);
HD44780_WriteCommand(LCD_INCR_RIGHT);
_delay_ms(50);
char read_buffer[10] = {0}; // Buffer pour lire les données
SPI_init();
FRAM_clear(); // Effacer toute la mémoire avant d'écrire
// Écriture dans la RAM à l'adresse 0x0000
FRAM_write(0x0000, "PICO_bin6");
_delay_ms(100);
// Lecture des données depuis l'adresse 0x0000
FRAM_read(0x0000, read_buffer, 9);
read_buffer[9] = '\0'; // Ajout d'un caractère de fin de chaîne
while (1) {
// Boucle infinie
display_GD(read_buffer);
_delay_ms(500);
}
return 0;
}
|
Nous n'arrivons cependant pas à expliquer l'origine des caractères présents après ceux que nous avons écrits sur la RAM. Notre principale hypothèse est qu'il s'agit de caractères initialement présents sur la RAM, qui n'ont pas été effacés. Nous décidons néanmoins de continuer dans notre gestion de la communication avec la carte fille.
Communication Picoshield-écran
Après avoir testé le bon fonctionnement de la RAM nous passons à la communication SPI entre le PicoShield et la carte fille écran. Le Picoshield envoie des caractères par SPI qui sont réçus puis traités via minicom par la carte fille qui les affiche ensuite sur l'écran lcd HD44780. Pour réaliser cette tâche nous programmons d'abord le picoshield en tant que maître pour la gestion de l'envoi des caractères, puis c'est au tour de la carte fille écran d'être programmée en esclave pour recevoir et afficher les caractères envoyés par le picoshield. Vous pouvez voir les codes de programmation des cartes picoshield et écran ci-dessous.
**Code SPI Esclave (Affichage LCD)** | **Code SPI Maître** |
---|---|
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
#define F_CPU 16000000UL
void spi_init_slave(void) {
DDRB &= ~((1 << PB3) | (1 << PB5)); // MOSI et SCK en entrée
DDRB |= (1 << PB4); // MISO en sortie
SPCR = (1 << SPE); // Activer le SPI en mode esclave
}
char spi_recevoir_caractere(void) {
while (!(SPSR & (1 << SPIF))); // Attendre la réception complète
return SPDR; // Retourner la donnée reçue
}
void afficher_caractere_sur_LCD(char caractere) {
HD44780_WriteData(caractere);
}
int main(void) {
// Initialisation SPI et LCD
spi_init_slave();
HD44780_Initialize();
HD44780_WriteCommand(LCD_ON | CURSOR_BLINK);
HD44780_WriteCommand(LCD_CLEAR);
HD44780_WriteCommand(LCD_HOME);
while (1) {
// Réception d'un caractère via SPI
char caractere = spi_recevoir_caractere();
// Affichage du caractère reçu sur l'écran LCD
afficher_caractere_sur_LCD(caractere);
}
return 0;
}
|
#include <avr/io.h>
#include <avr/interrupt.h>
#include "SPI.h"
#include "serial.h"
#define F_CPU 16000000UL
#include <util/delay.h>
// Définition des broches SPI
#define SPI_SS_PORT PORTC
#define SPI_SS_PIN PC0
char valeur;
void spi_envoyer_caractere(char c) {
spi_activer();
spi_echange(c);
spi_desactiver();
}
void set_valeur(void) {
while (1) {
valeur = serie_recevoir(); // Lecture du caractère depuis Minicom
serie_envoyer(valeur); // Echo vers le terminal Minicom
spi_envoyer_caractere(valeur); // Transmission du caractère via SPI
}
}
int main(void) {
spi_init(); // Initialisation du SPI
serie_init(9600); // Initialisation du port série
sei(); // Activation des interruptions
while (1) {
set_valeur();
}
return 0;
}
|
Une fois les cartes programmées nous connectons notre écran à notre Picoshield par le port HE-10 de ce dernier. Nous ouvrons ensuite un terminal minicom avec la commande suivante "minicom -D /dev/ttyUSB0 -b 9600" et envoyons les caractères qui s'affichent sur l'écran. Vous pouvez voir cela dans la vidéo ci-dessous.
Bilan & Conclusion
Nous sommes au terme de notre projet, et les objectifs que nous avons atteints sont les suivants :
- Une carte Shield fonctionnelle et programmable.
- Un ordonnanceur fonctionnel avec différentes tâches (LEDs clignotantes, affichage sept-segments et matrice de LEDs), fonctionnant simultanément et disposant chacune des états "WAKE" et "SLEEPY".
- Une carte fille écran LCD fonctionnelle, avec un écran gérant l'affichage des caractères spéciaux ainsi que quelques commandes VT100 et une mémoire RAM SPI sur laquelle nous pouvons lire et écrire.
Cependant, faute de temps, nous n'avons pas pu aborder les primitives systèmes. En effet, nous avons pris beaucoup plus de temps que prévu pour concevoir une carte fille fonctionnelle (la première carte présentait de nombreux problèmes), un temps précieux qui nous aurait sans doute permis de réaliser les primitives systèmes manquantes.
Ce projet, qui s'est étendu sur tout le semestre, nous a permis d'approfondir nos connaissances en conception de cartes électroniques, en analyse de codes C, ainsi que notre compréhension des microcontrôleurs en général.
Nous tenons à remercier nos encadrants, M. REDON et M. BOE, pour leur accompagnement et les conseils donnés tout au long du projet.