« SE4Binome2025-5 » : différence entre les versions
Aucun résumé des modifications |
Aucun résumé des modifications |
||
| Ligne 179 : | Ligne 179 : | ||
_delay_ms(100); | _delay_ms(100); | ||
... | |||
active_o(CS, HIGH, 'b'); | active_o(CS, HIGH, 'b'); | ||
Version du 8 décembre 2025 à 10:42
Objectif
L'objectif de notre groupe est de réaliser une carte fille compatible avec la carte mère réalisée par le binôme 2. Cette carte que nous réalisons doit pouvoir permettre au pico-ordinateur d'afficher des informations sur un écran. Pour complexifier la tâche, nous utiliserons un affichage LCD graphique, qui nous permettra d'effectuer un affichage simple initialement, mais aussi de créer des primitives graphiques dans un second temps.
En plus de cette carte, nous devons réaliser un "OS primitif" qui fonctionnera sur une carte Arduino, à la fois pour pouvoir comprendre le fonctionnement d'un ordonnanceur, mais aussi pour pouvoir tester notre carte de notre côté avant de l'intégrer au pico-ordinateur. L'Arduino sera complété d'un shield afin d'avoir une interface similaire à celle qui sera disponible sur la carte mère, que nous devons réaliser également. Aussi, ce shield sera accompagné d'un module de carte SD pour pouvoir charger des programmes "à la volée" depuis la carte SD.
Dépôt GIT
le dépôt git de ce projet est le suivant: https://gitea.plil.fr/avanghel/SE4-Pico-B5
Partie Hardware
Bouclier Arduino & carte SD
Le bouclier Arduino que nous réalisons servira d'interface entre l'Arduino et la carte fille, de façon à ce qu'un arduino avec le programme de la carte mère et le shield d'installé ait le même comportement que la carte mère. Le module SD pourra se brancher sur un connecteur de la carte mère et donc du bouclier aussi.
Composants utilisés
Composants du bouclier arduino
La liste des composants utilisés pour le bouclier est la suivante:
-5x LEDS rouges
-5x Résistances 1kohm
Connecteurs utilisés (tous en 2.54mm):
-Connecteur arduino R3(disponible dans la librairie d'empreintes KiCad)
-6x 1x8 mâle vertical
Composants du module SD
La liste des circuits intégrés utilisés pour le module SD est la suivante:
-1x LTC3531
-1x74LVC125
les composants hors circuits intégrés utilisés sont les suivants:
-1x Capacité 2.2µF
-1x Capacité 10µF
-1x Inductance 10µH
-3x Résistances 3.3kohms
Les connecteurs utilisés sont les suivants:
-1x 1x8 mâle horizontal
-1x Connecteur Molex microSD
Schématique des deux cartes
Ci dessous la schématique pour les deux cartes:
PCB du bouclier
Ci dessous le PCB du bouclier arduino:
PCB du module SD
Ci dessous le PCB du module SD. Il est à noter que le connecteur SD est à l'envers, et que l'insertion d'une carte SD est difficile de ce fait. Il est recommandé de changer le routage du module SD si le projet est réutilisé.
Vue 3D des deux cartes
Ci-dessous la vue 3D de la carte du bouclier et du module SD:
Carte Fille
Le pilotage d'un écran graphique est plus complexe que pour un écran à caractère, puisque la création d'une image se fait pixel par pixel (plutôt que par caractère pour l'écran à caractère). De plus, le microcontrôleur de la carte mère(que l'on appelera CPU ici) doit gérer d'autres cartes filles, il n'est donc pas souhaitable qu'il traite par lui-même une tâche aussi lourde.
Notre carte fille devra donc être composée elle aussi d'un microcontrôleur(que l'on appelera GPU) qui interprètera des données reçues par le CPU (par exemple, un caractère à une certaine position) et transmettra les données à afficher à l'écran LCD graphique. Par ailleurs, nous fixerons l'écran graphique sur la carte fille.
Composants utilisés
La liste des circuits intégrés est la suivante:
-Atmega328P(Microcontrôleur)
-FM256WG (mémoire SPI)
-TMUX1574 (Multiplexeur bidirectionnel 4 bits) (à commander)
La liste des composants hors CI est la suivante:
-1 oscillateur à quartz 8MHz
-2 Capacités de 22pF
-5 Capacités de 100nF
-1 Capacité de 10µF
-1 Résistance de 1 Mohm
-2 Résistances de 1 Kohm
-2 LEDs rouges
Les connecteurs sont tous des connecteurs traversants 2.54 mm, les voici:
- 2x3 mâle vertical (ISP)
- 1x2 mâle vertical (debug, connection série)
- 1x8 mâle horizontal (Interface mère-fille)
- 1x9 mâle vertical (Interface avec écran)
Schématique de la carte fille
PCB de la carte
Ci-dessous le PCB de la carte imprimée:
et ci dessous un zoom sur la partie logique:
Vue 3D de la carte
Ci-dessous une vue 3D de la carte fille:
A noter que le connecteur en bas de la carte(connecteur mère-fille) sera bien à l'horizontale.
Composants à commander
TMUX1574DYYR (SOT-23-16 THIN)
Software
Ordonnanceur
Initialisation de la pile
Interruption nue
Structure d'un processus
Code de l'ordonnanceur
Fonction wait
Exemple de tâches
Exemple d'utilisation
Carte SD
Ecran LCD
Pour notre carte fille, nous utiliserons l'écran Fermion: 3.5” 480x320 TFT LCD Capacitive. Voyons le code pour communiquer avec l'écran.
Initialisation
Tout d'abord, la carte utilisant le driver ILI9488 pour communiquer avec l'écran, nous devons initialiser la communication.
Il faut savoir que ce driver reçoit soit des commandes, soit des données, et donc nous allons souvent utiliser ces 2 fonctions :
void tft_command(uint8_t cmd) {
active_o(TFT_DC, LOW, 'd'); // DC low = command
enable_spi();
spi_echange(cmd);
disable_spi();
}
void tft_data(uint8_t data) {
active_o(TFT_DC, HIGH, 'd'); // DC high = data
enable_spi();
spi_echange(data);
disable_spi();
}
Maintenant que nous avons ces fonctions, nous pouvons initialiser notre écran.
void tft_init() {
// RESET
tft_reset();
// software reset
tft_command(0x01);
_delay_ms(100);
...
active_o(CS, HIGH, 'b');
_delay_ms(100);
}
Par ailleurs, il faut initialiser notre SPI pour l'activer en mode maître et choisir la vitesse voulue, dans notre cas 8MHz.
void spi_init(void){
SPCR = (1 << SPE) | (1 << MSTR); //Active le SPI en mode Maitre
SPSR = (1 << SPI2X); // SPI2X = 1 → diviseur final = 2
}
Afficher un rectangle de couleur
Pour afficher un rectangle de couleur, il faut premièrement saisir les coordonnées concernées.
void tft_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
//tft_command(0x2C); // Memory Write
tft_command(0x2A); // Column Address Set
tft_data(x0 >> 8);
tft_data(x0 & 0xFF);
tft_data(x1 >> 8);
tft_data(x1 & 0xFF);
tft_command(0x00);
tft_command(0x2B); // Page Address Set
tft_data(y0 >> 8);
tft_data(y0 & 0xFF);
tft_data(y1 >> 8);
tft_data(y1 & 0xFF);
tft_command(0x00);
tft_command(0x2C); // Memory Write
}
Ensuite, il faut parcourir chaque coordonnée pour venir lui associer une couleur.
void tft_fill_rect(uint16_t color, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
tft_set_window(x0, y0, x1, y1);
uint8_t r = ((color >> 11) & 0x1F) << 3;
uint8_t g = ((color >> 5) & 0x3F) << 2;
uint8_t b = (color & 0x1F) << 3;
active_o(TFT_DC, HIGH, 'd');
enable_spi();
for (uint32_t i = 0; i < (uint32_t)(x1 - x0 + 1) * (uint32_t)(y1 - y0 + 1); i++) {
spi_echange(r);
spi_echange(g);
spi_echange(b);
}
disable_spi();
}
Nous avons désormais un rectangle qui peut s'afficher de toutes les couleurs et de toutes les dimensions !
Afficher des caractères
L'affichage de caractères est un enjeu crucial dans notre projet de PicoOrdinateur car il permet de voir les commandes saisies par un utilisateur. Cependant, on ne peut pas écrire de caractère si facilement que ça, c'est pour ça que nous allons devoir utiliser une Bitmap qui nous fournit comment écrire une lettre en 5x7 pixels. Voici le code utilisé.
struct Font {
unsigned char letter;
unsigned char code[7][6]; // 5 caractères + '\0'
};
static const struct Font font[] = {
{ ' ', {
" ",
" ",
" ",
" ",
" ",
" ",
" " }},
{ 'A', {
" ### ",
"# #",
"# #",
"# #",
"#####",
"# #",
"# #" }},
{ 'B', {
"#### ",
"# #",
"# #",
"#### ",
"# #",
"# #",
"#### " }},
......
Le code ci-dessus est pratique car visuel mais peu optimisé d'un point de vue mémoire car chaque information est codé par un unsigned char alors même qu'il contient seulement une information binaire. Ainsi, nous pourrions diviser par 128 la place mémoire occupée par ce code en revoyant sa structure mais pour nos essais, c'est acceptable de laisser cela ainsi. Pour passer de cette bitmap à l'affichage, voilà la fonction que nous utilisons :
int print_char_on_screen(uint16_t color, unsigned char c, uint16_t x, uint16_t y, uint16_t scale){
int char_idx = find_idx(c);
if (char_idx == -1 ){
return 1;
}
for (uint16_t py = 0; py < 7 * scale; py++) {
for (uint16_t px = 0; px < 5 * scale; px++) {
if (font[char_idx].code[py/scale][px/scale] == '#') {
tft_draw_pixel(x + px, y + py, color);
}else{
tft_draw_pixel(x + px, y + py, BACKGROUND);
}
}
}
return 0;
}
On peut voir char la fonction est divisé en plusieurs parties. Tout d'abord, on recherche l'index associé au caractère que l'on veut écrire. Par la suite, on parcourt chaque pixel du caractère de dimension 5*7 pour venir appliquer la couleur de la lettre ou la couleur du fond. Par ailleurs, on multiplie les dimensions par un facteur d'aggrandissement pour pouvoir changer la taille des caractères.
Nous pouvons maintenant afficher des caractères, mais qu'en est-il des chaînes des caractères ?
Afficher une chaîne de caractères
Afficher une chaîne de caractère est bien pratique pour toute sorte d'affichage, mais on doit veillez à ne pas dépasser les limites de l'écran. Pour ce faire, nous avons fait cette fonction qui gère les sauts de lignes automatiquement, que ce soit via \n ou en écrivant trop loin sur une ligne.
int print_string_on_screen(uint16_t color, unsigned char *str, uint16_t x, uint16_t y, uint16_t scale){
uint16_t offset_x = x;
uint16_t offset_y = y;
for (int i = 0; str[i] != '\0'; i++){
if ((offset_x + CHAR_ESPACEMENT * scale) >= (SIZE_SCREEN_X - CHAR_WIDTH* scale - 1)){ //Saute une ligne si l'écriture va trop loin
offset_y = (offset_y + LINE_ESPACEMENT * scale)%(SIZE_SCREEN_Y - CHAR_HEIGHT* scale - 1);
}
offset_x = (offset_x + CHAR_ESPACEMENT* scale)%(SIZE_SCREEN_X - CHAR_WIDTH* scale - 1);
if (str[i] == '\n'){
offset_x = 0;
offset_y = (offset_y + LINE_ESPACEMENT* scale)%(SIZE_SCREEN_Y - CHAR_HEIGHT* scale - 1);
}
print_char_on_screen(color, str[i], offset_x, offset_y, scale);
}
return 0;
}
Nous avons donc tout ce qu'il nous faut pour afficher une chaîne de caractères !