« SE4Binome2024-8 » : différence entre les versions
Ligne 207 : | Ligne 207 : | ||
<code>avrdude -c stk500v1 -p atmega8u2 -P /dev/ttyACM0 -b 19200 -t</code>Il faut ensuite envoyer la commande <code>erase</code> et <code>quit</code> <br><code>avrdude -c stk500v1 -p atmega8u2 -P /dev/ttyACM0 -b 19200 -U lfuse:w:0xde:m -U hfuse:w:0xd9:m -U efuse:w:0xf4:m</code> commande pour la modification des fuses<br><code>avrdude -c stk500v1 -p atmega8u2 -P /dev/ttyACM0 -b 19200 -U flash:w:8u2_firmware.hex</code> | <code>avrdude -c stk500v1 -p atmega8u2 -P /dev/ttyACM0 -b 19200 -t</code>Il faut ensuite envoyer la commande <code>erase</code> et <code>quit</code> <br><code>avrdude -c stk500v1 -p atmega8u2 -P /dev/ttyACM0 -b 19200 -U lfuse:w:0xde:m -U hfuse:w:0xd9:m -U efuse:w:0xf4:m</code> commande pour la modification des fuses<br><code>avrdude -c stk500v1 -p atmega8u2 -P /dev/ttyACM0 -b 19200 -U flash:w:8u2_firmware.hex</code> | ||
[[File:Pico2024_B8_erreur.jpeg|thumb|left|400px|D- et D+ inversés]] | |||
Malheureusement notre carte n'est pas reconnue par l'ordinateur avec la commande <code>lsusb</code>. Avec <code>dmesg</code> on voit bien un périphérique USB mais avec des erreurs, nous avons essayé de ressouder notre connecteur USB-C et vérifions au multimètre que les pins sont bien soudés mais nous avons toujours les mêmes erreurs. Après vérification de notre schéma une erreur s'est glissée lors du commit 181625dc05, les pins D+ et D- sont inversés. Nous modifions notre carte pour corriger cette erreur et notre carte est bien reconnue par l'ordinateur. | Malheureusement notre carte n'est pas reconnue par l'ordinateur avec la commande <code>lsusb</code>. Avec <code>dmesg</code> on voit bien un périphérique USB mais avec des erreurs, nous avons essayé de ressouder notre connecteur USB-C et vérifions au multimètre que les pins sont bien soudés mais nous avons toujours les mêmes erreurs. Après vérification de notre schéma une erreur s'est glissée lors du commit 181625dc05, les pins D+ et D- sont inversés. Nous modifions notre carte pour corriger cette erreur et notre carte est bien reconnue par l'ordinateur. | ||
[[File:Pico2024_B8_quasi_soudee.jpeg|thumb|left|500px|Carte quasiment soudée]] | [[File:Pico2024_B8_quasi_soudee.jpeg|thumb|left|500px|Carte quasiment soudée]] | ||
[[File:Pico2024_B8_lsusb.jpeg|thumb| | [[File:Pico2024_B8_lsusb.jpeg|thumb|right|500px|Reconnue (comme une Arduino UNO)]] |
Version du 3 décembre 2024 à 19:07
Wiki du projet Pico BONNINGRE Louis LECOMTE Antoine.
Lors de ce projet nous allons réaliser un pico-ordinateur qui comporte plusieurs fonctionnalités qui sont implémentées grâce à des cartes filles que l'on vient brancher sur une carte mère.
PicoShield
Pour débuter cet ordinateur, nous allons tester les fonctionnalités de base grâce à un shield que nous connectons à une carte arduino.
23 septembre 2024
Modification du PCB du shield, ajout d'une puce mémoire dans le cas ou la connexion à la carte SD ne fonctionne pas.
30 septembre 2024
Nous avons soudé les composants sur la carte puis testé les led et un afficheur 7 segments connecté sur un des ports pour carte fille
1 octobre 2024
Nous avons testé le connecteur de carte SD, à l'aide de la bibliothèque arduino 'SD.h'. La carte est bien reconnue, nous pouvons voir la taille mémoire de la carte et les fichiers présents dessus.
Nous avons testé toutes les fonctionnalités de base avec le PicoShield, nous pouvons donc passer à la suite.
Ordonnanceur
Nous avons commencé par réaliser un ordonnanceur simple pour effectuer deux taches simples (clignotement de deux LEDs). Comme visible sur la vidéo, la LED bleue et la LED orange clignotent bien à des fréquences différentes, la LED rouge clignote à chaque appel de l'ordonnanceur.
Pour notre ordonnanceur il est important d'initialiser les taches, notamment leur pointeur de pile.
void init_task(int t){
uint16_t oldSP = SP;
SP = Taches[t].stack;
uint16_t adresse = (uint16_t)Taches[t].start;
asm volatile("push %0" : : "r" (adresse & 0x00ff));
asm volatile("push %0" : : "r" ((adresse & 0xff00) >> 8));
portSAVE_Registers();
Taches[t].stack = SP;
SP = oldSP;
}
A chaque interruption de l'ISR (toutes les 20ms) on sauvegarde le contexte de la tache en cours, l'ordonnanceur passe à la tache suivante et on restaure le contexte de cette tache.
ISR(TIMER1_COMPA_vect, ISR_NAKED){
/* Sauvegarde du contexte de la tâche interrompue */
portSAVE_Registers();
Taches[courant].stack = SP;
/* Appel à l'ordonnanceur */
ordonnanceur();
/* Récupération du contexte de la tâche ré-activée */
SP = Taches[courant].stack;
portRESTORE_Registers();
asm volatile("reti");
}
Tâche série
Une fois l’ordonnanceur capable de lancer deux tâches en parallèle, nous nous sommes attaqués à la communication série de la carte par USB. Pour ce faire, nous utilisons l’application minicom coté PC qui permet une connexion série. Il faut initialiser les paramètres de la connexion, notre carte renvoie le message reçu dans le terminal.
Ci joint les deux taches responsables de l'envoi et de la reception de données par le protocole série, serial_buffer
est une variable globale utilisée pour stocker les messages reçus et à envoyer. Les fonctions Serial_Transmit()
et Serial_Receive()
sont déclarées dans pico_serial.h
et proviennent de la documentation AVR.
void SerialWrite(){
while (1){
Serial_Transmit('\r\n');
Serial_Transmit(serial_buffer);
}
}
void SerialRead(){
while(1){
serial_buffer = Serial_Receive();
}
}
Lors de ce test notre atmega envoi "LOULOUTOINE" en boucle sur le port série.
Tâche 7 segments
Nous ajoutons maintenant une tâche permettant de communiquer avec l'écran 7 segments par la communication SPI (toujours en parallèle des autres tâches). Voici par exemple deux des fonctions SPI, il faut préalablement initialiser la communication SPI avec les registres SPI.
void SPI_send(uint8_t data) {
DISPLAY_PORT &= ~(1<<DISPLAY_PIN); //On met le pin CS de l'écran à l'état bas pour l'activer
SPDR = data;
while (!(SPSR & (1 << SPIF)));
DISPLAY_PORT |= (1<<DISPLAY_PIN); // On relache l'écran
}
void clearDisplaySPI() {
SPI_send(0x76); // Commande pour effacer l'écran et remettre le curseur a gauche
}
Pour afficher un caractère sur l'écran il suffit donc d'appeler SPI_send()
en passant en paramètre le caractère à envoyer.
Etat endormi
Une fois que les tâches ont été correctement séparées, il a fallu ajuster notre ordonnanceur pour garantir que les délais de chaque tâche soient respectés. En effet, avec notre méthode actuelle qui repose sur l'utilisation de la fonction _delays_ms()
à chaque ajout de tâche, le temps total d'exécution augmente de manière cumulative. Par exemple, avec deux tâches, un délai de 200 ms prendrait 400 ms, et avec trois tâches 600 ms. Pour résoudre ce problème, nous avons décidé d'ajouter un état à chaque tâche, permettant de les "endormir" lorsqu'elles ne sont pas appelées, et de les "réveiller" lorsqu'elles le sont. Grâce à ce système, chaque fois qu'une tâche endormie est exécutée, on décrémente son timer de 20 millisecondes à chaque cycle. Ainsi chaque tâche respecte son délai sans interférer avec l'exécution des autres tâches.
void Sleeping(){
for (int i = 0; i < NB_TASKS;i++){
if (Taches[i].etat.sit == ENDORMI) Taches[i].etat.time.tempsendormi -= 20;
if (Taches[i].etat.time.tempsendormi <= 0) {
Taches[i].etat.time.tempsendormi = 0;
Taches[i].etat.sit = ACTIF;
}
}
}
Notre nouvel ordonnanceur qui appelle Sleeping()
void ordonnanceur(){
PORTC ^= 0x01; // On fait clignoter une des led (J1) à chaque fois que l'ordonnanceur est appelé
Sleeping();
do{
courant ++;
if (courant == NB_TASKS) courant = 0;
} while (Taches[courant].etat.sit == ENDORMI);
}
Cette fonction endors la tâche pendant la durée t (en millisecondes). On remet ensuite le timer à 0 et on lance l'interruption manuellement.
void makeSleep(int t){
Taches[courant].etat.sit = ENDORMI;
Taches[courant].etat.time.tempsendormi = t;
TCNT1 = 0;
TIMER1_COMPA_vect();
}
Voici notre struture modifiée pour ajouter l'état endormi On utilise une union pour representer le temps d'endormissement.
#define ENDORMI 1
#define ACTIF 0
typedef union{
int tempsendormi;
} Time;
typedef struct{
int situation; //1 pour endormi, 0 pour éveillé
Time time;
} Etat;
typedef struct task{
void (*start)(void);
uint16_t stack;
Etat etat;
} task;
Carte mère
Parmi notre groupe, nous sommes le binôme en charge de la carte mère.
Nous avons décidé d'utiliser un Atmega 328p qui sera programmé avec avr-dude
pour cela notre carte mère comportera également un Atmega8u2 qui servira de programmateur et d'interface serie/USB.
Notre carte étant similaire à une Arduino UNO avec le shield intégré nous mesurerons lors de la prochaine séance la consommation de celle ci afin d'estimer la conso de la future carte mère. Avec cette mesure et les estimations de consommation des différentes cartes filles nous réaliserons un bilan de puissance détaillé.
Pour l'instant nous avons prévu une alimentation par un port USB C, ayant connecté les pins CC1 et CC2 à des resistances de 5.1k nous obtenons 5v et 3A max. Il sera donc simple d'alimenter notre carte avec un câble USB, chargeur de téléphone ou alimentation de Raspberry par exemple et d'obtenir jusqu'à 15w ce qui semble largement suffisant.
Notre PCB est terminé, voici le schéma et un rendu du PCB final.
Les fichiers GERBER sont disponibles dans notre dépot GIT
Nous avons reçu notre PCB, pour commencer nous assemblons les composants minimums pour faire clignoter une LED avec le 328p.
En programmant par le port ISP avec une Arduino as ISP on arrive à faire clignoter la LED reliée sur PC1 du 328p. On soude ensuite le minimum pour tester l'AtMega8u2, on arrive à faire clignoter deux led reliées a ses broches.
Nous installons maintenant le firmware dans le 8u2 et le bootloader dans le 328p afin de pouvoir programmer le 328p en utilisant la connexion USB du 8u2.
Pour cela il faut effacer le 8u2, modifier les fuses pour notre crystal externe à 16MHz, puis flashez le firmware 8u2 provenant d'une Arduino UNO.
avrdude -c stk500v1 -p atmega8u2 -P /dev/ttyACM0 -b 19200 -t
Il faut ensuite envoyer la commande erase
et quit
avrdude -c stk500v1 -p atmega8u2 -P /dev/ttyACM0 -b 19200 -U lfuse:w:0xde:m -U hfuse:w:0xd9:m -U efuse:w:0xf4:m
commande pour la modification des fusesavrdude -c stk500v1 -p atmega8u2 -P /dev/ttyACM0 -b 19200 -U flash:w:8u2_firmware.hex
Malheureusement notre carte n'est pas reconnue par l'ordinateur avec la commande lsusb
. Avec dmesg
on voit bien un périphérique USB mais avec des erreurs, nous avons essayé de ressouder notre connecteur USB-C et vérifions au multimètre que les pins sont bien soudés mais nous avons toujours les mêmes erreurs. Après vérification de notre schéma une erreur s'est glissée lors du commit 181625dc05, les pins D+ et D- sont inversés. Nous modifions notre carte pour corriger cette erreur et notre carte est bien reconnue par l'ordinateur.