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

De projets-se.plil.fr
Aller à la navigation Aller à la recherche
Aucun résumé des modifications
Aucun résumé des modifications
Ligne 37 : Ligne 37 :
<br style="clear: both;" />
<br style="clear: both;" />


Voici le code de notre ordonnanceur avec les deux taches de clignotement, la définition de la structure des taches ainsi que portSAVE_Registers() et portRESTORE_Registers() sont dans le fichier <code>ordonnanceur.h</code>
Pour notre ordonnanceur il est important d'initialiser les taches, notamment leur pointeur de pile.  
<syntaxhighlight lang="c" line="1" start="1">
<syntaxhighlight lang="c" line="1" start="1">
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "ordonnanceur.h"
#define NB_TASKS    2
int courant = 0;
task Taches[NB_TASKS] = {
  {Led2, 0x0700},
  {Led1, 0x0600}
};
void init_minuteur(int diviseur,long periode){
TCCR1A=0;              // Le mode choisi n'utilise pas ce registre
TCCR1B=(1<<CTC1);      // Réinitialisation du minuteur sur expiration
switch(diviseur){
  case    8: TCCR1B |= (1<<CS11); break;
  case  64: TCCR1B |= (1<<CS11 | 11<<CS10); break;
  case  256: TCCR1B |= (1<<CS12); break;
  case 1024: TCCR1B |= (1<<CS12 | 1<<CS10); break;
  }
// Un cycle prend 1/F_CPU secondes.
// Un pas de compteur prend diviseur/F_CPU secondes.
// Pour une periode en millisecondes, il faut (periode/1000)/(diviseur/F_CPU) pas
// soit (periode*F_CPU)/(1000*diviseur)
OCR1A=F_CPU/1000*periode/diviseur;  // Calcul du pas
TCNT1=0;                // Compteur initialisé
TIMSK1=(1<<OCIE1A);    // Comparaison du compteur avec OCR1A
}
void init_task(int t){
void init_task(int t){
     uint16_t oldSP = SP;
     uint16_t oldSP = SP;
Ligne 81 : Ligne 49 :
     SP = oldSP;
     SP = oldSP;
}
}
</syntaxhighlight>
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.


<syntaxhighlight lang="c" line="1" start="1">
ISR(TIMER1_COMPA_vect, ISR_NAKED){
ISR(TIMER1_COMPA_vect, ISR_NAKED){
     /* Sauvegarde du contexte de la tâche interrompue */
     /* Sauvegarde du contexte de la tâche interrompue */
     portSAVE_Registers();
     portSAVE_Registers();
     Taches[courant].stack = SP;
     Taches[courant].stack = SP;
     /* Appel à l'ordonnanceur */
     /* Appel à l'ordonnanceur */
     ordonnanceur();
     ordonnanceur();
     /* Récupération du contexte de la tâche ré-activée */
     /* Récupération du contexte de la tâche ré-activée */
     SP = Taches[courant].stack;
     SP = Taches[courant].stack;
     portRESTORE_Registers();
     portRESTORE_Registers();
     asm volatile("reti");
     asm volatile("reti");
}
void ordonnanceur(){
    PORTC ^= 0x01; // On fait clignoter une des led à chaque fois que l'ordonnanceur est appelé
    courant++;
    if (courant == NB_TASKS) courant = 0;
}
void Led1(){
    while(1){
        PORTD ^= 0x80;
        _delay_ms(333);
    }
}
void Led2(){
    while(1){
        PORTD ^= 0x10;
        _delay_ms(400);
    }
}
int main(void){
    DDRD |= 0x92; //Déclaration des sorties
    DDRC |= 0x01;
    init_minuteur(256, PERIODE);
    for(int i = 1; i < NB_TASKS; i++) init_task(i);
    sei();
    SP = Taches[courant].stack;
    Taches[courant].start();
    return 0;
}
}
</syntaxhighlight>
</syntaxhighlight>
Ligne 131 : Ligne 70 :


<br style="clear: both;" />
<br style="clear: both;" />
Ci joint les deux fonctions responsables de l'envoi et de la reception de données par le protocole série, l'initialisation et les constantes sont dans le fichier <code>pico_serial.h</code> sur notre GIT
Ci joint les deux taches responsables de l'envoi et de la reception de données par le protocole série, <code>serial_buffer</code> est une variable globale utilisée pour stocker les messages reçus et à envoyer. Les fonctions <code>Serial_Transmit()</code> et <code>Serial_Receive()</code> sont déclarées dans <code>pico_serial.h</code> et proviennent de la documentation AVR.
<syntaxhighlight lang="c" line="1" start="1">
<syntaxhighlight lang="c" line="1" start="1">
void Serial_Transmit(unsigned char data)
void SerialWrite(){
{
     while (1){
    /* Wait for empty transmit buffer */
        Serial_Transmit('\r\n');
     while (!(UCSR0A & (1 << UDRE0)));
        Serial_Transmit(serial_buffer);
     /* Put data into buffer, sends the data */
     }
    UDR0 = data;
}
}


unsigned char Serial_Receive(void)
void SerialRead(){
{
     while(1){
    /* Wait for data to be received */
        serial_buffer = Serial_Receive();
     while (!(UCSR0A & (1 << RXC0)));
     }
     /* Get and return received data from buffer */
    return UDR0;
}
}
</syntaxhighlight>
</syntaxhighlight>
Ligne 153 : Ligne 89 :
[[File:TestWriteSerial.png|thumb|right|400px|Message reçu par le port série]]
[[File:TestWriteSerial.png|thumb|right|400px|Message reçu par le port série]]
<br style="clear: both;" />
<br style="clear: both;" />
Nous ajoutons maintenant une tache permettant d'écrire le caractère reçu par la communication série dans l'écran 7 segments par la communication SPI.
Lors de ce test notre atmega envoi "LOULOUTOINE" en boucle sur le port série.
 


Nous ajoutons maintenant une tache permettant d'écrire le caractère reçu par la communication série dans l'écran 7 segments par la communication SPI (toujours en parallèle des autres taches).


=Carte mère=
=Carte mère=


Parmis notre groupe, nous somme le binôme en charge de la carte mère. L'ébauche du PCB est disponible sur le Git de notre projet.
Parmi notre groupe, nous sommes le binôme en charge de la carte mère. L'ébauche du PCB est disponible sur le Git de notre projet.

Version du 15 octobre 2024 à 17:16

Wiki du projet Pico BONNINGRE Louis LECOMTE Antoine Ce projet est le principal de notre semestre, il s'agit de 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 la carte mère.


GIT du projet

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.

Le schéma de la carte mère
Le PCB de la carte mère


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

Les LEDs fonctionnent
L'afficheur externe


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.

Lecture de la carte SD

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");
}

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();
    }
}
Paramètres du Minicom
Message reçu par le port série


Lors de ce test notre atmega envoi "LOULOUTOINE" en boucle sur le port série.


Nous ajoutons maintenant une tache permettant d'écrire le caractère reçu par la communication série dans l'écran 7 segments par la communication SPI (toujours en parallèle des autres taches).

Carte mère

Parmi notre groupe, nous sommes le binôme en charge de la carte mère. L'ébauche du PCB est disponible sur le Git de notre projet.